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>
Nanako Shiraishi committed
Dec 8, 2009 at 12:13 UTC
f59baa502f49c3f1579a82bc37d2bb3ce9e7b5da
3 files changed
+120
Documentation/git-rebase.txt
+10
@@ -308,6 +308,16 @@ which makes little sense.
308
root commits will be rewritten to have <newbase> as parent
309
instead.
310
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
+
321
include::merge-strategies.txt[]
322
323
NOTES
git-rebase--interactive.sh
+37
@@ -28,6 +28,7 @@ abort abort rebasing process and restore original branch
28
skip skip current patch and continue rebasing process
29
no-verify override pre-rebase hook from stopping the operation
30
root rebase all reachable commmits up to the root(s)
31
+autosquash move commits that begin with squash!/fixup! under -i
32
"
33
34
. git-sh-setup
@@ -46,6 +47,7 @@ ONTO=
47
VERBOSE=
48
OK_TO_SKIP_PRE_REBASE=
49
REBASE_ROOT=
50
+AUTOSQUASH=
51
52
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
53
mark the corrected paths with 'git add <paths>', and
@@ -519,6 +521,37 @@ get_saved_options () {
521
test -f "$DOTEST"/rebase-root && REBASE_ROOT=t
522
}
523
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
+
555
while test $# != 0
556
do
557
case "$1" in
@@ -624,6 +657,9 @@ first and then run 'git rebase --continue' again."
657
--root)
658
REBASE_ROOT=t
659
;;
660
+ --autosquash)
661
+ AUTOSQUASH=t
662
+ ;;
663
--onto)
664
shift
665
ONTO=$(git rev-parse --verify "$1") ||
@@ -783,6 +819,7 @@ first and then run 'git rebase --continue' again."
819
fi
820
821
test -s "$TODO" || echo noop >> "$TODO"
822
+ test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
823
cat >> "$TODO" << EOF
824
825
# Rebase $SHORTREVISIONS onto $SHORTONTO
t/t3415-rebase-autosquash.sh
new
+73
@@ -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