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
This commit is contained in:
Junio C Hamano 2010-01-20 14:41:48 -08:00
commit cc6b41cc7d
4 changed files with 137 additions and 68 deletions

View File

@ -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
@ -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`.

View File

@ -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,/^./{
@ -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 () {
@ -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"
@ -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.

View File

@ -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
@ -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"

View File

@ -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' '
@ -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' '
@ -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