X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=git-rebase--interactive.sh;h=5934b97fa106d73b1b091f050272c4c9f25eb646;hb=HEAD;hp=b94c2a03867ddcd1fa0c2051f81cf14547b550f0;hpb=c7e375de4228cdb86e2582e2eda7fa3a6f352fc2;p=git.git diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index b94c2a038..5934b97fa 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -111,11 +111,12 @@ 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 ', and -run 'git rebase --continue'" +GIT_CHERRY_PICK_HELP="\ +hint: after resolving the conflicts, mark the corrected paths +hint: with 'git add ' and run 'git rebase --continue'" export GIT_CHERRY_PICK_HELP warn () { @@ -152,14 +153,6 @@ run_pre_rebase_hook () { fi } -require_clean_work_tree () { - # test if working tree is dirty - git rev-parse --verify HEAD > /dev/null && - git update-index --ignore-submodules --refresh && - git diff-files --quiet --ignore-submodules && - git diff-index --cached --quiet HEAD --ignore-submodules -- || - die "Working tree is dirty" -} ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION" @@ -537,6 +530,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 "rebase") + 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 +612,30 @@ do_rest () { # skip picking commits whose parents are unchanged skip_unnecessary_picks () { fd=3 - while read -r 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 - printf '%s\n' "$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 @@ -638,9 +667,27 @@ get_saved_options () { # comes immediately after the former, and change "pick" to # "fixup"/"squash". rearrange_squash () { - sed -n -e 's/^pick \([0-9a-f]*\) \(squash\)! /\1 \2 /p' \ - -e 's/^pick \([0-9a-f]*\) \(fixup\)! /\1 \2 /p' \ - "$1" >"$1.sq" + # extract fixup!/squash! lines and resolve any referenced sha1's + while read -r pick sha1 message + do + case "$message" in + "squash! "*|"fixup! "*) + action="${message%%!*}" + rest="${message#*! }" + echo "$sha1 $action $rest" + # if it's a single word, try to resolve to a full sha1 and + # emit a second copy. This allows us to match on both message + # and on sha1 prefix + if test "${rest#* }" = "$rest"; then + fullsha="$(git rev-parse -q --verify "$rest" 2>/dev/null)" + if test -n "$fullsha"; then + # prefix the action to uniquely identify this line as + # intended for full sha1 match + echo "$sha1 +$action $fullsha" + fi + fi + esac + done >"$1.sq" <"$1" test -s "$1.sq" || return used= @@ -650,14 +697,26 @@ rearrange_squash () { *" $sha1 "*) continue ;; esac printf '%s\n' "$pick $sha1 $message" + used="$used$sha1 " while read -r squash action msg do - case "$message" in - "$msg"*) + case " $used" in + *" $squash "*) continue ;; + esac + emit=0 + case "$action" in + +*) + action="${action#+}" + # full sha1 prefix test + case "$msg" in "$sha1"*) emit=1;; esac ;; + *) + # message prefix test + case "$message" in "$msg"*) emit=1;; esac ;; + esac + if test $emit = 1; then printf '%s\n' "$action $squash $action! $msg" used="$used$squash " - ;; - esac + fi done <"$1.sq" done >"$1.rearranged" <"$1" cat "$1.rearranged" >"$1" @@ -731,7 +790,7 @@ first and then run 'git rebase --continue' again." record_in_rewritten "$(cat "$DOTEST"/stopped-sha)" - require_clean_work_tree + require_clean_work_tree "rebase" do_rest ;; --abort) @@ -795,6 +854,9 @@ first and then run 'git rebase --continue' again." --autosquash) AUTOSQUASH=t ;; + --no-autosquash) + AUTOSQUASH= + ;; --onto) shift ONTO=$(parse_onto "$1") || @@ -826,7 +888,7 @@ first and then run 'git rebase --continue' again." comment_for_reflog start - require_clean_work_tree + require_clean_work_tree "rebase" "Please commit or stash them." if test ! -z "$1" then @@ -957,6 +1019,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.