built-in rebase --autostash: fix regression
cover built-in rebase --autostash: fix regression
It was reported that the new, shiny built-in git rebase has a bug where it would detach the HEAD when it was not even necessary to detach it.
Keeping with my fine tradition to first demonstrate what is the actual problem (and making it easy to verify my claim), this patch series first introduces the regression test, and then the (quite simple) fix.
AEvar, sorry for the ASCII-fication of your name, I still did not find the time to look at the GitGitGadget bug closely where it does the wrong thing when Cc:ing with non-ASCII names.
Johannes Schindelin (2):
built-in rebase: demonstrate regression with --autostash built-in rebase --autostash: leave the current branch alone if
possible
builtin/rebase.c | 3 ++- t/t3420-rebase-autostash.sh | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
base-commit: 8858448bb49332d353febc078ce4a3abcc962efe
Published-As: https://github.com/gitgitgadget/git/releases/tags/pr-70%2Fdscho%2Ffix-built-in-rebase-autostash-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-70/dscho/fix-built-in-rebase-autostash-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/70
Signature · 1 line
gitgitgadget
PATCH 1/2 built-in rebase: demonstrate regression with --autostash
From: Johannes Schindelin <[email protected]>
An unnamed colleague of Ævar Arnfjörð Bjarmason reported a breakage where a pull --rebase (which did not really need to do anything but stash, see that nothing was changed, and apply the stash again) also detached the HEAD.
This patch adds a minimal reproducer for this regression.
--- t/t3420-rebase-autostash.sh | 8 ++++++++ 1 file changed, 8 insertions(+)
t/t3420-rebase-autostash.sh +8 -0
@@ -361,4 +361,12 @@ test_expect_success 'autostash with dirty submodules' ' git rebase -i --autostash HEAD ' +test_expect_failure 'branch is left alone when possible' ' + git checkout -b unchanged-branch && + echo changed >file0 && + git rebase --autostash unchanged-branch && + test changed = "$(cat file0)" && + test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)" +' + test_done
Signature · 1 line
gitgitgadget
PATCH 2/2 built-in rebase --autostash: leave the current branch alone if possible
In reply to Johannes Schindelin via GitGitGadgetFrom: Johannes Schindelin <[email protected]>
When we converted a git reset --hard call in the original Unix shell script to built-in code, we asked to reset the worktree and the index and explicitly *not* to detach the HEAD. By mistake, though, we still did. Let's fix this.
--- builtin/rebase.c | 3 ++- t/t3420-rebase-autostash.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
builtin/rebase.c +2 -1
@@ -613,7 +613,8 @@ static int reset_head(struct object_id *oid, const char *action, reflog_head = msg.buf; }if (!switch_to_branch) - ret =update_ref (reflog_head,"HEAD" , oid, orig,REF_NO_DEREF , + ret =update_ref (reflog_head,"HEAD" , oid, orig, + detach_head ?REF_NO_DEREF :0 ,UPDATE_REFS_MSG_ON_ERR );else { ret =create_symref ("HEAD" , switch_to_branch, msg.buf);
t/t3420-rebase-autostash.sh +1 -1
@@ -361,7 +361,7 @@ test_expect_success 'autostash with dirty submodules' ' git rebase -i --autostash HEAD ' -test_expect_failure 'branch is left alone when possible' ' +test_expect_success 'branch is left alone when possible' ' git checkout -b unchanged-branch && echo changed >file0 && git rebase --autostash unchanged-branch &&
Signature · 1 line
gitgitgadget
Re: [PATCH 2/2] built-in rebase --autostash: leave the current branch alone if possible
Quoted 12 lines · Johannes Schindelin via GitGitGadget
From: Johannes Schindelin <[email protected]>
When we converted a
git reset --hardcall in the original Unix shell script to built-in code, we asked to reset the worktree and the index and explicitly *not* to detach the HEAD. By mistake, though, we still did. Let's fix this.
[...]builtin/rebase.c +0
-0
builtin/rebase.c static int reset_head(struct object_id *oid, const char *action, · line 618
Quoted 7 lines
builtin/rebase.c +2
-1@@ -613,7 +613,8 @@ static int reset_head(struct object_id *oid, const char *action, reflog_head = msg.buf; }if (!switch_to_branch) - ret =update_ref (reflog_head,"HEAD" , oid, orig,REF_NO_DEREF , + ret =update_ref (reflog_head,"HEAD" , oid, orig, + detach_head ?REF_NO_DEREF :0 ,UPDATE_REFS_MSG_ON_ERR );
This makes sense. There are actually a bunch of calls that pass detach_head==0, besides the one related to autostash. I suspect for most of them it does not matter, because either:
1. We are already on a detached HEAD, since we detach as the first step of the rebase. So for the call in ACTION_SKIP, for example, we probably cannot trigger the problem.
2. They pass a switch_to_branch arg, so we do not hit this code path anyway (the call to fast-forward is like this, for example).
So there may be other ways to trigger the problem, but I didn't dig. Either way, your fix is clearly the right thing to do.
-Peff