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 root commits will be rewritten to have <newbase> as parent
instead. 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[] include::merge-strategies.txt[]
NOTES NOTES

View file

@ -28,6 +28,7 @@ abort abort rebasing process and restore original branch
skip skip current patch and continue rebasing process skip skip current patch and continue rebasing process
no-verify override pre-rebase hook from stopping the operation no-verify override pre-rebase hook from stopping the operation
root rebase all reachable commmits up to the root(s) root rebase all reachable commmits up to the root(s)
autosquash move commits that begin with squash!/fixup! under -i
" "
. git-sh-setup . git-sh-setup
@ -46,6 +47,7 @@ ONTO=
VERBOSE= VERBOSE=
OK_TO_SKIP_PRE_REBASE= OK_TO_SKIP_PRE_REBASE=
REBASE_ROOT= REBASE_ROOT=
AUTOSQUASH=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts, GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and mark the corrected paths with 'git add <paths>', and
@ -519,6 +521,37 @@ get_saved_options () {
test -f "$DOTEST"/rebase-root && REBASE_ROOT=t 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 while test $# != 0
do do
case "$1" in case "$1" in
@ -624,6 +657,9 @@ first and then run 'git rebase --continue' again."
--root) --root)
REBASE_ROOT=t REBASE_ROOT=t
;; ;;
--autosquash)
AUTOSQUASH=t
;;
--onto) --onto)
shift shift
ONTO=$(git rev-parse --verify "$1") || ONTO=$(git rev-parse --verify "$1") ||
@ -783,6 +819,7 @@ first and then run 'git rebase --continue' again."
fi fi
test -s "$TODO" || echo noop >> "$TODO" test -s "$TODO" || echo noop >> "$TODO"
test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
cat >> "$TODO" << EOF cat >> "$TODO" << EOF
# Rebase $SHORTREVISIONS onto $SHORTONTO # 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