prospective fix for bad_merge_commit_deleting_all_files
Assuming my analysis of a race is correct. In any case, this certianly closes a race..
This commit is contained in:
parent
4915f9ad03
commit
58acaf8026
4 changed files with 44 additions and 8 deletions
|
@ -5,6 +5,8 @@
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
{-# LANGUAGE CPP #-}
|
||||||
|
|
||||||
module Annex.Direct where
|
module Annex.Direct where
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
|
@ -150,13 +152,16 @@ addDirect file cache = do
|
||||||
- directory, and the merge is staged into a copy of the index.
|
- directory, and the merge is staged into a copy of the index.
|
||||||
- Then the work tree is updated to reflect the merge, and
|
- Then the work tree is updated to reflect the merge, and
|
||||||
- finally, the merge is committed and the real index updated.
|
- finally, the merge is committed and the real index updated.
|
||||||
|
-
|
||||||
|
- A lock file is used to avoid races with any other caller of mergeDirect.
|
||||||
|
-
|
||||||
|
- To avoid other git processes from making change to the index while our
|
||||||
|
- merge is in progress, the index lock file is used as the temp index
|
||||||
|
- file. This is the same as what git does when updating the index
|
||||||
|
- normally.
|
||||||
-}
|
-}
|
||||||
mergeDirect :: Maybe Git.Ref -> Maybe Git.Ref -> Git.Branch -> Annex Bool -> Git.Branch.CommitMode -> Annex Bool
|
mergeDirect :: Maybe Git.Ref -> Maybe Git.Ref -> Git.Branch -> Annex Bool -> Git.Branch.CommitMode -> Annex Bool
|
||||||
mergeDirect startbranch oldref branch resolvemerge commitmode = do
|
mergeDirect startbranch oldref branch resolvemerge commitmode = lockMerge $ do
|
||||||
-- Use the index lock file as the temp index file.
|
|
||||||
-- This is actually what git does when updating the index,
|
|
||||||
-- and so it will prevent other git processes from making
|
|
||||||
-- any changes to the index while our merge is in progress.
|
|
||||||
reali <- fromRepo indexFile
|
reali <- fromRepo indexFile
|
||||||
tmpi <- fromRepo indexFileLock
|
tmpi <- fromRepo indexFileLock
|
||||||
liftIO $ copyFile reali tmpi
|
liftIO $ copyFile reali tmpi
|
||||||
|
@ -174,9 +179,29 @@ mergeDirect startbranch oldref branch resolvemerge commitmode = do
|
||||||
else resolvemerge
|
else resolvemerge
|
||||||
mergeDirectCleanup d (fromMaybe Git.Sha.emptyTree oldref)
|
mergeDirectCleanup d (fromMaybe Git.Sha.emptyTree oldref)
|
||||||
mergeDirectCommit merged startbranch branch commitmode
|
mergeDirectCommit merged startbranch branch commitmode
|
||||||
|
|
||||||
liftIO $ rename tmpi reali
|
liftIO $ rename tmpi reali
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
lockMerge :: Annex a -> Annex a
|
||||||
|
lockMerge a = do
|
||||||
|
lockfile <- fromRepo gitAnnexMergeLock
|
||||||
|
createAnnexDirectory $ takeDirectory lockfile
|
||||||
|
mode <- annexFileMode
|
||||||
|
bracketIO (lock lockfile mode) unlock (const a)
|
||||||
|
where
|
||||||
|
#ifndef mingw32_HOST_OS
|
||||||
|
lock lockfile mode = do
|
||||||
|
l <- noUmask mode $ createFile lockfile mode
|
||||||
|
waitToSetLock l (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
|
return l
|
||||||
|
unlock = closeFd
|
||||||
|
#else
|
||||||
|
lock lockfile _mode = waitToLock $ lockExclusive lockfile
|
||||||
|
unlock = dropLock
|
||||||
|
#endif
|
||||||
|
|
||||||
{- Stage a merge into the index, avoiding changing HEAD or the current
|
{- Stage a merge into the index, avoiding changing HEAD or the current
|
||||||
- branch. -}
|
- branch. -}
|
||||||
stageMerge :: FilePath -> Git.Branch -> Git.Branch.CommitMode -> Annex Bool
|
stageMerge :: FilePath -> Git.Branch -> Git.Branch.CommitMode -> Annex Bool
|
||||||
|
|
|
@ -42,6 +42,7 @@ module Locations (
|
||||||
gitAnnexJournalDir,
|
gitAnnexJournalDir,
|
||||||
gitAnnexJournalLock,
|
gitAnnexJournalLock,
|
||||||
gitAnnexPreCommitLock,
|
gitAnnexPreCommitLock,
|
||||||
|
gitAnnexMergeLock,
|
||||||
gitAnnexIndex,
|
gitAnnexIndex,
|
||||||
gitAnnexIndexStatus,
|
gitAnnexIndexStatus,
|
||||||
gitAnnexViewIndex,
|
gitAnnexViewIndex,
|
||||||
|
@ -262,6 +263,10 @@ gitAnnexJournalLock r = gitAnnexDir r </> "journal.lck"
|
||||||
gitAnnexPreCommitLock :: Git.Repo -> FilePath
|
gitAnnexPreCommitLock :: Git.Repo -> FilePath
|
||||||
gitAnnexPreCommitLock r = gitAnnexDir r </> "precommit.lck"
|
gitAnnexPreCommitLock r = gitAnnexDir r </> "precommit.lck"
|
||||||
|
|
||||||
|
{- Lock file for direct mode merge. -}
|
||||||
|
gitAnnexMergeLock :: Git.Repo -> FilePath
|
||||||
|
gitAnnexMergeLock r = gitAnnexDir r </> "merge.lck"
|
||||||
|
|
||||||
{- .git/annex/index is used to stage changes to the git-annex branch -}
|
{- .git/annex/index is used to stage changes to the git-annex branch -}
|
||||||
gitAnnexIndex :: Git.Repo -> FilePath
|
gitAnnexIndex :: Git.Repo -> FilePath
|
||||||
gitAnnexIndex r = gitAnnexDir r </> "index"
|
gitAnnexIndex r = gitAnnexDir r </> "index"
|
||||||
|
|
4
debian/changelog
vendored
4
debian/changelog
vendored
|
@ -3,6 +3,10 @@ git-annex (5.20140708) UNRELEASED; urgency=medium
|
||||||
* Fix git version that supported --no-gpg-sign.
|
* Fix git version that supported --no-gpg-sign.
|
||||||
* Fix bug in automatic merge conflict resolution, when one side is an
|
* Fix bug in automatic merge conflict resolution, when one side is an
|
||||||
annexed symlink, and the other side is a non-annexed symlink.
|
annexed symlink, and the other side is a non-annexed symlink.
|
||||||
|
* Fix race in direct mode merge code that could cause all files in the
|
||||||
|
repository to be removed. It should be able to recover repositories
|
||||||
|
experiencing this bug without data loss. See:
|
||||||
|
http://git-annex.branchable.com/bugs/bad_merge_commit_deleting_all_files/
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Tue, 08 Jul 2014 12:44:42 -0400
|
-- Joey Hess <joeyh@debian.org> Tue, 08 Jul 2014 12:44:42 -0400
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,11 @@ redo, passing `-m 2` instead.)
|
||||||
Once the revert is done, all your files should be back. You can switch
|
Once the revert is done, all your files should be back. You can switch
|
||||||
the repository back to direct mode if desired (`git annex direct`)
|
the repository back to direct mode if desired (`git annex direct`)
|
||||||
and can `git annex sync` to push the fix out to all other clones.
|
and can `git annex sync` to push the fix out to all other clones.
|
||||||
Everywhere the fix lands should restore the deleted files. (Although
|
Everywhere the fix lands should restore the deleted files.
|
||||||
it's possible that some repositories may have pruned the deleted
|
|
||||||
files as unused.)
|
Note that it's possible that some repositories may have pruned the deleted
|
||||||
|
files as unused. This is most likely to happen in the repository that made
|
||||||
|
the bad merge commit in the first place.
|
||||||
|
|
||||||
[[!tag confirmed urgent]]
|
[[!tag confirmed urgent]]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue