t3404: Set up more of the test repo in the "setup" step
[gitweb.git] / git-rebase--interactive.sh
index d60e059838c3e50e4cdc9ef246d9a45b16c5c7ef..1569a7ad915988cfc14be71eb550debcd134f864 100755 (executable)
@@ -65,6 +65,13 @@ MSG="$DOTEST"/message
 # updated.  It is deleted just before the combined commit is made.
 SQUASH_MSG="$DOTEST"/message-squash
 
+# If the current series of squash/fixups has not yet included a squash
+# command, then this file exists and holds the commit message of the
+# original "pick" commit.  (If the series ends without a "squash"
+# command, then this can be used as the commit message of the combined
+# commit without opening the editor.)
+FIXUP_MSG="$DOTEST"/message-fixup
+
 # $REWRITTEN is the name of a directory containing files for each
 # commit that is reachable by at least one merge base of $HEAD and
 # $UPSTREAM. They are not necessarily rewritten, but their children
@@ -118,6 +125,11 @@ output () {
        esac
 }
 
+# Output the commit message for the specified commit.
+commit_message () {
+       git cat-file commit "$1" | sed "1,/^$/d"
+}
+
 run_pre_rebase_hook () {
        if test -z "$OK_TO_SKIP_PRE_REBASE" &&
           test -x "$GIT_DIR/hooks/pre-rebase"
@@ -178,7 +190,7 @@ make_patch () {
                ;;
        esac > "$DOTEST"/patch
        test -f "$MSG" ||
-               git cat-file commit "$1" | sed "1,/^$/d" > "$MSG"
+               commit_message "$1" > "$MSG"
        test -f "$AUTHOR_SCRIPT" ||
                get_author_ident_from_commit "$1" > "$AUTHOR_SCRIPT"
 }
@@ -198,6 +210,15 @@ has_action () {
        sane_grep '^[^#]' "$1" >/dev/null
 }
 
+# Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
+# GIT_AUTHOR_DATE exported from the current environment.
+do_with_author () {
+       GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
+       GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
+       GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
+       "$@"
+}
+
 pick_one () {
        no_ff=
        case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
@@ -316,14 +337,11 @@ pick_one_preserving_merges () {
                        # redo merge
                        author_script=$(get_author_ident_from_commit $sha1)
                        eval "$author_script"
-                       msg="$(git cat-file commit $sha1 | sed -e '1,/^$/d')"
+                       msg="$(commit_message $sha1)"
                        # No point in merging the first parent, that's HEAD
                        new_parents=${new_parents# $first_parent}
-                       if ! GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
-                               GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
-                               GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
-                               output git merge $STRATEGY -m "$msg" \
-                                       $new_parents
+                       if ! do_with_author output \
+                               git merge $STRATEGY -m "$msg" $new_parents
                        then
                                printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "Error redoing merge $sha1"
@@ -347,36 +365,43 @@ nth_string () {
        esac
 }
 
-make_squash_message () {
+update_squash_messages () {
        if test -f "$SQUASH_MSG"; then
+               mv "$SQUASH_MSG" "$SQUASH_MSG".bak || exit
                COUNT=$(($(sed -n \
                        -e "1s/^# This is a combination of \(.*\) commits\./\1/p" \
-                       -e "q" < "$SQUASH_MSG")+1))
-               echo "# This is a combination of $COUNT commits."
-               sed -e 1d -e '2,/^./{
-                       /^$/d
-               }' <"$SQUASH_MSG"
+                       -e "q" < "$SQUASH_MSG".bak)+1))
+               {
+                       echo "# This is a combination of $COUNT commits."
+                       sed -e 1d -e '2,/^./{
+                               /^$/d
+                       }' <"$SQUASH_MSG".bak
+               } >$SQUASH_MSG
        else
+               commit_message HEAD > "$FIXUP_MSG" || die "Cannot write $FIXUP_MSG"
                COUNT=2
-               echo "# This is a combination of 2 commits."
-               echo "# The first commit's message is:"
-               echo
-               git cat-file commit HEAD | sed -e '1,/^$/d'
+               {
+                       echo "# This is a combination of 2 commits."
+                       echo "# The first commit's message is:"
+                       echo
+                       cat "$FIXUP_MSG"
+               } >$SQUASH_MSG
        fi
        case $1 in
        squash)
+               rm -f "$FIXUP_MSG"
                echo
                echo "# This is the $(nth_string $COUNT) commit message:"
                echo
-               git cat-file commit $2 | sed -e '1,/^$/d'
+               commit_message $2
                ;;
        fixup)
                echo
                echo "# The $(nth_string $COUNT) commit message will be skipped:"
                echo
-               git cat-file commit $2 | sed -e '1,/^$/d' -e 's/^/#     /'
+               commit_message $2 | sed -e 's/^/#       /'
                ;;
-       esac
+       esac >>$SQUASH_MSG
 }
 
 peek_next_command () {
@@ -439,45 +464,61 @@ do_next () {
                        die "Cannot '$squash_style' without a previous commit"
 
                mark_action_done
-               make_squash_message $squash_style $sha1 > "$MSG"
+               update_squash_messages $squash_style $sha1
                failed=f
                author_script=$(get_author_ident_from_commit HEAD)
+               echo "$author_script" > "$AUTHOR_SCRIPT"
+               eval "$author_script"
                output git reset --soft HEAD^
                pick_one -n $sha1 || failed=t
                case "$(peek_next_command)" in
                squash|s|fixup|f)
-                       USE_OUTPUT=output
-                       MSG_OPT=-F
-                       EDIT_OR_FILE="$MSG"
-                       cp "$MSG" "$SQUASH_MSG"
+                       # This is an intermediate commit; its message will only be
+                       # used in case of trouble.  So use the long version:
+                       if test $failed = f
+                       then
+                               do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
+                                       failed=t
+                       fi
+                       if test $failed = t
+                       then
+                               cp "$SQUASH_MSG" "$MSG" || exit
+                               # After any kind of hiccup, prevent committing without
+                               # opening the commit message editor:
+                               rm -f "$FIXUP_MSG"
+                               cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
+                               warn
+                               warn "Could not apply $sha1... $rest"
+                               die_with_patch $sha1 ""
+                       fi
                        ;;
                *)
-                       USE_OUTPUT=
-                       MSG_OPT=
-                       EDIT_OR_FILE=-e
-                       rm -f "$SQUASH_MSG" || exit
-                       cp "$MSG" "$GIT_DIR"/SQUASH_MSG
-                       rm -f "$GIT_DIR"/MERGE_MSG || exit
+                       # This is the final command of this squash/fixup group
+                       if test $failed = f
+                       then
+                               if test -f "$FIXUP_MSG"
+                               then
+                                       do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
+                                               failed=t
+                               else
+                                       cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
+                                       rm -f "$GIT_DIR"/MERGE_MSG
+                                       do_with_author git commit --no-verify -e ||
+                                               failed=t
+                               fi
+                       fi
+                       rm -f "$FIXUP_MSG"
+                       if test $failed = t
+                       then
+                               mv "$SQUASH_MSG" "$MSG" || exit
+                               cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
+                               warn
+                               warn "Could not apply $sha1... $rest"
+                               die_with_patch $sha1 ""
+                       fi
+                       rm -f "$SQUASH_MSG"
                        ;;
                esac
-               echo "$author_script" > "$AUTHOR_SCRIPT"
-               if test $failed = f
-               then
-                       # This is like --amend, but with a different message
-                       eval "$author_script"
-                       GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
-                       GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
-                       GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
-                       $USE_OUTPUT git commit --no-verify \
-                               $MSG_OPT "$EDIT_OR_FILE" || failed=t
-               fi
-               if test $failed = t
-               then
-                       cp "$MSG" "$GIT_DIR"/MERGE_MSG
-                       warn
-                       warn "Could not apply $sha1... $rest"
-                       die_with_patch $sha1 ""
-               fi
                ;;
        *)
                warn "Unknown command: $command $sha1 $rest"
@@ -600,8 +641,7 @@ first and then run 'git rebase --continue' again."
                                git reset --soft HEAD^ ||
                                die "Cannot rewind the HEAD"
                        fi
-                       export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&
-                       git commit --no-verify -F "$MSG" -e || {
+                       do_with_author git commit --no-verify -F "$MSG" -e || {
                                test -n "$amend" && git reset --soft $amend
                                die "Could not commit staged changes."
                        }