summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Annex/AdjustedBranch.hs4
-rw-r--r--Annex/AutoMerge.hs74
-rw-r--r--Annex/GitOverlay.hs12
-rw-r--r--Command/ResolveMerge.hs2
-rw-r--r--Command/Sync.hs2
-rw-r--r--doc/design/adjusted_branches.mdwn31
6 files changed, 60 insertions, 65 deletions
diff --git a/Annex/AdjustedBranch.hs b/Annex/AdjustedBranch.hs
index 8d2d498e6..a30dda809 100644
--- a/Annex/AdjustedBranch.hs
+++ b/Annex/AdjustedBranch.hs
@@ -272,7 +272,7 @@ updateAdjustedBranch tomerge (origbranch, adj) commitmode = catchBoolIO $
withemptydir tmpwt $ withWorkTree tmpwt $ do
liftIO $ writeFile (tmpgit </> "HEAD") (fromRef updatedorig)
showAction $ "Merging into " ++ fromRef (Git.Ref.base origbranch)
- ifM (autoMergeFrom tomerge (Just updatedorig) commitmode)
+ ifM (autoMergeFrom tomerge (Just origbranch) True commitmode)
( do
!mergecommit <- liftIO $ extractSha <$> readFile (tmpgit </> "HEAD")
-- This is run after the commit lock is dropped.
@@ -305,7 +305,7 @@ updateAdjustedBranch tomerge (origbranch, adj) commitmode = catchBoolIO $
adjmergecommit <- commitAdjustedTree' adjtree mergecommit
[mergecommit, currbranch]
showAction "Merging into adjusted branch"
- ifM (autoMergeFrom adjmergecommit (Just currbranch) commitmode)
+ ifM (autoMergeFrom adjmergecommit (Just currbranch) False commitmode)
-- The adjusted branch has a merge commit on top;
-- clean that up and propigate any changes made
-- in that merge to the origbranch.
diff --git a/Annex/AutoMerge.hs b/Annex/AutoMerge.hs
index c9f13f5bf..e1662f81a 100644
--- a/Annex/AutoMerge.hs
+++ b/Annex/AutoMerge.hs
@@ -42,17 +42,17 @@ import qualified Data.ByteString.Lazy as L
- Callers should use Git.Branch.changed first, to make sure that
- there are changes from the current branch to the branch being merged in.
-}
-autoMergeFrom :: Git.Ref -> Maybe Git.Ref -> Git.Branch.CommitMode -> Annex Bool
-autoMergeFrom branch currbranch commitmode = do
+autoMergeFrom :: Git.Ref -> Maybe Git.Ref -> Bool -> Git.Branch.CommitMode -> Annex Bool
+autoMergeFrom branch currbranch inoverlay commitmode = do
showOutput
case currbranch of
Nothing -> go Nothing
Just b -> go =<< inRepo (Git.Ref.sha b)
where
go old = ifM isDirect
- ( mergeDirect currbranch old branch (resolveMerge old branch) commitmode
+ ( mergeDirect currbranch old branch (resolveMerge old branch False) commitmode
, inRepo (Git.Merge.mergeNonInteractive branch commitmode)
- <||> (resolveMerge old branch <&&> commitResolvedMerge commitmode)
+ <||> (resolveMerge old branch inoverlay <&&> commitResolvedMerge commitmode)
)
{- Resolves a conflicted merge. It's important that any conflicts be
@@ -77,11 +77,16 @@ autoMergeFrom branch currbranch commitmode = do
-
- In indirect mode, the merge is resolved in the work tree and files
- staged, to clean up from a conflicted merge that was run in the work
- - tree.
+ - tree.
-
- In direct mode, the work tree is not touched here; files are staged to
- the index, and written to the gitAnnexMergeDir, for later handling by
- the direct mode merge code.
+ -
+ - This is complicated by needing to support merges run in an overlay
+ - work tree, in which case the CWD won't be within the work tree.
+ - In this mode, there is no need to update the work tree at all,
+ - as the overlay work tree will get deleted.
-
- Unlocked files remain unlocked after merging, and locked files
- remain locked. When the merge conflict is between a locked and unlocked
@@ -93,12 +98,16 @@ autoMergeFrom branch currbranch commitmode = do
- A git merge can fail for other reasons, and this allows detecting
- such failures.
-}
-resolveMerge :: Maybe Git.Ref -> Git.Ref -> Annex Bool
-resolveMerge us them = do
- top <- fromRepo Git.repoPath
+resolveMerge :: Maybe Git.Ref -> Git.Ref -> Bool -> Annex Bool
+resolveMerge us them inoverlay = do
+ top <- if inoverlay
+ then pure "."
+ else fromRepo Git.repoPath
(fs, cleanup) <- inRepo (LsFiles.unmerged [top])
- srcmap <- inodeMap $ pure (map LsFiles.unmergedFile fs, return True)
- (mergedks, mergedfs) <- unzip <$> mapM (resolveMerge' srcmap us them) fs
+ srcmap <- if inoverlay
+ then pure M.empty
+ else inodeMap $ pure (map LsFiles.unmergedFile fs, return True)
+ (mergedks, mergedfs) <- unzip <$> mapM (resolveMerge' srcmap us them inoverlay) fs
let mergedks' = concat mergedks
let mergedfs' = catMaybes mergedfs
let merged = not (null mergedfs')
@@ -114,15 +123,15 @@ resolveMerge us them = do
when merged $ do
Annex.Queue.flush
- unlessM isDirect $ do
+ unlessM (pure inoverlay <||> isDirect) $ do
unstagedmap <- inodeMap $ inRepo $ LsFiles.notInRepo False [top]
cleanConflictCruft mergedks' mergedfs' unstagedmap
showLongNote "Merge conflict was automatically resolved; you may want to examine the result."
return merged
-resolveMerge' :: InodeMap -> Maybe Git.Ref -> Git.Ref -> LsFiles.Unmerged -> Annex ([Key], Maybe FilePath)
-resolveMerge' _ Nothing _ _ = return ([], Nothing)
-resolveMerge' unstagedmap (Just us) them u = do
+resolveMerge' :: InodeMap -> Maybe Git.Ref -> Git.Ref -> Bool -> LsFiles.Unmerged -> Annex ([Key], Maybe FilePath)
+resolveMerge' _ Nothing _ _ _ = return ([], Nothing)
+resolveMerge' unstagedmap (Just us) them inoverlay u = do
kus <- getkey LsFiles.valUs
kthem <- getkey LsFiles.valThem
case (kus, kthem) of
@@ -133,8 +142,9 @@ resolveMerge' unstagedmap (Just us) them u = do
makeannexlink keyThem LsFiles.valThem
-- cleanConflictCruft can't handle unlocked
-- files, so delete here.
- unless (islocked LsFiles.valUs) $
- liftIO $ nukeFile file
+ unless inoverlay $
+ unless (islocked LsFiles.valUs) $
+ liftIO $ nukeFile file
| otherwise -> do
-- Only resolve using symlink when both
-- were locked, otherwise use unlocked
@@ -170,23 +180,33 @@ resolveMerge' unstagedmap (Just us) them u = do
where
dest = variantFile file key
+ stagefile :: FilePath -> Annex FilePath
+ stagefile f
+ | inoverlay = (</> f) <$> fromRepo Git.repoPath
+ | otherwise = pure f
+
makesymlink key dest = do
l <- calcRepo $ gitAnnexLink dest key
- replacewithsymlink dest l
- stageSymlink dest =<< hashSymlink l
+ unless inoverlay $ replacewithsymlink dest l
+ dest' <- stagefile dest
+ stageSymlink dest' =<< hashSymlink l
replacewithsymlink dest link = withworktree dest $ \f ->
replaceFile f $ makeGitLink link
makepointer key dest = do
- unlessM (reuseOldFile unstagedmap key file dest) $ do
- r <- linkFromAnnex key dest
- case r of
- LinkAnnexFailed -> liftIO $
- writeFile dest (formatPointer key)
- _ -> noop
- stagePointerFile dest =<< hashPointerFile key
- Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest)
+ unless inoverlay $
+ unlessM (reuseOldFile unstagedmap key file dest) $ do
+ r <- linkFromAnnex key dest
+ case r of
+ LinkAnnexFailed -> liftIO $
+ writeFile dest (formatPointer key)
+ _ -> noop
+ dest' <- stagefile dest
+ stagePointerFile dest' =<< hashPointerFile key
+ unless inoverlay $
+ Database.Keys.addAssociatedFile key
+ =<< inRepo (toTopFilePath dest)
withworktree f a = ifM isDirect
( do
@@ -202,7 +222,7 @@ resolveMerge' unstagedmap (Just us) them u = do
=<< fromRepo (UpdateIndex.lsSubTree b item)
-- Update the work tree to reflect the graft.
- case (selectwant (LsFiles.unmergedBlobType u), selectunwant (LsFiles.unmergedBlobType u)) of
+ unless inoverlay $ case (selectwant (LsFiles.unmergedBlobType u), selectunwant (LsFiles.unmergedBlobType u)) of
-- Symlinks are never left in work tree when
-- there's a conflict with anything else.
-- So, when grafting in a symlink, we must create it:
diff --git a/Annex/GitOverlay.hs b/Annex/GitOverlay.hs
index b6b1398f4..4230ed4a4 100644
--- a/Annex/GitOverlay.hs
+++ b/Annex/GitOverlay.hs
@@ -21,14 +21,20 @@ withIndexFile f = withAltRepo
(\g -> addGitEnv g "GIT_INDEX_FILE" f)
(\g g' -> g' { gitEnv = gitEnv g })
-{- Runs an action using a different git work tree. -}
+{- Runs an action using a different git work tree.
+ -
+ - Smudge and clean filters are disabled in this work tree. -}
withWorkTree :: FilePath -> Annex a -> Annex a
withWorkTree d = withAltRepo
- (\g -> return $ g { location = modlocation (location g) })
- (\g g' -> g' { location = location g })
+ (\g -> return $ g { location = modlocation (location g), gitGlobalOpts = gitGlobalOpts g ++ disableSmudgeConfig })
+ (\g g' -> g' { location = location g, gitGlobalOpts = gitGlobalOpts g })
where
modlocation l@(Local {}) = l { worktree = Just d }
modlocation _ = error "withWorkTree of non-local git repo"
+ disableSmudgeConfig = map Param
+ [ "-c", "filter.annex.smudge="
+ , "-c", "filter.annex.clean="
+ ]
{- Runs an action with the git index file and HEAD, and a few other
- files that are related to the work tree coming from an overlay
diff --git a/Command/ResolveMerge.hs b/Command/ResolveMerge.hs
index 12fe8cfd3..8742a1104 100644
--- a/Command/ResolveMerge.hs
+++ b/Command/ResolveMerge.hs
@@ -29,7 +29,7 @@ start = do
let merge_head = d </> "MERGE_HEAD"
them <- fromMaybe (error nomergehead) . extractSha
<$> liftIO (readFile merge_head)
- ifM (resolveMerge (Just us) them)
+ ifM (resolveMerge (Just us) them False)
( do
void $ commitResolvedMerge Git.Branch.ManualCommit
next $ next $ return True
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 69f39bb8a..9ef26f19e 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -170,7 +170,7 @@ merge :: CurrBranch -> Git.Branch.CommitMode -> Git.Branch -> Annex Bool
merge (Just b, Just adj) commitmode tomerge =
updateAdjustedBranch tomerge (b, adj) commitmode
merge (b, _) commitmode tomerge =
- autoMergeFrom tomerge b commitmode
+ autoMergeFrom tomerge b False commitmode
syncBranch :: Git.Branch -> Git.Branch
syncBranch = Git.Ref.under "refs/heads/synced" . fromDirectBranch . fromAdjustedBranch
diff --git a/doc/design/adjusted_branches.mdwn b/doc/design/adjusted_branches.mdwn
index 6b69306a9..e94439d66 100644
--- a/doc/design/adjusted_branches.mdwn
+++ b/doc/design/adjusted_branches.mdwn
@@ -279,37 +279,6 @@ into adjusted view worktrees.]
will make copies of the content of annexed files, so this would need
to checkout the adjusted branch some other way. Maybe generalize so this
more efficient checkout is available as a git-annex command?
-* sync in adjusted branch runs merge in overlay worktree,
- but the merge conflict resolution code does not know to use that
- worktree.
-* sync in adjusted branch can trigger merge conflict detection where
- there should be no conflict.
-
- git init a
- cd a
- git annex init --version=6
- echo hi > f
- git annex add f
- git annex sync
- cd ..
-
- git clone a b
- cd b
- git annex init --version=6
- git annex get
- git annex adjust --unlock
- cd ..
-
- cd a
- git mv f f2
- git annex sync
- cd ..
-
- cd b
- git annex sync
-
- To fix, implement "avoiding conflicted merge" above.
-
* There are potentially races in code that assumes a branch like
master is not being changed by someone else. In particular,
propigateAdjustedCommits rebases the adjusted branch on top of master.