Merge branch 'mh/rebase-fixup' (early part)
authorJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:41:48 +0000 (14:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:41:48 +0000 (14:41 -0800)
* '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

Documentation/git-rebase.txt
git-rebase--interactive.sh
t/lib-rebase.sh
t/t3404-rebase-interactive.sh
index ca5e1e8653be7a1d2b0911ec572ff0a85300ebb9..9b648ece6e6fbd1371cf8802a9a312e2e4473542 100644 (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`.
 
 
index 1560e84bd5d06345dd3976ed55c1cfb8af51b41e..d0b59c96c4cba1cd645f834818b5d613ca059ca3 100755 (executable)
@@ -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.
index 62f452c8ea2c2718fff300d39531fbc4c2e6a44a..0db8250c5817a822021af4ceda1780ebddeaa553 100644 (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"
index 3a37793c0ddbdab8820dba033521d5e113bc33ac..d9382e41d31c6f469095eb35e449a46fd2cf3eb5 100755 (executable)
@@ -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