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
This commit is contained in:
commit
eb3a4fc149
@ -389,7 +389,9 @@ squash/fixup series.
|
|||||||
the same ..., automatically modify the todo list of rebase -i
|
the same ..., automatically modify the todo list of rebase -i
|
||||||
so that the commit marked for squashing comes right after the
|
so that the commit marked for squashing comes right after the
|
||||||
commit to be modified, and change the action of the moved
|
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.
|
This option is only valid when the '--interactive' option is used.
|
||||||
+
|
+
|
||||||
|
@ -689,8 +689,22 @@ rearrange_squash () {
|
|||||||
case "$message" in
|
case "$message" in
|
||||||
"squash! "*|"fixup! "*)
|
"squash! "*|"fixup! "*)
|
||||||
action="${message%%!*}"
|
action="${message%%!*}"
|
||||||
rest="${message#*! }"
|
rest=$message
|
||||||
echo "$sha1 $action $rest"
|
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
|
# 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
|
# emit a second copy. This allows us to match on both message
|
||||||
# and on sha1 prefix
|
# and on sha1 prefix
|
||||||
@ -699,7 +713,7 @@ rearrange_squash () {
|
|||||||
if test -n "$fullsha"; then
|
if test -n "$fullsha"; then
|
||||||
# prefix the action to uniquely identify this line as
|
# prefix the action to uniquely identify this line as
|
||||||
# intended for full sha1 match
|
# intended for full sha1 match
|
||||||
echo "$sha1 +$action $fullsha"
|
echo "$sha1 +$action $prefix $fullsha"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
esac
|
esac
|
||||||
@ -714,7 +728,7 @@ rearrange_squash () {
|
|||||||
esac
|
esac
|
||||||
printf '%s\n' "$pick $sha1 $message"
|
printf '%s\n' "$pick $sha1 $message"
|
||||||
used="$used$sha1 "
|
used="$used$sha1 "
|
||||||
while read -r squash action msg_content
|
while read -r squash action msg_prefix msg_content
|
||||||
do
|
do
|
||||||
case " $used" in
|
case " $used" in
|
||||||
*" $squash "*) continue ;;
|
*" $squash "*) continue ;;
|
||||||
@ -730,7 +744,8 @@ rearrange_squash () {
|
|||||||
case "$message" in "$msg_content"*) emit=1;; esac ;;
|
case "$message" in "$msg_content"*) emit=1;; esac ;;
|
||||||
esac
|
esac
|
||||||
if test $emit = 1; then
|
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 "
|
used="$used$squash "
|
||||||
fi
|
fi
|
||||||
done <"$1.sq"
|
done <"$1.sq"
|
||||||
|
@ -22,48 +22,60 @@
|
|||||||
# ">" -- Add a blank line.
|
# ">" -- Add a blank line.
|
||||||
|
|
||||||
set_fake_editor () {
|
set_fake_editor () {
|
||||||
echo "#!$SHELL_PATH" >fake-editor.sh
|
write_script fake-editor.sh <<-\EOF
|
||||||
cat >> fake-editor.sh <<\EOF
|
case "$1" in
|
||||||
case "$1" in
|
*/COMMIT_EDITMSG)
|
||||||
*/COMMIT_EDITMSG)
|
test -z "$EXPECT_HEADER_COUNT" ||
|
||||||
test -z "$EXPECT_HEADER_COUNT" ||
|
test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
|
||||||
test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
|
exit
|
||||||
|
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
|
||||||
|
test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
|
||||||
exit
|
exit
|
||||||
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
|
;;
|
||||||
test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
test -z "$EXPECT_COUNT" ||
|
|
||||||
test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
|
|
||||||
exit
|
|
||||||
test -z "$FAKE_LINES" && exit
|
|
||||||
grep -v '^#' < "$1" > "$1".tmp
|
|
||||||
rm -f "$1"
|
|
||||||
echo 'rebase -i script before editing:'
|
|
||||||
cat "$1".tmp
|
|
||||||
action=pick
|
|
||||||
for line in $FAKE_LINES; do
|
|
||||||
case $line in
|
|
||||||
squash|fixup|edit|reword)
|
|
||||||
action="$line";;
|
|
||||||
exec*)
|
|
||||||
echo "$line" | sed 's/_/ /g' >> "$1";;
|
|
||||||
"#")
|
|
||||||
echo '# comment' >> "$1";;
|
|
||||||
">")
|
|
||||||
echo >> "$1";;
|
|
||||||
*)
|
|
||||||
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
|
|
||||||
action=pick;;
|
|
||||||
esac
|
esac
|
||||||
done
|
test -z "$EXPECT_COUNT" ||
|
||||||
echo 'rebase -i script after editing:'
|
test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
|
||||||
cat "$1"
|
exit
|
||||||
EOF
|
test -z "$FAKE_LINES" && exit
|
||||||
|
grep -v '^#' < "$1" > "$1".tmp
|
||||||
|
rm -f "$1"
|
||||||
|
echo 'rebase -i script before editing:'
|
||||||
|
cat "$1".tmp
|
||||||
|
action=pick
|
||||||
|
for line in $FAKE_LINES; do
|
||||||
|
case $line in
|
||||||
|
squash|fixup|edit|reword)
|
||||||
|
action="$line";;
|
||||||
|
exec*)
|
||||||
|
echo "$line" | sed 's/_/ /g' >> "$1";;
|
||||||
|
"#")
|
||||||
|
echo '# comment' >> "$1";;
|
||||||
|
">")
|
||||||
|
echo >> "$1";;
|
||||||
|
*)
|
||||||
|
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
|
||||||
|
action=pick;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo 'rebase -i script after editing:'
|
||||||
|
cat "$1"
|
||||||
|
EOF
|
||||||
|
|
||||||
test_set_editor "$(pwd)/fake-editor.sh"
|
test_set_editor "$(pwd)/fake-editor.sh"
|
||||||
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
|
# checks that the revisions in "$2" represent a linear range with the
|
||||||
|
@ -4,6 +4,8 @@ test_description='auto squash'
|
|||||||
|
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
. "$TEST_DIRECTORY"/lib-rebase.sh
|
||||||
|
|
||||||
test_expect_success setup '
|
test_expect_success setup '
|
||||||
echo 0 >file0 &&
|
echo 0 >file0 &&
|
||||||
git add . &&
|
git add . &&
|
||||||
@ -193,4 +195,59 @@ test_expect_success 'use commit --squash' '
|
|||||||
test_auto_commit_flags squash 2
|
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
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user