diff options
Diffstat (limited to 'git-rebase--interactive.sh')
-rw-r--r-- | git-rebase--interactive.sh | 98 |
1 files changed, 85 insertions, 13 deletions
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5812222eb9..bef7bc0444 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -9,9 +9,7 @@ # # The original idea comes from Eric W. Biederman, in # http://article.gmane.org/gmane.comp.version-control.git/22407 - -. git-sh-setup - +# # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As # the lines are processed, they are removed from the front of this @@ -167,6 +165,14 @@ has_action () { sane_grep '^[^#]' "$1" >/dev/null } +is_empty_commit() { + tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null || + die "$1: not a commit that can be picked") + ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null || + ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904) + test "$tree" = "$ptree" +} + # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and # GIT_AUTHOR_DATE exported from the current environment. do_with_author () { @@ -191,12 +197,19 @@ git_sequence_editor () { pick_one () { ff=--ff + case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac case "$force_rebase" in '') ;; ?*) ff= ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" + + if is_empty_commit "$sha1" + then + empty_args="--allow-empty" + fi + test -d "$rewritten" && pick_one_preserving_merges "$@" && return - output git cherry-pick $ff "$@" + output git cherry-pick $empty_args $ff "$@" } pick_one_preserving_merges () { @@ -402,6 +415,29 @@ record_in_rewritten() { esac } +do_pick () { + if test "$(git rev-parse HEAD)" = "$squash_onto" + then + # Set the correct commit message and author info on the + # sentinel root before cherry-picking the original changes + # without committing (-n). Finally, update the sentinel again + # to include these changes. If the cherry-pick results in a + # conflict, this means our behaviour is similar to a standard + # failed cherry-pick during rebase, with a dirty index to + # resolve before manually running git commit --amend then git + # rebase --continue. + git commit --allow-empty --allow-empty-message --amend \ + --no-post-rewrite -n -q -C $1 && + pick_one -n $1 && + git commit --allow-empty --allow-empty-message \ + --amend --no-post-rewrite -n -q -C $1 || + die_with_patch $1 "Could not apply $1... $2" + else + pick_one $1 || + die_with_patch $1 "Could not apply $1... $2" + fi +} + do_next () { rm -f "$msg" "$author_script" "$amend" || exit read -r command sha1 rest < "$todo" @@ -413,16 +449,14 @@ do_next () { comment_for_reflog pick mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" record_in_rewritten $sha1 ;; reword|r) comment_for_reflog reword mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" git commit --amend --no-post-rewrite || { warn "Could not amend commit after successfully picking $sha1... $rest" warn "This is most likely due to an empty commit message, or the pre-commit hook" @@ -436,8 +470,7 @@ do_next () { comment_for_reflog edit mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" warn "Stopped at $sha1... $rest" exit_with_patch $sha1 0 ;; @@ -669,10 +702,31 @@ rearrange_squash () { rm -f "$1.sq" "$1.rearranged" } +# Add commands after a pick or after a squash/fixup serie +# in the todo list. +add_exec_commands () { + { + first=t + while read -r insn rest + do + case $insn in + pick) + test -n "$first" || + printf "%s" "$cmd" + ;; + esac + printf "%s %s\n" "$insn" "$rest" + first= + done + printf "%s" "$cmd" + } <"$1" >"$1.new" && + mv "$1.new" "$1" +} + case "$action" in continue) # do we have anything to commit? - if git diff-index --cached --quiet --ignore-submodules HEAD -- + if git diff-index --cached --quiet HEAD -- then : Nothing to commit -- skip this else @@ -780,9 +834,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \ sed -n "s/^>//p" | while read -r shortsha1 rest do + + if test -z "$keep_empty" && is_empty_commit $shortsha1 + then + comment_out="# " + else + comment_out= + fi + if test t != "$preserve_merges" then - printf '%s\n' "pick $shortsha1 $rest" >> "$todo" + printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo" else sha1=$(git rev-parse $shortsha1) if test -z "$rebase_root" @@ -801,7 +863,7 @@ do if test f = "$preserve" then touch "$rewritten"/$sha1 - printf '%s\n' "pick $shortsha1 $rest" >> "$todo" + printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo" fi fi done @@ -834,6 +896,8 @@ fi test -s "$todo" || echo noop >> "$todo" test -n "$autosquash" && rearrange_squash "$todo" +test -n "$cmd" && add_exec_commands "$todo" + cat >> "$todo" << EOF # Rebase $shortrevisions onto $shortonto @@ -846,11 +910,19 @@ cat >> "$todo" << EOF # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # +# These lines can be re-ordered; they are executed from top to bottom. +# # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # EOF +if test -z "$keep_empty" +then + echo "# Note that empty commits are commented out" >>"$todo" +fi + + has_action "$todo" || die_abort "Nothing to do" |