bug in rebase--interactive with squash and conflicts
Hi,
There's a problem with rebase--interactive where I want to squash two commits and the one to squash is the first in the original series. In particular, I change the commit list from
pick 1
pick 2
pick 3
to
pick 3
squash 1
pick 2
In this case, the edits of commit 3 are lost. There are conflicts when commits 3 and 1 are cherry-picked.
You can simulate the problematic case by applying this patch:
index 40d6799..861ece1 100755
t/t3404-rebase-interactive.sh +3 -2
@@ -252,3 +252,4 @@ 'interrupted squash works as expected' ' echo $n >> conflict && - git add conflict && + echo $n > $n + git add conflict $n && git commit -m $n
@@ -256,3 +257,3 @@ 'interrupted squash works as expected' ' one=$(git rev-parse HEAD~3) && - ! FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 && + ! FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 && (echo one; echo two; echo four) > conflict &&
The test fails now, because git rebase --continue did not fail although it should have. Run
gitk HEAD to-be-rebased@{1}
Note that the rebase was completed, i.e. there are now 2 commits instead of the original 3. But the file 'four' is missing and the final contents of the file 'conflict' is
one
two
three
i.e. as if commit 3 had never taken place.
-- Hannes
PATCH 1/1 rebase -i: fix squashing corner case
When squashing, rebase -i did not prevent fast forwards. This could happen when picking some other commit than the first one, and then squashing the first commit. So do not allow fast forwards when squashing.
Noticed by Johannes Sixt.
---
On Tue, 21 Aug 2007, Johannes Sixt wrote:
> There's a problem with rebase--interactive where I want to > squash two commits and the one to squash is the first in the > original series.
Thanks.
git-rebase--interactive.sh | 5 +++-- t/t3404-rebase-interactive.sh | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-)
git-rebase--interactive.sh +3 -2
@@ -96,13 +96,14 @@ die_abort () { } pick_one () { - case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac + no_ff= + case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" test -d "$REWRITTEN" && pick_one_preserving_merges "$@" && return parent_sha1=$(git rev-parse --verify $sha1^ 2>/dev/null) current_sha1=$(git rev-parse --verify HEAD) - if test $current_sha1 = $parent_sha1; then + if test $no_ff$current_sha1 = $parent_sha1; then output git reset --hard $sha1 test "a$1" = a-n && output git reset --soft $current_sha1 sha1=$(git rev-parse --short $sha1)
t/t3404-rebase-interactive.sh +21 -0
@@ -264,6 +264,27 @@ test_expect_success 'interrupted squash works as expected' ' test $one = $(git rev-parse HEAD~2) ' +test_expect_success 'interrupted squash works as expected (case 2)' ' + for n in one two three four + do + echo $n >> conflict && + git add conflict && + git commit -m $n + done && + one=$(git rev-parse HEAD~3) && + ! FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 && + (echo one; echo four) > conflict && + git add conflict && + ! git rebase --continue && + (echo one; echo two; echo four) > conflict && + git add conflict && + ! git rebase --continue && + echo resolved > conflict && + git add conflict && + git rebase --continue && + test $one = $(git rev-parse HEAD~2) +' + test_expect_success 'ignore patch if in upstream' ' HEAD=$(git rev-parse HEAD) && git checkout -b has-cherry-picked HEAD^ &&
Signature · 1 line
1.5.3.rc6.3.gaf460
Re: [PATCH] rebase -i: fix squashing corner case
Quoted 5 lines · Johannes Schindelin
When squashing, rebase -i did not prevent fast forwards. This could happen when picking some other commit than the first one, and then squashing the first commit. So do not allow fast forwards when squashing.
This indeed fixes the problem. Hence:
Junio, please apply.
-- Hannes