Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit eb3a4fc

Browse files
committed
Merge branch 'ap/rebase-multiple-fixups'
Having multiple "fixup!" on a line in the rebase instruction sheet did not work very well with "git rebase -i --autosquash". * ap/rebase-multiple-fixups: lib-rebase: style: use write_script, <<-\EOF rebase -i: handle fixup! fixup! in --autosquash
2 parents 4b9a0de + a495281 commit eb3a4fc

File tree

4 files changed

+130
-44
lines changed

4 files changed

+130
-44
lines changed

Documentation/git-rebase.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,9 @@ squash/fixup series.
389389
the same ..., automatically modify the todo list of rebase -i
390390
so that the commit marked for squashing comes right after the
391391
commit to be modified, and change the action of the moved
392-
commit from `pick` to `squash` (or `fixup`).
392+
commit from `pick` to `squash` (or `fixup`). Ignores subsequent
393+
"fixup! " or "squash! " after the first, in case you referred to an
394+
earlier fixup/squash with `git commit --fixup/--squash`.
393395
+
394396
This option is only valid when the '--interactive' option is used.
395397
+

git-rebase--interactive.sh

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,22 @@ rearrange_squash () {
689689
case "$message" in
690690
"squash! "*|"fixup! "*)
691691
action="${message%%!*}"
692-
rest="${message#*! }"
693-
echo "$sha1 $action $rest"
692+
rest=$message
693+
prefix=
694+
# skip all squash! or fixup! (but save for later)
695+
while :
696+
do
697+
case "$rest" in
698+
"squash! "*|"fixup! "*)
699+
prefix="$prefix${rest%%!*},"
700+
rest="${rest#*! }"
701+
;;
702+
*)
703+
break
704+
;;
705+
esac
706+
done
707+
echo "$sha1 $action $prefix $rest"
694708
# if it's a single word, try to resolve to a full sha1 and
695709
# emit a second copy. This allows us to match on both message
696710
# and on sha1 prefix
@@ -699,7 +713,7 @@ rearrange_squash () {
699713
if test -n "$fullsha"; then
700714
# prefix the action to uniquely identify this line as
701715
# intended for full sha1 match
702-
echo "$sha1 +$action $fullsha"
716+
echo "$sha1 +$action $prefix $fullsha"
703717
fi
704718
fi
705719
esac
@@ -714,7 +728,7 @@ rearrange_squash () {
714728
esac
715729
printf '%s\n' "$pick $sha1 $message"
716730
used="$used$sha1 "
717-
while read -r squash action msg_content
731+
while read -r squash action msg_prefix msg_content
718732
do
719733
case " $used" in
720734
*" $squash "*) continue ;;
@@ -730,7 +744,8 @@ rearrange_squash () {
730744
case "$message" in "$msg_content"*) emit=1;; esac ;;
731745
esac
732746
if test $emit = 1; then
733-
printf '%s\n' "$action $squash $action! $msg_content"
747+
real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
748+
printf '%s\n' "$action $squash ${real_prefix}$msg_content"
734749
used="$used$squash "
735750
fi
736751
done <"$1.sq"

t/lib-rebase.sh

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,48 +22,60 @@
2222
# ">" -- Add a blank line.
2323

2424
set_fake_editor () {
25-
echo "#!$SHELL_PATH" >fake-editor.sh
26-
cat >> fake-editor.sh <<\EOF
27-
case "$1" in
28-
*/COMMIT_EDITMSG)
29-
test -z "$EXPECT_HEADER_COUNT" ||
30-
test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
25+
write_script fake-editor.sh <<-\EOF
26+
case "$1" in
27+
*/COMMIT_EDITMSG)
28+
test -z "$EXPECT_HEADER_COUNT" ||
29+
test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
30+
exit
31+
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
32+
test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
3133
exit
32-
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
33-
test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
34-
exit
35-
;;
36-
esac
37-
test -z "$EXPECT_COUNT" ||
38-
test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
39-
exit
40-
test -z "$FAKE_LINES" && exit
41-
grep -v '^#' < "$1" > "$1".tmp
42-
rm -f "$1"
43-
echo 'rebase -i script before editing:'
44-
cat "$1".tmp
45-
action=pick
46-
for line in $FAKE_LINES; do
47-
case $line in
48-
squash|fixup|edit|reword)
49-
action="$line";;
50-
exec*)
51-
echo "$line" | sed 's/_/ /g' >> "$1";;
52-
"#")
53-
echo '# comment' >> "$1";;
54-
">")
55-
echo >> "$1";;
56-
*)
57-
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
58-
action=pick;;
34+
;;
5935
esac
60-
done
61-
echo 'rebase -i script after editing:'
62-
cat "$1"
63-
EOF
36+
test -z "$EXPECT_COUNT" ||
37+
test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
38+
exit
39+
test -z "$FAKE_LINES" && exit
40+
grep -v '^#' < "$1" > "$1".tmp
41+
rm -f "$1"
42+
echo 'rebase -i script before editing:'
43+
cat "$1".tmp
44+
action=pick
45+
for line in $FAKE_LINES; do
46+
case $line in
47+
squash|fixup|edit|reword)
48+
action="$line";;
49+
exec*)
50+
echo "$line" | sed 's/_/ /g' >> "$1";;
51+
"#")
52+
echo '# comment' >> "$1";;
53+
">")
54+
echo >> "$1";;
55+
*)
56+
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
57+
action=pick;;
58+
esac
59+
done
60+
echo 'rebase -i script after editing:'
61+
cat "$1"
62+
EOF
63+
64+
test_set_editor "$(pwd)/fake-editor.sh"
65+
}
66+
67+
# After set_cat_todo_editor, rebase -i will write the todo list (ignoring
68+
# blank lines and comments) to stdout, and exit failure (so you should run
69+
# it with test_must_fail). This can be used to verify the expected user
70+
# experience, for todo list changes that do not affect the outcome of
71+
# rebase; or as an extra check in addition to checking the outcome.
6472

73+
set_cat_todo_editor () {
74+
write_script fake-editor.sh <<-\EOF
75+
grep "^[^#]" "$1"
76+
exit 1
77+
EOF
6578
test_set_editor "$(pwd)/fake-editor.sh"
66-
chmod a+x fake-editor.sh
6779
}
6880

6981
# checks that the revisions in "$2" represent a linear range with the

t/t3415-rebase-autosquash.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ test_description='auto squash'
44

55
. ./test-lib.sh
66

7+
. "$TEST_DIRECTORY"/lib-rebase.sh
8+
79
test_expect_success setup '
810
echo 0 >file0 &&
911
git add . &&
@@ -193,4 +195,59 @@ test_expect_success 'use commit --squash' '
193195
test_auto_commit_flags squash 2
194196
'
195197

198+
test_auto_fixup_fixup () {
199+
git reset --hard base &&
200+
echo 1 >file1 &&
201+
git add -u &&
202+
test_tick &&
203+
git commit -m "$1! first" &&
204+
echo 2 >file1 &&
205+
git add -u &&
206+
test_tick &&
207+
git commit -m "$1! $2! first" &&
208+
git tag "final-$1-$2" &&
209+
test_tick &&
210+
(
211+
set_cat_todo_editor &&
212+
test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
213+
cat >expected <<-EOF &&
214+
pick $(git rev-parse --short HEAD^^^) first commit
215+
$1 $(git rev-parse --short HEAD^) $1! first
216+
$1 $(git rev-parse --short HEAD) $1! $2! first
217+
pick $(git rev-parse --short HEAD^^) second commit
218+
EOF
219+
test_cmp expected actual
220+
) &&
221+
git rebase --autosquash -i HEAD^^^^ &&
222+
git log --oneline >actual &&
223+
test_line_count = 3 actual
224+
git diff --exit-code "final-$1-$2" &&
225+
test 2 = "$(git cat-file blob HEAD^:file1)" &&
226+
if test "$1" = "fixup"
227+
then
228+
test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
229+
elif test "$1" = "squash"
230+
then
231+
test 3 = $(git cat-file commit HEAD^ | grep first | wc -l)
232+
else
233+
false
234+
fi
235+
}
236+
237+
test_expect_success 'fixup! fixup!' '
238+
test_auto_fixup_fixup fixup fixup
239+
'
240+
241+
test_expect_success 'fixup! squash!' '
242+
test_auto_fixup_fixup fixup squash
243+
'
244+
245+
test_expect_success 'squash! squash!' '
246+
test_auto_fixup_fixup squash squash
247+
'
248+
249+
test_expect_success 'squash! fixup!' '
250+
test_auto_fixup_fixup squash fixup
251+
'
252+
196253
test_done

0 commit comments

Comments
 (0)