Fix direct mode merge bug when a direct mode file was deleted and replaced with a directory. An ordering problem caused the directory to not get created in this case. Thanks to Tim for the test cases.

This commit is contained in:
Joey Hess 2013-11-15 13:40:12 -04:00
parent 0744560e4b
commit b0f85b3e22
3 changed files with 24 additions and 13 deletions

View file

@ -138,28 +138,33 @@ mergeDirect d branch g = do
- and the commit sha passed in, along with the old sha of the tree - and the commit sha passed in, along with the old sha of the tree
- before the merge. Uses git diff-tree to find files that changed between - before the merge. Uses git diff-tree to find files that changed between
- the two shas, and applies those changes to the work tree. - the two shas, and applies those changes to the work tree.
-
- There are really only two types of changes: An old item can be deleted,
- or a new item added. Two passes are made, first deleting and then
- adding. This is to handle cases where eg, a file is deleted and a
- directory is added. The diff-tree output may list these in the opposite
- order, but we cannot really add the directory until the file with the
- same name is remvoed.
-} -}
mergeDirectCleanup :: FilePath -> Git.Ref -> Git.Ref -> Annex () mergeDirectCleanup :: FilePath -> Git.Ref -> Git.Ref -> Annex ()
mergeDirectCleanup d oldsha newsha = do mergeDirectCleanup d oldsha newsha = do
(items, cleanup) <- inRepo $ DiffTree.diffTreeRecursive oldsha newsha (items, cleanup) <- inRepo $ DiffTree.diffTreeRecursive oldsha newsha
makeabs <- flip fromTopFilePath <$> gitRepo makeabs <- flip fromTopFilePath <$> gitRepo
forM_ items (updated makeabs) let fsitems = zip (map (makeabs . DiffTree.file) items) items
forM_ fsitems $
go DiffTree.srcsha DiffTree.srcmode moveout moveout_raw
forM_ fsitems $
go DiffTree.dstsha DiffTree.dstmode movein movein_raw
void $ liftIO cleanup void $ liftIO cleanup
liftIO $ removeDirectoryRecursive d liftIO $ removeDirectoryRecursive d
where where
updated makeabs item = do go getsha getmode a araw (f, item)
let f = makeabs (DiffTree.file item) | getsha item == nullSha = noop
void $ tryAnnex $ | otherwise = void $
go f DiffTree.srcsha DiffTree.srcmode moveout moveout_raw tryAnnex . maybe (araw f) (\k -> void $ a k f)
void $ tryAnnex $ =<< catKey (getsha item) (getmode item)
go f DiffTree.dstsha DiffTree.dstmode movein movein_raw
where
go f getsha getmode a araw
| getsha item == nullSha = noop
| otherwise = maybe (araw f) (\k -> void $ a k f)
=<< catKey (getsha item) (getmode item)
moveout = removeDirect moveout k f = removeDirect k f
{- Files deleted by the merge are removed from the work tree. {- Files deleted by the merge are removed from the work tree.
- Empty work tree directories are removed, per git behavior. -} - Empty work tree directories are removed, per git behavior. -}

4
debian/changelog vendored
View file

@ -27,6 +27,10 @@ git-annex (5.20131102) UNRELEASED; urgency=low
* repair: Handle case where index file is corrupt, but all objects are ok. * repair: Handle case where index file is corrupt, but all objects are ok.
* assistant: Notice on startup when the index file is corrupt, and * assistant: Notice on startup when the index file is corrupt, and
auto-repair. auto-repair.
* Fix direct mode merge bug when a direct mode file was deleted and replaced
with a directory. An ordering problem caused the directory to not get
created in this case.
Thanks to Tim for the test cases.
-- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400 -- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400

View file

@ -40,3 +40,5 @@ remote types: git gcrypt S3 bup directory rsync web webdav glacier hook
Linux ceilingcat 3.11.6-1-ARCH #1 SMP PREEMPT Fri Oct 18 23:22:36 CEST 2013 x86_64 GNU/Linux Linux ceilingcat 3.11.6-1-ARCH #1 SMP PREEMPT Fri Oct 18 23:22:36 CEST 2013 x86_64 GNU/Linux
"""]] """]]
> [[fixed|done]] --[[Joey]]