1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-29 01:36:13 +02:00

Merge branch 'pw/rebase-signoff'

"git rebase" has learned to honor "--signoff" option when using
backends other than "am" (but not "--preserve-merges").

* pw/rebase-signoff:
  rebase --keep-empty: always use interactive rebase
  rebase -p: error out if --signoff is given
  rebase: extend --signoff support
This commit is contained in:
Junio C Hamano 2018-04-25 13:28:51 +09:00
commit 850e925752
8 changed files with 115 additions and 58 deletions

View File

@ -364,9 +364,10 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.
Incompatible with the --interactive option. Incompatible with the --interactive option.
--signoff:: --signoff::
This flag is passed to 'git am' to sign off all the rebased Add a Signed-off-by: trailer to all the rebased commits. Note
commits (see linkgit:git-am[1]). Incompatible with the that if `--interactive` is given then only commits marked to be
--interactive option. picked, edited or reworded will have the trailer added. Incompatible
with the `--preserve-merges` option.
-i:: -i::
--interactive:: --interactive::

View File

@ -32,61 +32,48 @@ else
fi fi
ret=0 ret=0
if test -n "$keep_empty" rm -f "$GIT_DIR/rebased-patches"
git format-patch -k --stdout --full-index --cherry-pick --right-only \
--src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
--pretty=mboxrd \
$git_format_patch_opt \
"$revisions" ${restrict_revision+^$restrict_revision} \
>"$GIT_DIR/rebased-patches"
ret=$?
if test 0 != $ret
then then
# we have to do this the hard way. git format-patch completely squashes
# empty commits and even if it didn't the format doesn't really lend
# itself well to recording empty patches. fortunately, cherry-pick
# makes this easy
git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
$allow_rerere_autoupdate --right-only "$revisions" \
$allow_empty_message \
${restrict_revision+^$restrict_revision}
ret=$?
else
rm -f "$GIT_DIR/rebased-patches" rm -f "$GIT_DIR/rebased-patches"
case "$head_name" in
refs/heads/*)
git checkout -q "$head_name"
;;
*)
git checkout -q "$orig_head"
;;
esac
git format-patch -k --stdout --full-index --cherry-pick --right-only \ cat >&2 <<-EOF
--src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
--pretty=mboxrd \
$git_format_patch_opt \
"$revisions" ${restrict_revision+^$restrict_revision} \
>"$GIT_DIR/rebased-patches"
ret=$?
if test 0 != $ret git encountered an error while preparing the patches to replay
then these revisions:
rm -f "$GIT_DIR/rebased-patches"
case "$head_name" in
refs/heads/*)
git checkout -q "$head_name"
;;
*)
git checkout -q "$orig_head"
;;
esac
cat >&2 <<-EOF $revisions
git encountered an error while preparing the patches to replay As a result, git cannot rebase them.
these revisions: EOF
return $ret
$revisions
As a result, git cannot rebase them.
EOF
return $ret
fi
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
--patch-format=mboxrd \
$allow_rerere_autoupdate \
${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches"
ret=$?
rm -f "$GIT_DIR/rebased-patches"
fi fi
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
--patch-format=mboxrd \
$allow_rerere_autoupdate \
${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches"
ret=$?
rm -f "$GIT_DIR/rebased-patches"
if test 0 != $ret if test 0 != $ret
then then
test -d "$state_dir" && write_basic_state test -d "$state_dir" && write_basic_state

View File

@ -285,7 +285,7 @@ pick_one () {
pick_one_preserving_merges "$@" && return pick_one_preserving_merges "$@" && return
output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \ output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \ ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
"$strategy_args" $empty_args $ff "$@" $signoff "$strategy_args" $empty_args $ff "$@"
# If cherry-pick dies it leaves the to-be-picked commit unrecorded. Reschedule # If cherry-pick dies it leaves the to-be-picked commit unrecorded. Reschedule
# previous task so this commit is not lost. # previous task so this commit is not lost.
@ -524,10 +524,10 @@ do_pick () {
# resolve before manually running git commit --amend then git # resolve before manually running git commit --amend then git
# rebase --continue. # rebase --continue.
git commit --allow-empty --allow-empty-message --amend \ git commit --allow-empty --allow-empty-message --amend \
--no-post-rewrite -n -q -C $sha1 && --no-post-rewrite -n -q -C $sha1 $signoff &&
pick_one -n $sha1 && pick_one -n $sha1 &&
git commit --allow-empty --allow-empty-message \ git commit --allow-empty --allow-empty-message \
--amend --no-post-rewrite -n -q -C $sha1 \ --amend --no-post-rewrite -n -q -C $sha1 $signoff \
${gpg_sign_opt:+"$gpg_sign_opt"} || ${gpg_sign_opt:+"$gpg_sign_opt"} ||
die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")" die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")"
else else

View File

@ -27,7 +27,7 @@ continue_merge () {
cmt=$(cat "$state_dir/current") cmt=$(cat "$state_dir/current")
if ! git diff-index --quiet --ignore-submodules HEAD -- if ! git diff-index --quiet --ignore-submodules HEAD --
then then
if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \ if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $signoff $allow_empty_message \
--no-verify -C "$cmt" --no-verify -C "$cmt"
then then
echo "Commit failed, please do not call \"git commit\"" echo "Commit failed, please do not call \"git commit\""

View File

@ -93,6 +93,7 @@ preserve_merges=
autosquash= autosquash=
keep_empty= keep_empty=
allow_empty_message= allow_empty_message=
signoff=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
case "$(git config --bool commit.gpgsign)" in case "$(git config --bool commit.gpgsign)" in
true) gpg_sign_opt=-S ;; true) gpg_sign_opt=-S ;;
@ -122,6 +123,10 @@ read_basic_state () {
allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)" allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
test -f "$state_dir"/gpg_sign_opt && test -f "$state_dir"/gpg_sign_opt &&
gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)" gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
test -f "$state_dir"/signoff && {
signoff="$(cat "$state_dir"/signoff)"
force_rebase=t
}
} }
write_basic_state () { write_basic_state () {
@ -136,6 +141,7 @@ write_basic_state () {
test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \ test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
"$state_dir"/allow_rerere_autoupdate "$state_dir"/allow_rerere_autoupdate
test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
test -n "$signoff" && echo "$signoff" >"$state_dir"/signoff
} }
output () { output () {
@ -336,7 +342,13 @@ do
--ignore-whitespace) --ignore-whitespace)
git_am_opt="$git_am_opt $1" git_am_opt="$git_am_opt $1"
;; ;;
--committer-date-is-author-date|--ignore-date|--signoff|--no-signoff) --signoff)
signoff=--signoff
;;
--no-signoff)
signoff=
;;
--committer-date-is-author-date|--ignore-date)
git_am_opt="$git_am_opt $1" git_am_opt="$git_am_opt $1"
force_rebase=t force_rebase=t
;; ;;
@ -452,6 +464,11 @@ then
test -z "$interactive_rebase" && interactive_rebase=implied test -z "$interactive_rebase" && interactive_rebase=implied
fi fi
if test -n "$keep_empty"
then
test -z "$interactive_rebase" && interactive_rebase=implied
fi
if test -n "$interactive_rebase" if test -n "$interactive_rebase"
then then
type=interactive type=interactive
@ -470,6 +487,14 @@ then
git_format_patch_opt="$git_format_patch_opt --progress" git_format_patch_opt="$git_format_patch_opt --progress"
fi fi
if test -n "$signoff"
then
test -n "$preserve_merges" &&
die "$(gettext "error: cannot combine '--signoff' with '--preserve-merges'")"
git_am_opt="$git_am_opt $signoff"
force_rebase=t
fi
if test -z "$rebase_root" if test -z "$rebase_root"
then then
case "$#" in case "$#" in

View File

@ -127,6 +127,7 @@ static GIT_PATH_FUNC(rebase_path_rewritten_pending,
static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt") static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head") static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose") static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
static GIT_PATH_FUNC(rebase_path_signoff, "rebase-merge/signoff")
static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name") static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name")
static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto") static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash") static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash")
@ -1604,7 +1605,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
} }
} }
if (opts->signoff) if (opts->signoff && !is_fixup(command))
append_signoff(&msgbuf, 0, 0); append_signoff(&msgbuf, 0, 0);
if (is_rebase_i(opts) && write_author_script(msg.message) < 0) if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
@ -2043,6 +2044,11 @@ static int read_populate_opts(struct replay_opts *opts)
if (file_exists(rebase_path_verbose())) if (file_exists(rebase_path_verbose()))
opts->verbose = 1; opts->verbose = 1;
if (file_exists(rebase_path_signoff())) {
opts->allow_ff = 0;
opts->signoff = 1;
}
read_strategy_opts(opts, &buf); read_strategy_opts(opts, &buf);
strbuf_release(&buf); strbuf_release(&buf);

View File

@ -199,7 +199,7 @@ test_run_rebase () {
" "
} }
test_run_rebase success '' test_run_rebase success ''
test_run_rebase failure -m test_run_rebase success -m
test_run_rebase success -i test_run_rebase success -i
test_run_rebase failure -p test_run_rebase failure -p
@ -214,7 +214,7 @@ test_run_rebase () {
" "
} }
test_run_rebase success '' test_run_rebase success ''
test_run_rebase failure -m test_run_rebase success -m
test_run_rebase success -i test_run_rebase success -i
test_run_rebase failure -p test_run_rebase failure -p

View File

@ -12,6 +12,13 @@ cat >file <<EOF
a a
EOF EOF
# Expected commit message for initial commit after rebase --signoff
cat >expected-initial-signed <<EOF
Initial empty commit
Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/")
EOF
# Expected commit message after rebase --signoff # Expected commit message after rebase --signoff
cat >expected-signed <<EOF cat >expected-signed <<EOF
first first
@ -43,4 +50,35 @@ test_expect_success 'rebase --no-signoff does not add a sign-off line' '
test_cmp expected-unsigned actual test_cmp expected-unsigned actual
' '
test_expect_success 'rebase --exec --signoff adds a sign-off line' '
test_when_finished "rm exec" &&
git commit --amend -m "first" &&
git rebase --exec "touch exec" --signoff HEAD^ &&
test_path_is_file exec &&
git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
test_cmp expected-signed actual
'
test_expect_success 'rebase --root --signoff adds a sign-off line' '
git commit --amend -m "first" &&
git rebase --root --keep-empty --signoff &&
git cat-file commit HEAD^ | sed -e "1,/^\$/d" >actual &&
test_cmp expected-initial-signed actual &&
git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
test_cmp expected-signed actual
'
test_expect_success 'rebase -i --signoff fails' '
git commit --amend -m "first" &&
git rebase -i --signoff HEAD^ &&
git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
test_cmp expected-signed actual
'
test_expect_success 'rebase -m --signoff fails' '
git commit --amend -m "first" &&
git rebase -m --signoff HEAD^ &&
git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
test_cmp expected-signed actual
'
test_done test_done