rebase -i --autosquash: auto-squash commits

Teach a new option, --autosquash, to the interactive rebase.
When the commit log message begins with "!fixup ...", and there
is a commit whose title begins with the same ..., automatically
modify the todo list of rebase -i so that the commit marked for
squashing come right after the commit to be modified, and change
the action of the moved commit from pick to squash.

Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nanako Shiraishi 2009-12-08 12:13:14 +09:00 committed by Junio C Hamano
parent 0205e72f08
commit f59baa502f
3 changed files with 120 additions and 0 deletions

View file

@ -308,6 +308,16 @@ which makes little sense.
root commits will be rewritten to have <newbase> as parent
instead.
--autosquash::
When the commit log message begins with "squash! ..." (or
"fixup! ..."), and there is a commit whose title begins with
the same ..., automatically modify the todo list of rebase -i
so that the commit marked for quashing come right after the
commit to be modified, and change the action of the moved
commit from `pick` to `squash` (or `fixup`).
+
This option is only valid when '--interactive' option is used.
include::merge-strategies.txt[]
NOTES

View file

@ -28,6 +28,7 @@ abort abort rebasing process and restore original branch
skip skip current patch and continue rebasing process
no-verify override pre-rebase hook from stopping the operation
root rebase all reachable commmits up to the root(s)
autosquash move commits that begin with squash!/fixup! under -i
"
. git-sh-setup
@ -46,6 +47,7 @@ ONTO=
VERBOSE=
OK_TO_SKIP_PRE_REBASE=
REBASE_ROOT=
AUTOSQUASH=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
@ -519,6 +521,37 @@ get_saved_options () {
test -f "$DOTEST"/rebase-root && REBASE_ROOT=t
}
# Rearrange the todo list that has both "pick sha1 msg" and
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
# "fixup"/"squash".
rearrange_squash () {
sed -n -e 's/^pick \([0-9a-f]*\) \(squash\)! /\1 \2 /p' \
-e 's/^pick \([0-9a-f]*\) \(fixup\)! /\1 \2 /p' \
"$1" >"$1.sq"
test -s "$1.sq" || return
used=
while read pick sha1 message
do
case " $used" in
*" $sha1 "*) continue ;;
esac
echo "$pick $sha1 $message"
while read squash action msg
do
case "$message" in
"$msg"*)
echo "$action $squash $action! $msg"
used="$used$squash "
;;
esac
done <"$1.sq"
done >"$1.rearranged" <"$1"
cat "$1.rearranged" >"$1"
rm -f "$1.sq" "$1.rearranged"
}
while test $# != 0
do
case "$1" in
@ -624,6 +657,9 @@ first and then run 'git rebase --continue' again."
--root)
REBASE_ROOT=t
;;
--autosquash)
AUTOSQUASH=t
;;
--onto)
shift
ONTO=$(git rev-parse --verify "$1") ||
@ -783,6 +819,7 @@ first and then run 'git rebase --continue' again."
fi
test -s "$TODO" || echo noop >> "$TODO"
test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
cat >> "$TODO" << EOF
# Rebase $SHORTREVISIONS onto $SHORTONTO

73
t/t3415-rebase-autosquash.sh Executable file
View file

@ -0,0 +1,73 @@
#!/bin/sh
test_description='auto squash'
. ./test-lib.sh
test_expect_success setup '
echo 0 >file0 &&
git add . &&
test_tick &&
git commit -m "initial commit" &&
echo 0 >file1 &&
echo 2 >file2 &&
git add . &&
test_tick &&
git commit -m "first commit" &&
echo 3 >file3 &&
git add . &&
test_tick &&
git commit -m "second commit" &&
git tag base
'
test_expect_success 'auto fixup' '
git reset --hard base &&
echo 1 >file1 &&
git add -u &&
test_tick &&
git commit -m "fixup! first"
git tag final-fixup &&
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
test 3 = $(wc -l <actual) &&
git diff --exit-code final-fixup &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
'
test_expect_success 'auto squash' '
git reset --hard base &&
echo 1 >file1 &&
git add -u &&
test_tick &&
git commit -m "squash! first"
git tag final-squash &&
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
test 3 = $(wc -l <actual) &&
git diff --exit-code final-squash &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 2 = $(git cat-file commit HEAD^ | grep first | wc -l)
'
test_expect_success 'misspelled auto squash' '
git reset --hard base &&
echo 1 >file1 &&
git add -u &&
test_tick &&
git commit -m "squash! forst"
git tag final-missquash &&
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
test 4 = $(wc -l <actual) &&
git diff --exit-code final-missquash &&
test 0 = $(git rev-list final-missquash...HEAD | wc -l)
'
test_done