Skip to content

Commit cc6b41c

Browse files
committed
Merge branch 'mh/rebase-fixup' (early part)
* 'mh/rebase-fixup' (early part): rebase-i: Ignore comments and blank lines in peek_next_command lib-rebase: Allow comments and blank lines to be added to the rebase script lib-rebase: Provide clearer debugging info about what the editor did Add a command "fixup" to rebase --interactive t3404: Use test_commit to set up test repository
2 parents 533e8af + 234b3da commit cc6b41c

File tree

4 files changed

+137
-68
lines changed

4 files changed

+137
-68
lines changed

Documentation/git-rebase.txt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,12 @@ If you just want to edit the commit message for a commit, replace the
382382
command "pick" with the command "reword".
383383

384384
If you want to fold two or more commits into one, replace the command
385-
"pick" with "squash" for the second and subsequent commit. If the
386-
commits had different authors, it will attribute the squashed commit to
387-
the author of the first commit.
385+
"pick" for the second and subsequent commits with "squash" or "fixup".
386+
If the commits had different authors, the folded commit will be
387+
attributed to the author of the first commit. The suggested commit
388+
message for the folded commit is the concatenation of the commit
389+
messages of the first commit and of those with the "squash" command,
390+
but omits the commit messages of commits with the "fixup" command.
388391

389392
'git-rebase' will stop when "pick" has been replaced with "edit" or
390393
when a command fails due to merge errors. When you are done editing
@@ -512,8 +515,8 @@ Easy case: The changes are literally the same.::
512515
Hard case: The changes are not the same.::
513516

514517
This happens if the 'subsystem' rebase had conflicts, or used
515-
`\--interactive` to omit, edit, or squash commits; or if the
516-
upstream used one of `commit \--amend`, `reset`, or
518+
`\--interactive` to omit, edit, squash, or fixup commits; or
519+
if the upstream used one of `commit \--amend`, `reset`, or
517520
`filter-branch`.
518521

519522

git-rebase--interactive.sh

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,10 @@ nth_string () {
302302

303303
make_squash_message () {
304304
if test -f "$SQUASH_MSG"; then
305-
COUNT=$(($(sed -n "s/^# This is [^0-9]*\([1-9][0-9]*\).*/\1/p" \
305+
# We want to be careful about matching only the commit
306+
# message comment lines generated by this function.
307+
# "[snrt][tdh]" matches the nth_string endings.
308+
COUNT=$(($(sed -n "s/^# Th[^0-9]*\([1-9][0-9]*\)[snrt][tdh] commit message.*:/\1/p" \
306309
< "$SQUASH_MSG" | sed -ne '$p')+1))
307310
echo "# This is a combination of $COUNT commits."
308311
sed -e 1d -e '2,/^./{
@@ -315,10 +318,23 @@ make_squash_message () {
315318
echo
316319
git cat-file commit HEAD | sed -e '1,/^$/d'
317320
fi
318-
echo
319-
echo "# This is the $(nth_string $COUNT) commit message:"
320-
echo
321-
git cat-file commit $1 | sed -e '1,/^$/d'
321+
case $1 in
322+
squash)
323+
echo
324+
echo "# This is the $(nth_string $COUNT) commit message:"
325+
echo
326+
git cat-file commit $2 | sed -e '1,/^$/d'
327+
;;
328+
fixup)
329+
echo
330+
echo "# The $(nth_string $COUNT) commit message will be skipped:"
331+
echo
332+
# Comment the lines of the commit message out using
333+
# "# " rather than "# " to make them less likely to
334+
# confuse the sed regexp above.
335+
git cat-file commit $2 | sed -e '1,/^$/d' -e 's/^/# /'
336+
;;
337+
esac
322338
}
323339

324340
peek_next_command () {
@@ -367,20 +383,28 @@ do_next () {
367383
warn
368384
exit 0
369385
;;
370-
squash|s)
371-
comment_for_reflog squash
386+
squash|s|fixup|f)
387+
case "$command" in
388+
squash|s)
389+
squash_style=squash
390+
;;
391+
fixup|f)
392+
squash_style=fixup
393+
;;
394+
esac
395+
comment_for_reflog $squash_style
372396

373397
test -f "$DONE" && has_action "$DONE" ||
374-
die "Cannot 'squash' without a previous commit"
398+
die "Cannot '$squash_style' without a previous commit"
375399

376400
mark_action_done
377-
make_squash_message $sha1 > "$MSG"
401+
make_squash_message $squash_style $sha1 > "$MSG"
378402
failed=f
379403
author_script=$(get_author_ident_from_commit HEAD)
380404
output git reset --soft HEAD^
381405
pick_one -n $sha1 || failed=t
382406
case "$(peek_next_command)" in
383-
squash|s)
407+
squash|s|fixup|f)
384408
USE_OUTPUT=output
385409
MSG_OPT=-F
386410
EDIT_OR_FILE="$MSG"
@@ -787,6 +811,7 @@ first and then run 'git rebase --continue' again."
787811
# r, reword = use commit, but edit the commit message
788812
# e, edit = use commit, but stop for amending
789813
# s, squash = use commit, but meld into previous commit
814+
# f, fixup = like "squash", but discard this commit's log message
790815
#
791816
# If you remove a line here THAT COMMIT WILL BE LOST.
792817
# However, if you remove everything, the rebase will be aborted.

t/lib-rebase.sh

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
# - override the commit message with $FAKE_COMMIT_MESSAGE,
66
# - amend the commit message with $FAKE_COMMIT_AMEND
77
# - check that non-commit messages have a certain line count with $EXPECT_COUNT
8-
# - rewrite a rebase -i script with $FAKE_LINES in the form
8+
# - rewrite a rebase -i script as directed by $FAKE_LINES.
9+
# $FAKE_LINES consists of a sequence of words separated by spaces.
10+
# The following word combinations are possible:
911
#
10-
# "[<lineno1>] [<lineno2>]..."
12+
# "<lineno>" -- add a "pick" line with the SHA1 taken from the
13+
# specified line.
1114
#
12-
# If a line number is prefixed with "squash", "edit", or "reword", the
13-
# respective line's command will be replaced with the specified one.
15+
# "<cmd> <lineno>" -- add a line with the specified command
16+
# ("squash", "fixup", "edit", or "reword") and the SHA1 taken
17+
# from the specified line.
18+
#
19+
# "#" -- Add a comment line.
20+
#
21+
# ">" -- Add a blank line.
1422

1523
set_fake_editor () {
1624
echo "#!$SHELL_PATH" >fake-editor.sh
@@ -28,19 +36,24 @@ test -z "$EXPECT_COUNT" ||
2836
test -z "$FAKE_LINES" && exit
2937
grep -v '^#' < "$1" > "$1".tmp
3038
rm -f "$1"
39+
echo 'rebase -i script before editing:'
3140
cat "$1".tmp
3241
action=pick
3342
for line in $FAKE_LINES; do
3443
case $line in
35-
squash|edit|reword)
44+
squash|fixup|edit|reword)
3645
action="$line";;
46+
"#")
47+
echo '# comment' >> "$1";;
48+
">")
49+
echo >> "$1";;
3750
*)
38-
echo sed -n "${line}s/^pick/$action/p"
39-
sed -n "${line}p" < "$1".tmp
4051
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
4152
action=pick;;
4253
esac
4354
done
55+
echo 'rebase -i script after editing:'
56+
cat "$1"
4457
EOF
4558

4659
test_set_editor "$(pwd)/fake-editor.sh"

t/t3404-rebase-interactive.sh

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,53 +16,26 @@ set_fake_editor
1616

1717
# set up two branches like this:
1818
#
19-
# A - B - C - D - E
19+
# A - B - C - D - E (master)
2020
# \
21-
# F - G - H
21+
# F - G - H (branch1)
2222
# \
23-
# I
23+
# I (branch2)
2424
#
25-
# where B, D and G touch the same file.
25+
# where A, B, D and G touch the same file.
2626

2727
test_expect_success 'setup' '
28-
: > file1 &&
29-
git add file1 &&
30-
test_tick &&
31-
git commit -m A &&
32-
git tag A &&
33-
echo 1 > file1 &&
34-
test_tick &&
35-
git commit -m B file1 &&
36-
: > file2 &&
37-
git add file2 &&
38-
test_tick &&
39-
git commit -m C &&
40-
echo 2 > file1 &&
41-
test_tick &&
42-
git commit -m D file1 &&
43-
: > file3 &&
44-
git add file3 &&
45-
test_tick &&
46-
git commit -m E &&
28+
test_commit A file1 &&
29+
test_commit B file1 &&
30+
test_commit C file2 &&
31+
test_commit D file1 &&
32+
test_commit E file3 &&
4733
git checkout -b branch1 A &&
48-
: > file4 &&
49-
git add file4 &&
50-
test_tick &&
51-
git commit -m F &&
52-
git tag F &&
53-
echo 3 > file1 &&
54-
test_tick &&
55-
git commit -m G file1 &&
56-
: > file5 &&
57-
git add file5 &&
58-
test_tick &&
59-
git commit -m H &&
34+
test_commit F file4 &&
35+
test_commit G file1 &&
36+
test_commit H file5 &&
6037
git checkout -b branch2 F &&
61-
: > file6 &&
62-
git add file6 &&
63-
test_tick &&
64-
git commit -m I &&
65-
git tag I
38+
test_commit I file6
6639
'
6740

6841
test_expect_success 'no changes are a nop' '
@@ -111,19 +84,20 @@ test_expect_success 'exchange two commits' '
11184

11285
cat > expect << EOF
11386
diff --git a/file1 b/file1
114-
index e69de29..00750ed 100644
87+
index f70f10e..fd79235 100644
11588
--- a/file1
11689
+++ b/file1
117-
@@ -0,0 +1 @@
118-
+3
90+
@@ -1 +1 @@
91+
-A
92+
+G
11993
EOF
12094

12195
cat > expect2 << EOF
12296
<<<<<<< HEAD
123-
2
97+
D
12498
=======
125-
3
126-
>>>>>>> b7ca976... G
99+
G
100+
>>>>>>> 91201e5... G
127101
EOF
128102

129103
test_expect_success 'stop on conflicting pick' '
@@ -261,6 +235,60 @@ test_expect_success 'multi-squash only fires up editor once' '
261235
test 1 = $(git show | grep ONCE | wc -l)
262236
'
263237

238+
test_expect_success 'multi-fixup only fires up editor once' '
239+
git checkout -b multi-fixup E &&
240+
base=$(git rev-parse HEAD~4) &&
241+
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
242+
git rebase -i $base &&
243+
test $base = $(git rev-parse HEAD^) &&
244+
test 1 = $(git show | grep ONCE | wc -l) &&
245+
git checkout to-be-rebased &&
246+
git branch -D multi-fixup
247+
'
248+
249+
cat > expect-squash-fixup << EOF
250+
B
251+
252+
D
253+
254+
ONCE
255+
EOF
256+
257+
test_expect_success 'squash and fixup generate correct log messages' '
258+
git checkout -b squash-fixup E &&
259+
base=$(git rev-parse HEAD~4) &&
260+
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
261+
git rebase -i $base &&
262+
git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
263+
test_cmp expect-squash-fixup actual-squash-fixup &&
264+
git checkout to-be-rebased &&
265+
git branch -D squash-fixup
266+
'
267+
268+
test_expect_success 'squash ignores comments' '
269+
git checkout -b skip-comments E &&
270+
base=$(git rev-parse HEAD~4) &&
271+
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
272+
EXPECT_HEADER_COUNT=4 \
273+
git rebase -i $base &&
274+
test $base = $(git rev-parse HEAD^) &&
275+
test 1 = $(git show | grep ONCE | wc -l) &&
276+
git checkout to-be-rebased &&
277+
git branch -D skip-comments
278+
'
279+
280+
test_expect_success 'squash ignores blank lines' '
281+
git checkout -b skip-blank-lines E &&
282+
base=$(git rev-parse HEAD~4) &&
283+
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
284+
EXPECT_HEADER_COUNT=4 \
285+
git rebase -i $base &&
286+
test $base = $(git rev-parse HEAD^) &&
287+
test 1 = $(git show | grep ONCE | wc -l) &&
288+
git checkout to-be-rebased &&
289+
git branch -D skip-blank-lines
290+
'
291+
264292
test_expect_success 'squash works as expected' '
265293
for n in one two three four
266294
do

0 commit comments

Comments
 (0)