send-email: use \E***\Q instead of \*\*\*
[gitweb.git] / git-rebase--interactive.sh
index 436b7f5977c05c347debc12130f822af482c03e3..a27952d9fdfb517f684b7d304831bf74d0ce237b 100755 (executable)
@@ -111,15 +111,16 @@ VERBOSE=
 OK_TO_SKIP_PRE_REBASE=
 REBASE_ROOT=
 AUTOSQUASH=
+test "$(git config --bool rebase.autosquash)" = "true" && AUTOSQUASH=t
 NEVER_FF=
 
-GIT_CHERRY_PICK_HELP="  After resolving the conflicts,
-mark the corrected paths with 'git add <paths>', and
-run 'git rebase --continue'"
+GIT_CHERRY_PICK_HELP="\
+hint: after resolving the conflicts, mark the corrected paths
+hint: with 'git add <paths>' and run 'git rebase --continue'"
 export GIT_CHERRY_PICK_HELP
 
 warn () {
-       echo "$*" >&2
+       printf '%s\n' "$*" >&2
 }
 
 output () {
@@ -263,10 +264,10 @@ pick_one_preserving_merges () {
        then
                if test "$fast_forward" = t
                then
-                       cat "$DOTEST"/current-commit | while read current_commit
+                       while read current_commit
                        do
                                git rev-parse HEAD > "$REWRITTEN"/$current_commit
-                       done
+                       done <"$DOTEST"/current-commit
                        rm "$DOTEST"/current-commit ||
                        die "Cannot write current commit's replacement sha1"
                fi
@@ -440,9 +441,9 @@ record_in_rewritten() {
        echo "$oldsha1" >> "$REWRITTEN_PENDING"
 
        case "$(peek_next_command)" in
-           squash|s|fixup|f)
+       squash|s|fixup|f)
                ;;
-           *)
+       *)
                flush_rewritten_pending
                ;;
        esac
@@ -450,7 +451,7 @@ record_in_rewritten() {
 
 do_next () {
        rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
-       read command sha1 rest < "$TODO"
+       read -r command sha1 rest < "$TODO"
        case "$command" in
        '#'*|''|noop)
                mark_action_done
@@ -537,6 +538,34 @@ do_next () {
                esac
                record_in_rewritten $sha1
                ;;
+       x|"exec")
+               read -r command rest < "$TODO"
+               mark_action_done
+               printf 'Executing: %s\n' "$rest"
+               # "exec" command doesn't take a sha1 in the todo-list.
+               # => can't just use $sha1 here.
+               git rev-parse --verify HEAD > "$DOTEST"/stopped-sha
+               ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution
+               status=$?
+               if test "$status" -ne 0
+               then
+                       warn "Execution failed: $rest"
+                       warn "You can fix the problem, and then run"
+                       warn
+                       warn "  git rebase --continue"
+                       warn
+                       exit "$status"
+               fi
+               # Run in subshell because require_clean_work_tree can die.
+               if ! (require_clean_work_tree)
+               then
+                       warn "Commit or stash your changes, and then run"
+                       warn
+                       warn "  git rebase --continue"
+                       warn
+                       exit 1
+               fi
+               ;;
        *)
                warn "Unknown command: $command $sha1 $rest"
                if git rev-parse --verify -q "$sha1" >/dev/null
@@ -591,22 +620,30 @@ do_rest () {
 # skip picking commits whose parents are unchanged
 skip_unnecessary_picks () {
        fd=3
-       while read command sha1 rest
+       while read -r command rest
        do
                # fd=3 means we skip the command
-               case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in
-               3,pick,"$ONTO"*|3,p,"$ONTO"*)
+               case "$fd,$command" in
+               3,pick|3,p)
                        # pick a commit whose parent is current $ONTO -> skip
-                       ONTO=$sha1
+                       sha1=${rest%% *}
+                       case "$(git rev-parse --verify --quiet "$sha1"^)" in
+                       "$ONTO"*)
+                               ONTO=$sha1
+                               ;;
+                       *)
+                               fd=1
+                               ;;
+                       esac
                        ;;
-               3,#*|3,,*)
+               3,#*|3,)
                        # copy comments
                        ;;
                *)
                        fd=1
                        ;;
                esac
-               echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
+               printf '%s\n' "$command${rest:+ }$rest" >&$fd
        done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
        mv -f "$TODO".new "$TODO" &&
        case "$(peek_next_command)" in
@@ -644,17 +681,17 @@ rearrange_squash () {
        test -s "$1.sq" || return
 
        used=
-       while read pick sha1 message
+       while read -r pick sha1 message
        do
                case " $used" in
                *" $sha1 "*) continue ;;
                esac
-               echo "$pick $sha1 $message"
-               while read squash action msg
+               printf '%s\n' "$pick $sha1 $message"
+               while read -r squash action msg
                do
                        case "$message" in
                        "$msg"*)
-                               echo "$action $squash $action! $msg"
+                               printf '%s\n' "$action $squash $action! $msg"
                                used="$used$squash "
                                ;;
                        esac
@@ -795,6 +832,9 @@ first and then run 'git rebase --continue' again."
        --autosquash)
                AUTOSQUASH=t
                ;;
+       --no-autosquash)
+               AUTOSQUASH=
+               ;;
        --onto)
                shift
                ONTO=$(parse_onto "$1") ||
@@ -890,11 +930,12 @@ first and then run 'git rebase --continue' again."
                git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
                        --abbrev=7 --reverse --left-right --topo-order \
                        $REVISIONS | \
-                       sed -n "s/^>//p" | while read shortsha1 rest
+                       sed -n "s/^>//p" |
+               while read -r shortsha1 rest
                do
                        if test t != "$PRESERVE_MERGES"
                        then
-                               echo "pick $shortsha1 $rest" >> "$TODO"
+                               printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
                        else
                                sha1=$(git rev-parse $shortsha1)
                                if test -z "$REBASE_ROOT"
@@ -913,7 +954,7 @@ first and then run 'git rebase --continue' again."
                                if test f = "$preserve"
                                then
                                        touch "$REWRITTEN"/$sha1
-                                       echo "pick $shortsha1 $rest" >> "$TODO"
+                                       printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
                                fi
                        fi
                done
@@ -956,6 +997,7 @@ first and then run 'git rebase --continue' again."
 #  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
+#  x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
@@ -974,8 +1016,9 @@ EOF
 
                test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
 
+               output git checkout $ONTO || die_abort "could not detach HEAD"
                git update-ref ORIG_HEAD $HEAD
-               output git checkout $ONTO && do_rest
+               do_rest
                ;;
        esac
        shift