propigateAdjustedCommits: avoid overwriting diverged original branch

Bug fix: Re-running git-annex adjust or sync when in an adjusted branch
would overwrite the original branch, losing any commits that had been made
to it since the adjusted branch was created.

When git-annex adjust is run in this situation, it will display a warning
about the diverged branches.

When git-annex sync is run in this situation, mergeToAdjustedBranch
will merge the changes from the original branch to the adjusted branch.
So it does not need to display the divergence warning.

Note that for some reason, I'm needing to run sync twice for that to
happen. The first run does not do the merge and the second does. I'm unsure
why and so am not fully done with this bug.

Sponsored-By: the NIH-funded NICEMAN (ReproNim TR&D3) project
This commit is contained in:
Joey Hess 2023-07-05 17:01:39 -04:00
parent fc1fcc7491
commit adb09117f1
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
5 changed files with 66 additions and 13 deletions

View file

@ -258,7 +258,7 @@ updateAdjustedBranch adj (AdjBranch currbranch) origbranch
-- Avoid losing any commits that the adjusted branch -- Avoid losing any commits that the adjusted branch
-- has that have not yet been propigated back to the -- has that have not yet been propigated back to the
-- origbranch. -- origbranch.
_ <- propigateAdjustedCommits' origbranch adj commitlck _ <- propigateAdjustedCommits' True origbranch adj commitlck
origheadfile <- inRepo $ readFileStrict . Git.Ref.headFile origheadfile <- inRepo $ readFileStrict . Git.Ref.headFile
origheadsha <- inRepo (Git.Ref.sha currbranch) origheadsha <- inRepo (Git.Ref.sha currbranch)
@ -294,7 +294,7 @@ updateAdjustedBranch adj (AdjBranch currbranch) origbranch
return ok return ok
| otherwise = preventCommits $ \commitlck -> do | otherwise = preventCommits $ \commitlck -> do
-- Done for consistency. -- Done for consistency.
_ <- propigateAdjustedCommits' origbranch adj commitlck _ <- propigateAdjustedCommits' True origbranch adj commitlck
-- No need to actually update the branch because the -- No need to actually update the branch because the
-- adjustment is stable. -- adjustment is stable.
return True return True
@ -495,20 +495,21 @@ findAdjustingCommit (AdjBranch b) = go =<< catCommit b
propigateAdjustedCommits :: OrigBranch -> Adjustment -> Annex () propigateAdjustedCommits :: OrigBranch -> Adjustment -> Annex ()
propigateAdjustedCommits origbranch adj = propigateAdjustedCommits origbranch adj =
preventCommits $ \commitsprevented -> preventCommits $ \commitsprevented ->
join $ snd <$> propigateAdjustedCommits' origbranch adj commitsprevented join $ snd <$> propigateAdjustedCommits' True origbranch adj commitsprevented
{- Returns sha of updated basis branch, and action which will rebase {- Returns sha of updated basis branch, and action which will rebase
- the adjusted branch on top of the updated basis branch. -} - the adjusted branch on top of the updated basis branch. -}
propigateAdjustedCommits' propigateAdjustedCommits'
:: OrigBranch :: Bool
-> OrigBranch
-> Adjustment -> Adjustment
-> CommitsPrevented -> CommitsPrevented
-> Annex (Maybe Sha, Annex ()) -> Annex (Maybe Sha, Annex ())
propigateAdjustedCommits' origbranch adj _commitsprevented = propigateAdjustedCommits' warnwhendiverged origbranch adj _commitsprevented =
inRepo (Git.Ref.sha basis) >>= \case inRepo (Git.Ref.sha basis) >>= \case
Just origsha -> catCommit currbranch >>= \case Just origsha -> catCommit currbranch >>= \case
Just currcommit -> Just currcommit ->
newcommits >>= go origsha False >>= \case newcommits >>= go origsha origsha False >>= \case
Left e -> do Left e -> do
warning (UnquotedString e) warning (UnquotedString e)
return (Nothing, return ()) return (Nothing, return ())
@ -528,20 +529,25 @@ propigateAdjustedCommits' origbranch adj _commitsprevented =
-- Get commits oldest first, so they can be processed -- Get commits oldest first, so they can be processed
-- in order made. -- in order made.
[Param "--reverse"] [Param "--reverse"]
go parent _ [] = do go origsha parent _ [] = do
setBasisBranch (BasisBranch basis) parent setBasisBranch (BasisBranch basis) parent
inRepo $ Git.Branch.update' origbranch parent inRepo (Git.Ref.sha origbranch) >>= \case
Just origbranchsha | origbranchsha /= origsha ->
when warnwhendiverged $
warning $ UnquotedString $
"Original branch " ++ fromRef origbranch ++ " has diverged from current adjusted branch " ++ fromRef currbranch
_ -> inRepo $ Git.Branch.update' origbranch parent
return (Right parent) return (Right parent)
go parent pastadjcommit (sha:l) = catCommit sha >>= \case go origsha parent pastadjcommit (sha:l) = catCommit sha >>= \case
Just c Just c
| commitMessage c == adjustedBranchCommitMessage -> | commitMessage c == adjustedBranchCommitMessage ->
go parent True l go origsha parent True l
| pastadjcommit -> | pastadjcommit ->
reverseAdjustedCommit parent adj (sha, c) origbranch reverseAdjustedCommit parent adj (sha, c) origbranch
>>= \case >>= \case
Left e -> return (Left e) Left e -> return (Left e)
Right commit -> go commit pastadjcommit l Right commit -> go origsha commit pastadjcommit l
_ -> go parent pastadjcommit l _ -> go origsha parent pastadjcommit l
rebase currcommit newparent = do rebase currcommit newparent = do
-- Reuse the current adjusted tree, and reparent it -- Reuse the current adjusted tree, and reparent it
-- on top of the newparent. -- on top of the newparent.

View file

@ -46,7 +46,7 @@ mergeToAdjustedBranch tomerge (origbranch, adj) mergeconfig canresolvemerge comm
ifM (inRepo $ Git.Branch.changed currbranch tomerge) ifM (inRepo $ Git.Branch.changed currbranch tomerge)
( do ( do
(updatedorig, _) <- propigateAdjustedCommits' (updatedorig, _) <- propigateAdjustedCommits'
origbranch adj commitsprevented False origbranch adj commitsprevented
changestomerge updatedorig changestomerge updatedorig
, nochangestomerge , nochangestomerge
) )

View file

@ -8,6 +8,9 @@ git-annex (10.20230627) UNRELEASED; urgency=medium
annexed text files. annexed text files.
* assist: With --jobs, parallelize transferring content to/from remotes. * assist: With --jobs, parallelize transferring content to/from remotes.
* Fix breakage when git is configured with safe.bareRepository = explicit. * Fix breakage when git is configured with safe.bareRepository = explicit.
* Bug fix: Re-running git-annex adjust or sync when in an adjusted branch
would overwrite the original branch, losing any commits that had been
made to it since the adjusted branch was created.
-- Joey Hess <id@joeyh.name> Mon, 26 Jun 2023 13:10:40 -0400 -- Joey Hess <id@joeyh.name> Mon, 26 Jun 2023 13:10:40 -0400

View file

@ -0,0 +1,33 @@
[[!comment format=mdwn
username="joey"
subject="""comment 1"""
date="2023-07-05T19:49:19Z"
content="""
Simplified test case:
git init tc
cd tc
git-annex init
echo 1 > foo
git-annex add
git commit -m add
git annex adjust --unlock
git checkout master
rm foo
echo 2 > foo
git-annex add
git commit -m "this commit will be lost"
git checkout 'adjusted/master(unlocked)'
git annex adjust --unlock # or git-annex sync
git log master
What an unfortunate oversight! And it's not a reversion, it's been there
since the beginning of adjusted branches.
git-annex adjust should display a warning message in that situation,
since the original branch has diverged from the adjusted branch.
And git-annex sync should be able to resolve the divergence by
auto-merging the changes from the original branch into the adjusted
branch.
"""]]

View file

@ -0,0 +1,11 @@
[[!comment format=mdwn
username="joey"
subject="""comment 2"""
date="2023-07-05T21:01:53Z"
content="""
I've fixed the data loss part of this bug.
`git-annex sync` is able to resolve the divergence too. But for some
reason, the first time it's run after the divergence, it leaves it
diverged, and the second time it resolves it. That needs to be fixed.
"""]]