From 12a06e3abf21438b2601446faf9d1ca06e8062af Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 16 Sep 2010 10:59:21 +0200 Subject: [PATCH] git-rebase: extend --signoff support Support for the --signoff option is extended to other forms of git rebase (particularly, interactive rebasing). Signed-off-by: Giuseppe Bilotta --- Documentation/git-rebase.txt | 3 +-- git-rebase--am.sh | 2 +- git-rebase--interactive.sh | 44 ++++++++++++++++++++++++++++-------- git-rebase--merge.sh | 2 +- git-rebase.sh | 13 +++++++++-- t/t3428-rebase-signoff.sh | 40 ++++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 16 deletions(-) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 53f4e14444..f56f28a592 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -372,8 +372,7 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`. --signoff:: This flag is passed to 'git am' to sign off all the rebased - commits (see linkgit:git-am[1]). Incompatible with the - --interactive option. + commits (see linkgit:git-am[1]). -i:: --interactive:: diff --git a/git-rebase--am.sh b/git-rebase--am.sh index 375239341f..1fa8714d77 100644 --- a/git-rebase--am.sh +++ b/git-rebase--am.sh @@ -81,7 +81,7 @@ else return $ret fi - git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \ + git am $git_am_opt $signoff --rebasing --resolvemsg="$resolvemsg" \ ${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches" ret=$? diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2c9c0165b5..962a0fde56 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -81,6 +81,11 @@ rewritten_pending="$state_dir"/rewritten-pending # and leaves CR at the end instead. cr=$(printf "\015") +# When signoff=--signoff, we may actually want to skip signing off specific commits, +# particularly those followed by squashes or fixups. The next variable holds the +# signoff option for the commit being processed +this_signoff=$signoff + strategy_args=${strategy:+--strategy=$strategy} test -n "$strategy_opts" && eval ' @@ -281,9 +286,10 @@ pick_one () { test -d "$rewritten" && pick_one_preserving_merges "$@" && return + output eval git cherry-pick \ ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ - "$strategy_args" $empty_args $ff "$@" + $this_signoff "$strategy_args" $empty_args $ff "$@" # If cherry-pick dies it leaves the to-be-picked commit unrecorded. Reschedule # previous task so this commit is not lost. @@ -403,7 +409,7 @@ pick_one_preserving_merges () { *) output eval git cherry-pick \ ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ - "$strategy_args" "$@" || + $this_signoff "$strategy_args" "$@" || die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")" ;; esac @@ -469,6 +475,19 @@ peek_next_command () { git stripspace --strip-comments <"$todo" | sed -n -e 's/ .*//p' -e q } +# Check if the current commit should be signed off or not. This sets the +# variable this_signoff to the value of the signoff variable unless the next +# action is a squash or fixup, in which case the signoff is skipped. +check_this_signoff() { + this_signoff=$signoff + if test "$this_signoff" = --signoff ; then + case "$(peek_next_command)" in + squash|s|fixup|f) + this_signoff=--no-signoff + esac + fi +} + # A squash/fixup has failed. Prepare the long version of the squash # commit message, then die_with_patch. This code path requires the # user to edit the combined commit message for all commits that have @@ -524,7 +543,7 @@ do_pick () { pick_one -n $sha1 && git commit --allow-empty --allow-empty-message \ --amend --no-post-rewrite -n -q -C $sha1 \ - ${gpg_sign_opt:+"$gpg_sign_opt"} || + $this_signoff ${gpg_sign_opt:+"$gpg_sign_opt"} || die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")" else pick_one $sha1 || @@ -547,6 +566,7 @@ do_next () { comment_for_reflog pick mark_action_done + check_this_signoff do_pick $sha1 "$rest" record_in_rewritten $sha1 ;; @@ -554,6 +574,7 @@ do_next () { comment_for_reflog reword mark_action_done + check_this_signoff do_pick $sha1 "$rest" git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || { warn "$(eval_gettext "\ @@ -569,6 +590,7 @@ you are able to reword the commit.")" comment_for_reflog edit mark_action_done + check_this_signoff do_pick $sha1 "$rest" sha1_abbrev=$(git rev-parse --short $sha1) warn "$(eval_gettext "Stopped at \$sha1_abbrev... \$rest")" @@ -611,13 +633,13 @@ you are able to reword the commit.")" if test -f "$fixup_msg" then do_with_author git commit --amend --no-verify -F "$fixup_msg" \ - ${gpg_sign_opt:+"$gpg_sign_opt"} || + $signoff ${gpg_sign_opt:+"$gpg_sign_opt"} || die_failed_squash $sha1 "$rest" else cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit rm -f "$GIT_DIR"/MERGE_MSG do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \ - ${gpg_sign_opt:+"$gpg_sign_opt"} || + $signoff ${gpg_sign_opt:+"$gpg_sign_opt"} || die_failed_squash $sha1 "$rest" fi rm -f "$squash_msg" "$fixup_msg" @@ -1071,7 +1093,7 @@ case "$action" in continue) if test ! -d "$rewritten" then - exec git rebase--helper ${force_rebase:+--no-ff} --continue + exec git rebase--helper ${force_rebase:+--no-ff} $signoff --continue fi # do we have anything to commit? if git diff-index --cached --quiet HEAD -- @@ -1103,6 +1125,8 @@ In both cases, once you're done, continue with: fi . "$author_script" || die "$(gettext "Error trying to find the author identity to amend commit")" + + check_this_signoff if test -f "$amend" then current_head=$(git rev-parse --verify HEAD) @@ -1111,11 +1135,11 @@ In both cases, once you're done, continue with: You have uncommitted changes in your working tree. Please commit them first and then run 'git rebase --continue' again.")" do_with_author git commit --amend --no-verify -F "$msg" -e \ - ${gpg_sign_opt:+"$gpg_sign_opt"} || + $this_signoff ${gpg_sign_opt:+"$gpg_sign_opt"} || die "$(gettext "Could not commit staged changes.")" else do_with_author git commit --no-verify -F "$msg" -e \ - ${gpg_sign_opt:+"$gpg_sign_opt"} || + $this_signoff ${gpg_sign_opt:+"$gpg_sign_opt"} || die "$(gettext "Could not commit staged changes.")" fi fi @@ -1134,7 +1158,7 @@ skip) if test ! -d "$rewritten" then - exec git rebase--helper ${force_rebase:+--no-ff} --continue + exec git rebase--helper ${force_rebase:+--no-ff} $signoff --continue fi do_rest return 0 @@ -1325,7 +1349,7 @@ checkout_onto if test -z "$rebase_root" && test ! -d "$rewritten" then require_clean_work_tree "rebase" - exec git rebase--helper ${force_rebase:+--no-ff} --continue + exec git rebase--helper ${force_rebase:+--no-ff} $signoff --continue fi do_rest diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index 06a4723d4d..50b9345d72 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -27,7 +27,7 @@ continue_merge () { cmt=$(cat "$state_dir/current") if ! git diff-index --quiet --ignore-submodules HEAD -- then - if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt" + if ! git commit $signoff ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt" then echo "Commit failed, please do not call \"git commit\"" echo "directly, but instead do one of the following: " diff --git a/git-rebase.sh b/git-rebase.sh index db1deed846..ca87cd7103 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -34,7 +34,7 @@ root! rebase all reachable commits up to the root(s) autosquash move commits that begin with squash!/fixup! under -i committer-date-is-author-date! passed to 'git am' ignore-date! passed to 'git am' -signoff passed to 'git am' +signoff add a sign-off line to each rebased commit whitespace=! passed to 'git apply' ignore-whitespace! passed to 'git apply' C=! passed to 'git apply' @@ -75,6 +75,7 @@ fork_point=auto git_am_opt= rebase_root= force_rebase= +signoff= allow_rerere_autoupdate= # Non-empty if a rebase was in progress when 'git rebase' was invoked in_progress= @@ -116,6 +117,9 @@ read_basic_state () { allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)" test -f "$state_dir"/gpg_sign_opt && gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)" + test -f "$state_dir"/signoff && + signoff="$(cat "$state_dir"/signoff)" && + test "$signoff" = --signoff && force_rebase=t } write_basic_state () { @@ -130,6 +134,7 @@ write_basic_state () { test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \ "$state_dir"/allow_rerere_autoupdate test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt + test -n "$signoff" && echo "$signoff" > "$state_dir"/signoff } output () { @@ -322,10 +327,14 @@ do --ignore-whitespace) git_am_opt="$git_am_opt $1" ;; - --committer-date-is-author-date|--ignore-date|--signoff|--no-signoff) + --committer-date-is-author-date|--ignore-date) git_am_opt="$git_am_opt $1" force_rebase=t ;; + --signoff|--no-signoff) + signoff=$1 + test $1 = --signoff && force_rebase=t + ;; -C*) git_am_opt="$git_am_opt $1" ;; diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index 2afb564701..aa8cfa4909 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -7,6 +7,8 @@ This test runs git rebase --signoff and make sure that it works. . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + # A simple file to commit cat >file <expected-unsigned <expected-squash <.*/>/") +EOF + # We configure an alias to do the rebase --signoff so that # on the next subtest we can show that --no-signoff overrides the alias @@ -43,4 +54,33 @@ test_expect_success 'rebase --no-signoff does not add a sign-off line' ' test_cmp expected-unsigned actual ' +test_expect_success 'rebase --signoff works in interactive mode' ' + git commit --amend -m "first" && + git rbs -i HEAD^ && + git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && + test_cmp expected-signed actual +' + +test_expect_success 'rebase --signoff gets applied only once with fixups' ' + git commit --amend -m "first" && + echo b >> file && + git commit --fixup HEAD file && + git rbs -i --autosquash HEAD~2 && + git log && + git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && + test_cmp expected-signed actual +' + +test_expect_success 'rebase --signoff gets applied only once with squashes' ' + git commit --amend -m "first" && + echo b >> file && + git commit -m squash file && + set_fake_editor && + FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 git rbs -i HEAD~2 && + git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && + test_cmp expected-squash actual +' + + + test_done -- 2.32.0.93.g670b81a890