rebase -i: Use symbolic constant $MSG consistently
[gitweb.git] / git-rebase--interactive.sh
index 27daaa9ded9745b6747dc2995ea344ad038443a5..efd5749973dc156db07a338435263f22fa1d7168 100755 (executable)
@@ -106,8 +106,8 @@ mark_action_done () {
        sed -e 1q < "$TODO" >> "$DONE"
        sed -e 1d < "$TODO" >> "$TODO".new
        mv -f "$TODO".new "$TODO"
-       count=$(grep -c '^[^#]' < "$DONE")
-       total=$(($count+$(grep -c '^[^#]' < "$TODO")))
+       count=$(sane_grep -c '^[^#]' < "$DONE")
+       total=$(($count+$(sane_grep -c '^[^#]' < "$TODO")))
        if test "$last_count" != "$count"
        then
                last_count=$count
@@ -129,8 +129,8 @@ make_patch () {
                echo "Root commit"
                ;;
        esac > "$DOTEST"/patch
-       test -f "$DOTEST"/message ||
-               git cat-file commit "$1" | sed "1,/^$/d" > "$DOTEST"/message
+       test -f "$MSG" ||
+               git cat-file commit "$1" | sed "1,/^$/d" > "$MSG"
        test -f "$DOTEST"/author-script ||
                get_author_ident_from_commit "$1" > "$DOTEST"/author-script
 }
@@ -147,7 +147,7 @@ die_abort () {
 }
 
 has_action () {
-       grep '^[^#]' "$1" >/dev/null
+       sane_grep '^[^#]' "$1" >/dev/null
 }
 
 pick_one () {
@@ -156,7 +156,7 @@ pick_one () {
        output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
        test -d "$REWRITTEN" &&
                pick_one_preserving_merges "$@" && return
-       if test ! -z "$REBASE_ROOT"
+       if test -n "$REBASE_ROOT"
        then
                output git cherry-pick "$@"
                return
@@ -164,11 +164,10 @@ pick_one () {
        parent_sha1=$(git rev-parse --verify $sha1^) ||
                die "Could not get the parent of $sha1"
        current_sha1=$(git rev-parse --verify HEAD)
-       if test "$no_ff$current_sha1" = "$parent_sha1"; then
+       if test -z "$no_ff" -a "$current_sha1" = "$parent_sha1"
+       then
                output git reset --hard $sha1
-               test "a$1" = a-n && output git reset --soft $current_sha1
-               sha1=$(git rev-parse --short $sha1)
-               output warn Fast-forward to $sha1
+               output warn Fast-forward to $(git rev-parse --short $sha1)
        else
                output git cherry-pick "$@"
        fi
@@ -302,7 +301,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,18 +317,31 @@ 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 () {
-       sed -n "1s/ .*$//p" < "$TODO"
+       sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO"
 }
 
 do_next () {
-       rm -f "$DOTEST"/message "$DOTEST"/author-script \
+       rm -f "$MSG" "$DOTEST"/author-script \
                "$DOTEST"/amend || exit
        read command sha1 rest < "$TODO"
        case "$command" in
@@ -367,20 +382,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"
@@ -536,7 +559,7 @@ first and then run 'git rebase --continue' again."
                                die "Cannot rewind the HEAD"
                        fi
                        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&
-                       git commit --no-verify -F "$DOTEST"/message -e || {
+                       git commit --no-verify -F "$MSG" -e || {
                                test -n "$amend" && git reset --soft $amend
                                die "Could not commit staged changes."
                        }
@@ -744,7 +767,7 @@ first and then run 'git rebase --continue' again."
                        git rev-list $REVISIONS |
                        while read rev
                        do
-                               if test -f "$REWRITTEN"/$rev -a "$(grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
+                               if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
                                then
                                        # Use -f2 because if rev-list is telling us this commit is
                                        # not worthwhile, we don't want to track its multiple heads,
@@ -752,7 +775,7 @@ first and then run 'git rebase --continue' again."
                                        # be rebasing on top of it
                                        git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
                                        short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-                                       grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
+                                       sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
                                        rm "$REWRITTEN"/$rev
                                fi
                        done
@@ -768,6 +791,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.