Skip to content

Commit

Permalink
Merge branch 'mh/rebase-fixup' (early part)
Browse files Browse the repository at this point in the history
* '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
  • Loading branch information
Junio C Hamano committed Jan 20, 2010
2 parents 533e8af + 234b3da commit cc6b41c
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 68 deletions.
13 changes: 8 additions & 5 deletions Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,12 @@ If you just want to edit the commit message for a commit, replace the
command "pick" with the command "reword".

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

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

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


Expand Down
45 changes: 35 additions & 10 deletions git-rebase--interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,10 @@ nth_string () {

make_squash_message () {
if test -f "$SQUASH_MSG"; then
COUNT=$(($(sed -n "s/^# This is [^0-9]*\([1-9][0-9]*\).*/\1/p" \
# We want to be careful about matching only the commit
# message comment lines generated by this function.
# "[snrt][tdh]" matches the nth_string endings.
COUNT=$(($(sed -n "s/^# Th[^0-9]*\([1-9][0-9]*\)[snrt][tdh] commit message.*:/\1/p" \
< "$SQUASH_MSG" | sed -ne '$p')+1))
echo "# This is a combination of $COUNT commits."
sed -e 1d -e '2,/^./{
Expand All @@ -315,10 +318,23 @@ make_squash_message () {
echo
git cat-file commit HEAD | sed -e '1,/^$/d'
fi
echo
echo "# This is the $(nth_string $COUNT) commit message:"
echo
git cat-file commit $1 | sed -e '1,/^$/d'
case $1 in
squash)
echo
echo "# This is the $(nth_string $COUNT) commit message:"
echo
git cat-file commit $2 | sed -e '1,/^$/d'
;;
fixup)
echo
echo "# The $(nth_string $COUNT) commit message will be skipped:"
echo
# Comment the lines of the commit message out using
# "# " rather than "# " to make them less likely to
# confuse the sed regexp above.
git cat-file commit $2 | sed -e '1,/^$/d' -e 's/^/# /'
;;
esac
}

peek_next_command () {
Expand Down Expand Up @@ -367,20 +383,28 @@ do_next () {
warn
exit 0
;;
squash|s)
comment_for_reflog squash
squash|s|fixup|f)
case "$command" in
squash|s)
squash_style=squash
;;
fixup|f)
squash_style=fixup
;;
esac
comment_for_reflog $squash_style

test -f "$DONE" && has_action "$DONE" ||
die "Cannot 'squash' without a previous commit"
die "Cannot '$squash_style' without a previous commit"

mark_action_done
make_squash_message $sha1 > "$MSG"
make_squash_message $squash_style $sha1 > "$MSG"
failed=f
author_script=$(get_author_ident_from_commit HEAD)
output git reset --soft HEAD^
pick_one -n $sha1 || failed=t
case "$(peek_next_command)" in
squash|s)
squash|s|fixup|f)
USE_OUTPUT=output
MSG_OPT=-F
EDIT_OR_FILE="$MSG"
Expand Down Expand Up @@ -787,6 +811,7 @@ first and then run 'git rebase --continue' again."
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
Expand Down
27 changes: 20 additions & 7 deletions t/lib-rebase.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
# - override the commit message with $FAKE_COMMIT_MESSAGE,
# - amend the commit message with $FAKE_COMMIT_AMEND
# - check that non-commit messages have a certain line count with $EXPECT_COUNT
# - rewrite a rebase -i script with $FAKE_LINES in the form
# - rewrite a rebase -i script as directed by $FAKE_LINES.
# $FAKE_LINES consists of a sequence of words separated by spaces.
# The following word combinations are possible:
#
# "[<lineno1>] [<lineno2>]..."
# "<lineno>" -- add a "pick" line with the SHA1 taken from the
# specified line.
#
# If a line number is prefixed with "squash", "edit", or "reword", the
# respective line's command will be replaced with the specified one.
# "<cmd> <lineno>" -- add a line with the specified command
# ("squash", "fixup", "edit", or "reword") and the SHA1 taken
# from the specified line.
#
# "#" -- Add a comment line.
#
# ">" -- Add a blank line.

set_fake_editor () {
echo "#!$SHELL_PATH" >fake-editor.sh
Expand All @@ -28,19 +36,24 @@ test -z "$EXPECT_COUNT" ||
test -z "$FAKE_LINES" && exit
grep -v '^#' < "$1" > "$1".tmp
rm -f "$1"
echo 'rebase -i script before editing:'
cat "$1".tmp
action=pick
for line in $FAKE_LINES; do
case $line in
squash|edit|reword)
squash|fixup|edit|reword)
action="$line";;
"#")
echo '# comment' >> "$1";;
">")
echo >> "$1";;
*)
echo sed -n "${line}s/^pick/$action/p"
sed -n "${line}p" < "$1".tmp
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
action=pick;;
esac
done
echo 'rebase -i script after editing:'
cat "$1"
EOF

test_set_editor "$(pwd)/fake-editor.sh"
Expand Down
120 changes: 74 additions & 46 deletions t/t3404-rebase-interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,53 +16,26 @@ set_fake_editor

# set up two branches like this:
#
# A - B - C - D - E
# A - B - C - D - E (master)
# \
# F - G - H
# F - G - H (branch1)
# \
# I
# I (branch2)
#
# where B, D and G touch the same file.
# where A, B, D and G touch the same file.

test_expect_success 'setup' '
: > file1 &&
git add file1 &&
test_tick &&
git commit -m A &&
git tag A &&
echo 1 > file1 &&
test_tick &&
git commit -m B file1 &&
: > file2 &&
git add file2 &&
test_tick &&
git commit -m C &&
echo 2 > file1 &&
test_tick &&
git commit -m D file1 &&
: > file3 &&
git add file3 &&
test_tick &&
git commit -m E &&
test_commit A file1 &&
test_commit B file1 &&
test_commit C file2 &&
test_commit D file1 &&
test_commit E file3 &&
git checkout -b branch1 A &&
: > file4 &&
git add file4 &&
test_tick &&
git commit -m F &&
git tag F &&
echo 3 > file1 &&
test_tick &&
git commit -m G file1 &&
: > file5 &&
git add file5 &&
test_tick &&
git commit -m H &&
test_commit F file4 &&
test_commit G file1 &&
test_commit H file5 &&
git checkout -b branch2 F &&
: > file6 &&
git add file6 &&
test_tick &&
git commit -m I &&
git tag I
test_commit I file6
'

test_expect_success 'no changes are a nop' '
Expand Down Expand Up @@ -111,19 +84,20 @@ test_expect_success 'exchange two commits' '

cat > expect << EOF
diff --git a/file1 b/file1
index e69de29..00750ed 100644
index f70f10e..fd79235 100644
--- a/file1
+++ b/file1
@@ -0,0 +1 @@
+3
@@ -1 +1 @@
-A
+G
EOF

cat > expect2 << EOF
<<<<<<< HEAD
2
D
=======
3
>>>>>>> b7ca976... G
G
>>>>>>> 91201e5... G
EOF

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

test_expect_success 'multi-fixup only fires up editor once' '
git checkout -b multi-fixup E &&
base=$(git rev-parse HEAD~4) &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
test 1 = $(git show | grep ONCE | wc -l) &&
git checkout to-be-rebased &&
git branch -D multi-fixup
'

cat > expect-squash-fixup << EOF
B
D
ONCE
EOF

test_expect_success 'squash and fixup generate correct log messages' '
git checkout -b squash-fixup E &&
base=$(git rev-parse HEAD~4) &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
git rebase -i $base &&
git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
test_cmp expect-squash-fixup actual-squash-fixup &&
git checkout to-be-rebased &&
git branch -D squash-fixup
'

test_expect_success 'squash ignores comments' '
git checkout -b skip-comments E &&
base=$(git rev-parse HEAD~4) &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
test 1 = $(git show | grep ONCE | wc -l) &&
git checkout to-be-rebased &&
git branch -D skip-comments
'

test_expect_success 'squash ignores blank lines' '
git checkout -b skip-blank-lines E &&
base=$(git rev-parse HEAD~4) &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
test 1 = $(git show | grep ONCE | wc -l) &&
git checkout to-be-rebased &&
git branch -D skip-blank-lines
'

test_expect_success 'squash works as expected' '
for n in one two three four
do
Expand Down

0 comments on commit cc6b41c

Please sign in to comment.