aboutsummaryrefslogtreecommitdiff
path: root/Annex/Direct.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-03-04 01:58:09 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-03-04 02:03:15 -0400
commitcfe87407f493e428ca8e1d5592b228675199afb3 (patch)
tree260e68fab396ba20c515a31a7ad8a88e2bcf3aeb /Annex/Direct.hs
parent0ba6b3aa7d3a7528ba95ffbae7df6634adbed9b6 (diff)
finish fixing direct mode merge bug involving unstaged local files
Added test cases for both ways this can happen, with a conflict involving a file, or a directory. Cleaned up resolveMerge to not touch the work tree in direct mode, which turned out to be the only way to handle things.. And makes it much nicer. Still need to run test suite on windows.
Diffstat (limited to 'Annex/Direct.hs')
-rw-r--r--Annex/Direct.hs75
1 files changed, 48 insertions, 27 deletions
diff --git a/Annex/Direct.hs b/Annex/Direct.hs
index 02766ab18..2f583fd94 100644
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -170,23 +170,23 @@ mergeDirectCleanup d oldsha newsha = do
makeabs <- flip fromTopFilePath <$> gitRepo
let fsitems = zip (map (makeabs . DiffTree.file) items) items
forM_ fsitems $
- go DiffTree.srcsha DiffTree.srcmode moveout moveout_raw
+ go makeabs DiffTree.srcsha DiffTree.srcmode moveout moveout_raw
forM_ fsitems $
- go DiffTree.dstsha DiffTree.dstmode movein movein_raw
+ go makeabs DiffTree.dstsha DiffTree.dstmode movein movein_raw
void $ liftIO cleanup
liftIO $ removeDirectoryRecursive d
where
- go getsha getmode a araw (f, item)
+ go makeabs getsha getmode a araw (f, item)
| getsha item == nullSha = noop
| otherwise = void $
- tryAnnex . maybe (araw f item) (\k -> void $ a k f)
+ tryAnnex . maybe (araw item makeabs f) (\k -> void $ a item makeabs k f)
=<< catKey (getsha item) (getmode item)
- moveout = removeDirect
+ moveout _ _ = removeDirect
{- Files deleted by the merge are removed from the work tree.
- Empty work tree directories are removed, per git behavior. -}
- moveout_raw f _item = liftIO $ do
+ moveout_raw _ _ f = liftIO $ do
nukeFile f
void $ tryIO $ removeDirectory $ parentDir f
@@ -198,39 +198,60 @@ mergeDirectCleanup d oldsha newsha = do
-
- Otherwise, create the symlink and then if possible, replace it
- with the content. -}
- movein k f = unlessM (goodContent k f) $ do
- preserveUnannexed f
+ movein item makeabs k f = unlessM (goodContent k f) $ do
+ preserveUnannexed item makeabs f oldsha
l <- inRepo $ gitAnnexLink f k
replaceFile f $ makeAnnexLink l
toDirect k f
{- Any new, modified, or renamed files were written to the temp
- directory by the merge, and are moved to the real work tree. -}
- movein_raw f item = do
- preserveUnannexed f
+ movein_raw item makeabs f = do
+ preserveUnannexed item makeabs f oldsha
liftIO $ do
createDirectoryIfMissing True $ parentDir f
void $ tryIO $ rename (d </> getTopFilePath (DiffTree.file item)) f
- {- If the file is present in the work tree, but did not exist in
- - the oldsha branch, preserve this local, unannexed file. -}
- preserveUnannexed f = whenM unannexed $
- whenM (isNothing <$> catFileDetails oldsha f) $
- liftIO $ findnewname (0 :: Int)
- where
- exists = isJust <$$> catchMaybeIO . getSymbolicLinkStatus
+{- If the file that's being moved in is already present in the work
+ - tree, but did not exist in the oldsha branch, preserve this
+ - local, unannexed file (or directory), as "variant-local".
+ -
+ - It's also possible that the file that's being moved in
+ - is in a directory that collides with an exsting, non-annexed
+ - file (not a directory), which should be preserved.
+ -}
+preserveUnannexed :: DiffTree.DiffTreeItem -> (TopFilePath -> FilePath) -> FilePath -> Ref -> Annex ()
+preserveUnannexed item makeabs absf oldsha = do
+ whenM (liftIO (collidingitem absf) <&&> unannexed absf) $
+ liftIO $ findnewname absf 0
+ checkdirs (DiffTree.file item)
+ where
+ checkdirs from = do
+ let p = parentDir (getTopFilePath from)
+ let d = asTopFilePath p
+ unless (null p) $ do
+ let absd = makeabs d
+ whenM (liftIO (colliding_nondir absd) <&&> unannexed absd) $
+ liftIO $ findnewname absd 0
+ checkdirs d
+
+ collidingitem f = isJust
+ <$> catchMaybeIO (getSymbolicLinkStatus f)
+ colliding_nondir f = maybe False (not . isDirectory)
+ <$> catchMaybeIO (getSymbolicLinkStatus f)
- unannexed = liftIO (exists f)
- <&&> (isNothing <$> isAnnexLink f)
+ unannexed f = (isNothing <$> isAnnexLink f)
+ <&&> (isNothing <$> catFileDetails oldsha f)
- findnewname n = do
- let localf = mkVariant f
- ("local" ++ if n > 0 then show n else "")
- ifM (exists localf)
- ( findnewname (n+1)
- , rename f localf
- `catchIO` const (findnewname (n+1))
- )
+ findnewname :: FilePath -> Int -> IO ()
+ findnewname f n = do
+ let localf = mkVariant f
+ ("local" ++ if n > 0 then show n else "")
+ ifM (collidingitem localf)
+ ( findnewname f (n+1)
+ , rename f localf
+ `catchIO` const (findnewname f (n+1))
+ )
{- If possible, converts a symlink in the working tree into a direct
- mode file. If the content is not available, leaves the symlink