Skip to content

Commit

Permalink
rebase -i: handle fixup! fixup! in --autosquash
Browse files Browse the repository at this point in the history
In rebase -i --autosquash, ignore all "fixup! " or "squash! " after the
first.  This supports the case when a git commit --fixup/--squash referred
to an earlier fixup/squash instead of the original commit (whether
intentionally, as when the user expressly meant to note that the commit
fixes an earlier fixup; or inadvertently, as when the user meant to refer to
the original commit with :/msg; or out of laziness, as when the user could
remember how to refer to the fixup but not the original).

In the todo list, the full commit message is preserved, in case it provides
useful cues to the user.  A test helper set_cat_todo_editor is introduced to
check this.

Helped-by: Thomas Rast <trast@inf.ethz.ch>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Andrew Pimlott <andrew@pimlott.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Andrew Pimlott authored and Junio C Hamano committed Jun 27, 2013
1 parent 9832cb9 commit 22c5b13
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 6 deletions.
4 changes: 3 additions & 1 deletion Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ squash/fixup series.
the same ..., automatically modify the todo list of rebase -i
so that the commit marked for squashing comes right after the
commit to be modified, and change the action of the moved
commit from `pick` to `squash` (or `fixup`).
commit from `pick` to `squash` (or `fixup`). Ignores subsequent
"fixup! " or "squash! " after the first, in case you referred to an
earlier fixup/squash with `git commit --fixup/--squash`.
+
This option is only valid when the '--interactive' option is used.
+
Expand Down
25 changes: 20 additions & 5 deletions git-rebase--interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -689,8 +689,22 @@ rearrange_squash () {
case "$message" in
"squash! "*|"fixup! "*)
action="${message%%!*}"
rest="${message#*! }"
echo "$sha1 $action $rest"
rest=$message
prefix=
# skip all squash! or fixup! (but save for later)
while :
do
case "$rest" in
"squash! "*|"fixup! "*)
prefix="$prefix${rest%%!*},"
rest="${rest#*! }"
;;
*)
break
;;
esac
done
echo "$sha1 $action $prefix $rest"
# if it's a single word, try to resolve to a full sha1 and
# emit a second copy. This allows us to match on both message
# and on sha1 prefix
Expand All @@ -699,7 +713,7 @@ rearrange_squash () {
if test -n "$fullsha"; then
# prefix the action to uniquely identify this line as
# intended for full sha1 match
echo "$sha1 +$action $fullsha"
echo "$sha1 +$action $prefix $fullsha"
fi
fi
esac
Expand All @@ -714,7 +728,7 @@ rearrange_squash () {
esac
printf '%s\n' "$pick $sha1 $message"
used="$used$sha1 "
while read -r squash action msg_content
while read -r squash action msg_prefix msg_content
do
case " $used" in
*" $squash "*) continue ;;
Expand All @@ -730,7 +744,8 @@ rearrange_squash () {
case "$message" in "$msg_content"*) emit=1;; esac ;;
esac
if test $emit = 1; then
printf '%s\n' "$action $squash $action! $msg_content"
real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
printf '%s\n' "$action $squash ${real_prefix}$msg_content"
used="$used$squash "
fi
done <"$1.sq"
Expand Down
14 changes: 14 additions & 0 deletions t/lib-rebase.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ EOF
chmod a+x fake-editor.sh
}

# After set_cat_todo_editor, rebase -i will write the todo list (ignoring
# blank lines and comments) to stdout, and exit failure (so you should run
# it with test_must_fail). This can be used to verify the expected user
# experience, for todo list changes that do not affect the outcome of
# rebase; or as an extra check in addition to checking the outcome.

set_cat_todo_editor () {
write_script fake-editor.sh <<-\EOF
grep "^[^#]" "$1"
exit 1
EOF
test_set_editor "$(pwd)/fake-editor.sh"
}

# checks that the revisions in "$2" represent a linear range with the
# subjects in "$1"
test_linear_range () {
Expand Down
57 changes: 57 additions & 0 deletions t/t3415-rebase-autosquash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ test_description='auto squash'

. ./test-lib.sh

. "$TEST_DIRECTORY"/lib-rebase.sh

test_expect_success setup '
echo 0 >file0 &&
git add . &&
Expand Down Expand Up @@ -193,4 +195,59 @@ test_expect_success 'use commit --squash' '
test_auto_commit_flags squash 2
'

test_auto_fixup_fixup () {
git reset --hard base &&
echo 1 >file1 &&
git add -u &&
test_tick &&
git commit -m "$1! first" &&
echo 2 >file1 &&
git add -u &&
test_tick &&
git commit -m "$1! $2! first" &&
git tag "final-$1-$2" &&
test_tick &&
(
set_cat_todo_editor &&
test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
cat >expected <<-EOF &&
pick $(git rev-parse --short HEAD^^^) first commit
$1 $(git rev-parse --short HEAD^) $1! first
$1 $(git rev-parse --short HEAD) $1! $2! first
pick $(git rev-parse --short HEAD^^) second commit
EOF
test_cmp expected actual
) &&
git rebase --autosquash -i HEAD^^^^ &&
git log --oneline >actual &&
test_line_count = 3 actual
git diff --exit-code "final-$1-$2" &&
test 2 = "$(git cat-file blob HEAD^:file1)" &&
if test "$1" = "fixup"
then
test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
elif test "$1" = "squash"
then
test 3 = $(git cat-file commit HEAD^ | grep first | wc -l)
else
false
fi
}

test_expect_success 'fixup! fixup!' '
test_auto_fixup_fixup fixup fixup
'

test_expect_success 'fixup! squash!' '
test_auto_fixup_fixup fixup squash
'

test_expect_success 'squash! squash!' '
test_auto_fixup_fixup squash squash
'

test_expect_success 'squash! fixup!' '
test_auto_fixup_fixup squash fixup
'

test_done

0 comments on commit 22c5b13

Please sign in to comment.