Skip to content

Commit f59baa5

Browse files
Nanako Shiraishigitster
authored andcommitted
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>
1 parent 0205e72 commit f59baa5

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

Documentation/git-rebase.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,16 @@ which makes little sense.
308308
root commits will be rewritten to have <newbase> as parent
309309
instead.
310310

311+
--autosquash::
312+
When the commit log message begins with "squash! ..." (or
313+
"fixup! ..."), and there is a commit whose title begins with
314+
the same ..., automatically modify the todo list of rebase -i
315+
so that the commit marked for quashing come right after the
316+
commit to be modified, and change the action of the moved
317+
commit from `pick` to `squash` (or `fixup`).
318+
+
319+
This option is only valid when '--interactive' option is used.
320+
311321
include::merge-strategies.txt[]
312322

313323
NOTES

git-rebase--interactive.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ abort abort rebasing process and restore original branch
2828
skip skip current patch and continue rebasing process
2929
no-verify override pre-rebase hook from stopping the operation
3030
root rebase all reachable commmits up to the root(s)
31+
autosquash move commits that begin with squash!/fixup! under -i
3132
"
3233

3334
. git-sh-setup
@@ -46,6 +47,7 @@ ONTO=
4647
VERBOSE=
4748
OK_TO_SKIP_PRE_REBASE=
4849
REBASE_ROOT=
50+
AUTOSQUASH=
4951

5052
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
5153
mark the corrected paths with 'git add <paths>', and
@@ -519,6 +521,37 @@ get_saved_options () {
519521
test -f "$DOTEST"/rebase-root && REBASE_ROOT=t
520522
}
521523

524+
# Rearrange the todo list that has both "pick sha1 msg" and
525+
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
526+
# comes immediately after the former, and change "pick" to
527+
# "fixup"/"squash".
528+
rearrange_squash () {
529+
sed -n -e 's/^pick \([0-9a-f]*\) \(squash\)! /\1 \2 /p' \
530+
-e 's/^pick \([0-9a-f]*\) \(fixup\)! /\1 \2 /p' \
531+
"$1" >"$1.sq"
532+
test -s "$1.sq" || return
533+
534+
used=
535+
while read pick sha1 message
536+
do
537+
case " $used" in
538+
*" $sha1 "*) continue ;;
539+
esac
540+
echo "$pick $sha1 $message"
541+
while read squash action msg
542+
do
543+
case "$message" in
544+
"$msg"*)
545+
echo "$action $squash $action! $msg"
546+
used="$used$squash "
547+
;;
548+
esac
549+
done <"$1.sq"
550+
done >"$1.rearranged" <"$1"
551+
cat "$1.rearranged" >"$1"
552+
rm -f "$1.sq" "$1.rearranged"
553+
}
554+
522555
while test $# != 0
523556
do
524557
case "$1" in
@@ -624,6 +657,9 @@ first and then run 'git rebase --continue' again."
624657
--root)
625658
REBASE_ROOT=t
626659
;;
660+
--autosquash)
661+
AUTOSQUASH=t
662+
;;
627663
--onto)
628664
shift
629665
ONTO=$(git rev-parse --verify "$1") ||
@@ -783,6 +819,7 @@ first and then run 'git rebase --continue' again."
783819
fi
784820

785821
test -s "$TODO" || echo noop >> "$TODO"
822+
test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
786823
cat >> "$TODO" << EOF
787824
788825
# Rebase $SHORTREVISIONS onto $SHORTONTO

t/t3415-rebase-autosquash.sh

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/sh
2+
3+
test_description='auto squash'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success setup '
8+
echo 0 >file0 &&
9+
git add . &&
10+
test_tick &&
11+
git commit -m "initial commit" &&
12+
echo 0 >file1 &&
13+
echo 2 >file2 &&
14+
git add . &&
15+
test_tick &&
16+
git commit -m "first commit" &&
17+
echo 3 >file3 &&
18+
git add . &&
19+
test_tick &&
20+
git commit -m "second commit" &&
21+
git tag base
22+
'
23+
24+
test_expect_success 'auto fixup' '
25+
git reset --hard base &&
26+
echo 1 >file1 &&
27+
git add -u &&
28+
test_tick &&
29+
git commit -m "fixup! first"
30+
31+
git tag final-fixup &&
32+
test_tick &&
33+
git rebase --autosquash -i HEAD^^^ &&
34+
git log --oneline >actual &&
35+
test 3 = $(wc -l <actual) &&
36+
git diff --exit-code final-fixup &&
37+
test 1 = "$(git cat-file blob HEAD^:file1)" &&
38+
test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
39+
'
40+
41+
test_expect_success 'auto squash' '
42+
git reset --hard base &&
43+
echo 1 >file1 &&
44+
git add -u &&
45+
test_tick &&
46+
git commit -m "squash! first"
47+
48+
git tag final-squash &&
49+
test_tick &&
50+
git rebase --autosquash -i HEAD^^^ &&
51+
git log --oneline >actual &&
52+
test 3 = $(wc -l <actual) &&
53+
git diff --exit-code final-squash &&
54+
test 1 = "$(git cat-file blob HEAD^:file1)" &&
55+
test 2 = $(git cat-file commit HEAD^ | grep first | wc -l)
56+
'
57+
58+
test_expect_success 'misspelled auto squash' '
59+
git reset --hard base &&
60+
echo 1 >file1 &&
61+
git add -u &&
62+
test_tick &&
63+
git commit -m "squash! forst"
64+
git tag final-missquash &&
65+
test_tick &&
66+
git rebase --autosquash -i HEAD^^^ &&
67+
git log --oneline >actual &&
68+
test 4 = $(wc -l <actual) &&
69+
git diff --exit-code final-missquash &&
70+
test 0 = $(git rev-list final-missquash...HEAD | wc -l)
71+
'
72+
73+
test_done

0 commit comments

Comments
 (0)