atomic git-annex branch update when regrafting in transition

Fix a bug where interrupting git-annex while it is updating the git-annex
branch could lead to git fsck complaining about missing tree objects.

Interrupting git-annex while regraftexports is running in a transition
that is forgetting git-annex branch history would leave the
repository with a git-annex branch that did not contain the tree shas
listed in export.log. That lets those trees be garbage collected.

A subsequent run of the same transition then regrafts the trees listed
in export.log into the git-annex branch. But those trees have been lost.

Note that both sides of `if neednewlocalbranch` are atomic now. I had
thought only the True side needed to be, but I do think there may be
cases where the False side needs to be as well.

Sponsored-by: Dartmouth College's OpenNeuro project
This commit is contained in:
Joey Hess 2024-06-07 15:59:54 -04:00
parent f5532be954
commit b32c4c2e98
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 78 additions and 27 deletions

View file

@ -178,13 +178,25 @@ commitCommand' runner commitmode commitquiet ps =
- in any way, or output a summary.
-}
commit :: CommitMode -> Bool -> String -> Branch -> [Ref] -> Repo -> IO (Maybe Sha)
commit commitmode allowempty message branch parentrefs repo = do
tree <- writeTree repo
ifM (cancommit tree)
( do
sha <- commitTree commitmode [message] parentrefs tree repo
commit commitmode allowempty message branch parentrefs repo =
commitSha commitmode allowempty message parentrefs repo >>= \case
Just sha -> do
update' branch sha repo
return $ Just sha
Nothing -> return Nothing
where
cancommit tree
| allowempty = return True
| otherwise = case parentrefs of
[p] -> maybe False (tree /=) <$> Git.Ref.tree p repo
_ -> return True
{- Same as commit but without updating any branch. -}
commitSha :: CommitMode -> Bool -> String -> [Ref] -> Repo -> IO (Maybe Sha)
commitSha commitmode allowempty message parentrefs repo = do
tree <- writeTree repo
ifM (cancommit tree)
( Just <$> commitTree commitmode [message] parentrefs tree repo
, return Nothing
)
where
@ -198,6 +210,10 @@ commitAlways :: CommitMode -> String -> Branch -> [Ref] -> Repo -> IO Sha
commitAlways commitmode message branch parentrefs repo = fromJust
<$> commit commitmode True message branch parentrefs repo
commitShaAlways :: CommitMode -> String -> [Ref] -> Repo -> IO Sha
commitShaAlways commitmode message parentrefs repo = fromJust
<$> commitSha commitmode True message parentrefs repo
-- Throws exception if the index is locked, with an error message output by
-- git on stderr.
writeTree :: Repo -> IO Sha