From cd035b1cef39811fd3116aa07d99395960ec947a Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Tue, 10 Aug 2010 17:17:51 +0200 Subject: rebase -i: add exec command to launch a shell command The typical usage pattern would be to run a test (or simply a compilation command) at given points in history. The shell command is ran (from the worktree root), and the rebase is stopped when the command fails, to give the user an opportunity to fix the problem before continuing with "git rebase --continue". This needs a little rework of skip_unnecessary_picks, which wasn't robust enough to deal with lines like exec >"file name with many spaces" in the todolist. The new version extracts command, sha1 and rest from each line, but outputs the line itself verbatim to avoid changing the whitespace layout. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 31e68603f4..6c8ff0c46a 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -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 , exec = Run a shell command , 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. -- cgit v1.3-5-g9baa From 2d6ca6ef55226185b6a093f7fac27f5fecd51fe6 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Fri, 13 Aug 2010 15:47:34 -0500 Subject: git-rebase--interactive.sh: rework skip_unnecessary_picks Commit cd035b1c introduced the exec command to interactive rebase. In doing so, it modified the way that skip_unnecessary_picks iterates through the list of rebase commands so that it avoided collapsing multiple spaces into a single space. This is necessary for example if the argument to the exec command contains a path with multiple spaces in it. The way it did this was by reading each line of rebase commands into a single variable, and then breaking the individual components out using echo, sed, and cut. It used the individual broken-out components for decision making, and was still able to write the original line to the output file from the variable it had saved it in. But, since we only really need to look at anything other than the first element of the line when a 'pick' command is encountered, and even that is only necessary when we are still searching for "unnecessary" picks, and since newer rebase commands like 'exec' may not even require a sha1 field, let's make our read statement parse its input into a "command" variable, and a "rest" variable, and then only break out the sha1 from $rest, and call git-rev-parse, when absolutely necessary. I think this future proofs this subroutine, avoids calling git-rev-parse unnecessarily, and possibly with bogus arguments, and still accomplishes the goal of not mangling the $rest of the rebase command. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 6c8ff0c46a..3b10513806 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -619,25 +619,30 @@ do_rest () { # skip picking commits whose parents are unchanged skip_unnecessary_picks () { fd=3 - while read -r line + while read -r command rest 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 - 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=$(echo "$rest" | cut -d ' ' -f 1) + case "$(git rev-parse --verify --quiet "$sha1"^)" in + "$ONTO"*) + ONTO=$sha1 + ;; + *) + fd=1 + ;; + esac ;; - 3,#*|3,,*) + 3,#*|3,) # copy comments ;; *) fd=1 ;; esac - echo "$line" >&$fd + echo "$command${rest:+ }$rest" >&$fd done <"$TODO" >"$TODO.new" 3>>"$DONE" && mv -f "$TODO".new "$TODO" && case "$(peek_next_command)" in -- cgit v1.3-5-g9baa From d1c3b10f7ced34a607c50de8b5c271ce9cf764ea Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Fri, 13 Aug 2010 15:47:35 -0500 Subject: git-rebase--interactive.sh: use printf instead of echo to print commit message Replace the echo statements that operate on $rest with printf's to restore what was lost from 938791cd. This avoids any mangling that XSI-conformant echo's may introduce. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 3b10513806..e16dbe201d 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -625,7 +625,7 @@ skip_unnecessary_picks () { case "$fd,$command" in 3,pick|3,p) # pick a commit whose parent is current $ONTO -> skip - sha1=$(echo "$rest" | cut -d ' ' -f 1) + sha1=$(printf '%s' "$rest" | cut -d ' ' -f 1) case "$(git rev-parse --verify --quiet "$sha1"^)" in "$ONTO"*) ONTO=$sha1 @@ -642,7 +642,7 @@ skip_unnecessary_picks () { fd=1 ;; esac - echo "$command${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 -- cgit v1.3-5-g9baa