summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Command/Sync.hs9
-rw-r--r--Test.hs71
2 files changed, 50 insertions, 30 deletions
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 33b30df13..22a6b6f4d 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -434,13 +434,14 @@ resolveMerge' u
d <- fromRepo gitAnnexMergeDir
l <- liftIO $ dirContentsRecursive (d </> item)
if null l
- then go (d </> item)
- else mapM_ go l
+ then go d (d </> item)
+ else mapM_ (go d) l
where
- go f = do
+ go d f = do
v <- getAnnexLinkTarget f
+ let worktreef = makeRelative d f
case v of
- Just target -> stageSymlink f
+ Just target -> stageSymlink worktreef
=<< hashSymlink target
Nothing -> noop
diff --git a/Test.hs b/Test.hs
index af44ade08..346066893 100644
--- a/Test.hs
+++ b/Test.hs
@@ -33,6 +33,8 @@ import qualified Backend
import qualified Git.CurrentRepo
import qualified Git.Filename
import qualified Git.Types
+import qualified Git.Ref
+import qualified Git.LsTree
import qualified Locations
import qualified Types.KeySource
import qualified Types.Backend
@@ -199,7 +201,7 @@ unitTests note getenv = testGroup ("Unit Tests " ++ note)
, check "union merge regression" test_union_merge_regression
, check "conflict resolution" test_conflict_resolution_movein_bug
, check "conflict resolution (mixed directory and file)" test_mixed_conflict_resolution
- , check "conflict resolution (mixed directory and file) 2" test_mixed_conflict_resolution2
+ , check "conflict resolution symlinks" test_conflict_resolution_symlinks
, check "conflict resolution (uncommitted local file)" test_uncommitted_conflict_resolution
, check "map" test_map
, check "uninit" test_uninit
@@ -824,7 +826,7 @@ test_mixed_conflict_resolution env = do
indir env r2 $ do
disconnectOrigin
createDirectory conflictor
- writeFile (conflictor </> "subfile") "subfile"
+ writeFile subfile "subfile"
git_annex env "add" [conflictor] @? "add conflicter failed"
git_annex env "sync" [] @? "sync failed in r2"
pair env r1 r2
@@ -834,12 +836,21 @@ test_mixed_conflict_resolution env = do
checkmerge "r1" r1
checkmerge "r1" r2
conflictor = "conflictor"
+ subfile = conflictor </> "subfile"
variantprefix = conflictor ++ ".variant"
checkmerge what d = do
doesDirectoryExist (d </> conflictor) @? (d ++ " conflictor directory missing")
l <- getDirectoryContents d
- any (variantprefix `isPrefixOf`) l
+ let v = filter (variantprefix `isPrefixOf`) l
+ not (null v)
@? (what ++ " conflictor file missing in: " ++ show l )
+ -- Make sure that files after conflict resolution are
+ -- annexed, particularly on filesystems without symlinks,
+ -- it's possible to lose track.
+ indir env d $ do
+ git_annex env "get" (conflictor:v) @? ("get failed in " ++ what)
+ git_annex_expectoutput env "find" [conflictor] [subfile]
+ git_annex_expectoutput env "find" v v
{- Check merge conflict resolution when there is a local file,
- that is not staged or committed, that conflicts with what's being added
@@ -888,30 +899,37 @@ test_uncommitted_conflict_resolution env = do
localcontent = "local"
annexedcontent = "annexed"
-{-
- - During conflict resolution, one of the annexed files in git is
- - accidentially converted from a symlink to a regular file.
- - This only happens on crippled filesystems.
- -
- - This test case happens to detect the problem when it tries the next
- - pass of conflict resolution, since it's unable to resolve a conflict
- - between an annexed and non-annexed file.
+{- On Windows/FAT, repeated conflict resolution sometimes
+ - lost track of whether a file was a symlink.
-}
-test_mixed_conflict_resolution2 :: TestEnv -> Assertion
-test_mixed_conflict_resolution2 env = go >> go
- where
- go = withtmpclonerepo env False $ \r1 ->
+test_conflict_resolution_symlinks :: TestEnv -> Assertion
+test_conflict_resolution_symlinks env = do
+ withtmpclonerepo env False $ \r1 ->
withtmpclonerepo env False $ \r2 -> do
- indir env r1 $ do
- writeFile conflictor "conflictor"
- git_annex env "add" [conflictor] @? "add conflicter failed"
- git_annex env "sync" [] @? "sync failed in r1"
- indir env r2 $ do
- createDirectory conflictor
- writeFile (conflictor </> "subfile") "subfile"
- git_annex env "add" [conflictor] @? "add conflicter failed"
- git_annex env "sync" [] @? "sync failed in r2"
+ withtmpclonerepo env False $ \r3 -> do
+ indir env r1 $ do
+ writeFile conflictor "conflictor"
+ git_annex env "add" [conflictor] @? "add conflicter failed"
+ git_annex env "sync" [] @? "sync failed in r1"
+ check_is_link conflictor "r1"
+ indir env r2 $ do
+ createDirectory conflictor
+ writeFile (conflictor </> "subfile") "subfile"
+ git_annex env "add" [conflictor] @? "add conflicter failed"
+ git_annex env "sync" [] @? "sync failed in r2"
+ check_is_link (conflictor </> "subfile") "r2"
+ indir env r3 $ do
+ writeFile conflictor "conflictor"
+ git_annex env "add" [conflictor] @? "add conflicter failed"
+ git_annex env "sync" [] @? "sync failed in r1"
+ check_is_link (conflictor </> "subfile") "r3"
+ where
conflictor = "conflictor"
+ check_is_link f what = do
+ git_annex_expectoutput env "find" ["--include=*", f] [f]
+ l <- annexeval $ Annex.inRepo $ Git.LsTree.lsTreeFiles Git.Ref.headRef [f]
+ all (\i -> Git.Types.toBlobType (Git.LsTree.mode i) == Just Git.Types.SymlinkBlob) l
+ @? (what ++ " " ++ f ++ " lost symlink bit after merge: " ++ show l)
{- Set up repos as remotes of each other. -}
pair :: TestEnv -> FilePath -> FilePath -> Assertion
@@ -1392,7 +1410,8 @@ prepareTestEnv forcedirect = do
cwd <- getCurrentDirectory
p <- Utility.Env.getEnvDefault "PATH" ""
- let env =
+ env <- Utility.Env.getEnvironment
+ let newenv =
-- Ensure that the just-built git annex is used.
[ ("PATH", cwd ++ [searchPathSeparator] ++ p)
, ("TOPDIR", cwd)
@@ -1408,7 +1427,7 @@ prepareTestEnv forcedirect = do
, ("FORCEDIRECT", if forcedirect then "1" else "")
]
- return $ M.fromList env
+ return $ M.fromList newenv `M.union` M.fromList env
changeToTmpDir :: TestEnv -> FilePath -> IO ()
changeToTmpDir env t = do