git - Empty commits removed after interactive rebase, even though --keep-empty is used -
i have trouble using --keep-empty option of git rebase, , i'm not sure whether i'm misunderstanding option does, or there's bug.
here minimal example:
setup
create new git repository , initial, unrelated commit.
$ git init $ echo >base.txt $ git add base.txt $ git commit -m 'some base commit not run root corner case'create new commit adds 2 new files.
$ echo >a.txt; echo b >b.txt $ git add a.txt b.txt $ git commit -m 'add , b'modify 1 of files.
$ echo a1 >a.txt $ git add a.txt $ git commit -m 'change a'modify other file.
$ echo b1 >b.txt $ git add b.txt $ git commit -m 'change b'
rebase
$ git checkout -b rebased master $ git rebase --keep-empty -i :/base … choosing edit commit a , b added, , changing b added (in real scenario reason might a confidential):
$ git rm a.txt $ git commit --amend $ git rebase --continue naturally, next commit a modified gives conflict:
error: not apply 182aaa1... change when have resolved problem, run "git rebase --continue". if prefer skip patch, run "git rebase --skip" instead. check out original branch , stop rebasing, run "git rebase --abort". not apply 182aaa1701ad100fc02a5d5500cacebdd317a24b... change … choosing not add modified version of a.txt:
$ git mergetool merging: a.txt deleted merge conflict 'a.txt': {local}: deleted {remote}: modified file use (m)odified or (d)eleted file, or (a)bort? d the commit a modified empty:
$ git diff --cached # nothing … , finishing rebase:
$ git rebase --continue rebased , updated refs/heads/rebased. question
so have 2 versions of history, difference there no trace of a in 1 of them. however, because chose --keep-empty option, still expect empty commit exist in rebased, show me a have been modified, had been there.
but apparently, not case:
$ git log --oneline master f893569 change b 182aaa1 change 3340b71 add , b 38cb5da base commit not run root corner case $ git log --oneline rebased 73a2c05 change b 55f502b add , b 38cb5da base commit not run root corner case is not --keep-empty supposed do, or not work correctly?
related: rebase on root , keep empty commits similar question, involves --root corner case explicitly avoided here. , has no answer, comments suggest i'm showing here should work. difference in other question commit empty in first place, while here becomes empty after resolving conflict.
it's sort of bug, due sort of feature. :-)
when run interactive rebase , "pauses", in reality, finishes, leaves files around let new git rebase realize it's more of continuation after all. fine far goes; need run git rebase --continue later start new rebase , tell it: you're not new, go read state , act you're continuing original rebase.
and, let's @ "interactive rebase". in reality series of cherry-pick operations: pick command literally instructs old rebase shell script—which being phased out now—to run git cherry-pick.
ok, no big deal far. let's consider why interactive rebase stops. there 2 reasons:
you marked commit "edit". commits cherry-pick, , stops let amend commit or otherwise fuss it.
or, there problem—such merge conflict—that forced stop.
in case (1), when run git rebase --continue, git should not make own commit.
in case (2), when run git rebase --continue, git should make own commit. is, should unless—this feature part—you make own commit first. in case, case (2) git should not make own commit.
git could, , perhaps should, record reason-for-stoppage tell these 2 cases apart ... doesn't. instead, looks @ state on --continue.
for non-interactive rebase, git knows stops on conflicts, knows try make commit, , complain if there nothing commit. --keep-empty or -k flag useful. (internally, non-interactive case uses git format-patch , git am default, although can force use interactive machinery --preserve-merges instance. mention here it's implementational reason git has know whether you're being "interactive": happens, here git lets implementation dictate behavior. if git didn't need distinction, --continue use same code interactive , non-interactive rebase, git does need distinction, , hence doesn't use same code.)
for interactive rebase, though, git allows make own commit in case (2), before running git rebase --continue (this feature part). if so, --continue step should move on next commit. --continue checks whether there's commit now, rather whether earlier interactive rebase exited case (1) vs case (2). simple implementation trick enables feature, means --keep-empty cannot work here: git doesn't know difference.
the workaround own git commit --allow-empty after resolving merge. in other words, convert case (2) simulated case (1), using "you may make own commit" feature.
Comments
Post a Comment