if neednewlocalbranch
then do
cmode <- annexCommitMode <$> Annex.getGitConfig
- committedref <- inRepo $ Git.Branch.commitAlways cmode message fullname transitionedrefs
- setIndexSha committedref
+ -- Creating a new empty branch must happen
+ -- atomically, so if this is interrupted,
+ -- it will not leave the new branch created
+ -- but without exports grafted in.
+ c <- inRepo $ Git.Branch.commitShaAlways
+ cmode message transitionedrefs
+ void $ regraftexports c
else do
ref <- getBranch
- commitIndex jl ref message (nub $ fullname:transitionedrefs)
- regraftexports
+ ref' <- regraftexports ref
+ commitIndex jl ref' message
+ (nub $ fullname:transitionedrefs)
where
message
| neednewlocalbranch && null transitionedrefs = "new branch for transition " ++ tdesc
apply rest file content'
-- Trees mentioned in export.log were grafted into the old
- -- git-annex branch to make sure they remain available. Re-graft
- -- the trees into the new branch.
- regraftexports = do
+ -- git-annex branch to make sure they remain available.
+ -- Re-graft the trees.
+ regraftexports parent = do
l <- exportedTreeishes . M.elems . parseExportLogMap
<$> getStaged exportLog
- forM_ l $ \t ->
- rememberTreeishLocked t (asTopFilePath exportTreeGraftPoint) jl
+ c <- regraft l parent
+ inRepo $ Git.Branch.update' fullname c
+ setIndexSha c
+ return c
+ where
+ regraft [] c = pure c
+ regraft (et:ets) c =
+ prepRememberTreeish et graftpoint c
+ >>= regraft ets
+ graftpoint = asTopFilePath exportTreeGraftPoint
checkBranchDifferences :: Git.Ref -> Annex ()
checkBranchDifferences ref = do
- Returns the sha of the git commit made to the git-annex branch.
-}
rememberTreeish :: Git.Ref -> TopFilePath -> Annex Git.Sha
-rememberTreeish treeish graftpoint = lockJournal $
- rememberTreeishLocked treeish graftpoint
-rememberTreeishLocked :: Git.Ref -> TopFilePath -> JournalLocked -> Annex Git.Sha
-rememberTreeishLocked treeish graftpoint jl = do
+rememberTreeish treeish graftpoint = lockJournal $ \jl -> do
branchref <- getBranch
updateIndex jl branchref
+ c <- prepRememberTreeish treeish graftpoint branchref
+ inRepo $ Git.Branch.update' fullname c
+ -- The tree in c is the same as the tree in branchref,
+ -- and the index was updated to that above, so it's safe to
+ -- say that the index contains c.
+ setIndexSha c
+ return c
+
+{- Create a series of commits that graft a tree onto the parent commit,
+ - and then remove it. -}
+prepRememberTreeish :: Git.Ref -> TopFilePath -> Git.Ref -> Annex Git.Sha
+prepRememberTreeish treeish graftpoint parent = do
origtree <- fromMaybe (giveup "unable to determine git-annex branch tree") <$>
- inRepo (Git.Ref.tree branchref)
+ inRepo (Git.Ref.tree parent)
addedt <- inRepo $ Git.Tree.graftTree treeish graftpoint origtree
cmode <- annexCommitMode <$> Annex.getGitConfig
c <- inRepo $ Git.Branch.commitTree cmode
- ["graft"] [branchref] addedt
- c' <- inRepo $ Git.Branch.commitTree cmode
+ ["graft"] [parent] addedt
+ inRepo $ Git.Branch.commitTree cmode
["graft cleanup"] [c] origtree
- inRepo $ Git.Branch.update' fullname c'
- -- The tree in c' is the same as the tree in branchref,
- -- and the index was updated to that above, so it's safe to
- -- say that the index contains c'.
- setIndexSha c'
- return c'
{- Runs an action on the content of selected files from the branch.
- This is much faster than reading the content of each file in turn,
- 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
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