Code

rebase -i: add exec command to launch a shell command
[git.git] / git-rebase--interactive.sh
index 31e68603f4e8124fd67f42c8aae6033a792892cb..6c8ff0c46a6bd26f1dcdbac56bbdfa79bb104531 100755 (executable)
@@ -537,6 +537,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,10 +619,13 @@ do_rest () {
 # skip picking commits whose parents are unchanged
 skip_unnecessary_picks () {
        fd=3
-       while read -r command sha1 rest
+       while read -r line
        do
+               command=$(echo "$line" | sed 's/  */ /' | cut -d ' ' -f 1)
+               sha1=$(echo "$line"    | sed 's/  */ /' | cut -d ' ' -f 2)
+               rest=$(echo "$line"    | sed 's/  */ /' | cut -d ' ' -f 3-)
                # fd=3 means we skip the command
-               case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in
+               case "$fd,$command,$(git rev-parse --verify --quiet "$sha1"^)" in
                3,pick,"$ONTO"*|3,p,"$ONTO"*)
                        # pick a commit whose parent is current $ONTO -> skip
                        ONTO=$sha1
@@ -606,7 +637,7 @@ skip_unnecessary_picks () {
                        fd=1
                        ;;
                esac
-               echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
+               echo "$line" >&$fd
        done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
        mv -f "$TODO".new "$TODO" &&
        case "$(peek_next_command)" in
@@ -957,6 +988,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.