rebase: add --allow-empty-message option

This option allows commits with empty commit messages to be rebased, matching the same option in git-commit and git-cherry-pick. While empty log messages are frowned upon, sometimes one finds them in older repositories (e.g. translated from another VCS [0]), or have other reasons for desiring them. The option is available in git-commit and git-cherry-pick, so it is natural to make other git tools play nicely with them. Adding this as an option allows the default to be "give the user a chance to fix", while not interrupting the user's workflow otherwise [1]. [0]: https://stackoverflow.com/q/8542304 [1]: https://public-inbox.org/git/7vd33afqjh.fsf@alter.siamese.dyndns.org/ To implement this, add a new --allow-empty-message flag. Then propagate it to all calls of 'git commit', 'git cherry-pick', and 'git rebase--helper' within the rebase scripts. Signed-off-by: Genki Sky <sky@genki.is> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Genki Sky committed Feb 4, 2018 at 15:08 UTC a6c612b528a22fe9d4cad8807e36d18f2f0fea2c
7 files changed +53 -11
Documentation/git-rebase.txt
+5
@@ -244,6 +244,11 @@ leave out at most one of A and B, in which case it defaults to HEAD.
244 Keep the commits that do not change anything from its
245 parents in the result.
246
247 +--allow-empty-message::
248 + By default, rebasing commits with an empty message will fail.
249 + This option overrides that behavior, allowing commits with empty
250 + messages to be rebased.
251 +
252 --skip::
253 Restart the rebasing process by skipping the current patch.
254
builtin/rebase--helper.c
+2
@@ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
22 struct option options[] = {
23 OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
24 OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
25 + OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
26 + N_("allow commits with empty messages")),
27 OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
28 CONTINUE),
29 OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
git-rebase--am.sh
+1
@@ -46,6 +46,7 @@ then
46 # makes this easy
47 git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
48 $allow_rerere_autoupdate --right-only "$revisions" \
49 + $allow_empty_message \
50 ${restrict_revision+^$restrict_revision}
51 ret=$?
52 else
git-rebase--interactive.sh
+15 -10
@@ -281,7 +281,7 @@ pick_one () {
281
282 test -d "$rewritten" &&
283 pick_one_preserving_merges "$@" && return
284 - output eval git cherry-pick $allow_rerere_autoupdate \
284 + output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
285 ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
286 "$strategy_args" $empty_args $ff "$@"
287
@@ -406,6 +406,7 @@ pick_one_preserving_merges () {
406 ;;
407 *)
408 output eval git cherry-pick $allow_rerere_autoupdate \
409 + $allow_empty_message \
410 ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
411 "$strategy_args" "$@" ||
412 die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
@@ -559,7 +560,8 @@ do_next () {
560
561 mark_action_done
562 do_pick $sha1 "$rest"
562 - git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
563 + git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \
564 + $allow_empty_message || {
565 warn "$(eval_gettext "\
566 Could not amend commit after successfully picking \$sha1... \$rest
567 This is most likely due to an empty commit message, or the pre-commit hook
@@ -607,7 +609,7 @@ you are able to reword the commit.")"
609 # This is an intermediate commit; its message will only be
610 # used in case of trouble. So use the long version:
611 do_with_author output git commit --amend --no-verify -F "$squash_msg" \
610 - ${gpg_sign_opt:+"$gpg_sign_opt"} ||
612 + ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
613 die_failed_squash $sha1 "$rest"
614 ;;
615 *)
@@ -615,13 +617,13 @@ you are able to reword the commit.")"
617 if test -f "$fixup_msg"
618 then
619 do_with_author git commit --amend --no-verify -F "$fixup_msg" \
618 - ${gpg_sign_opt:+"$gpg_sign_opt"} ||
620 + ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
621 die_failed_squash $sha1 "$rest"
622 else
623 cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
624 rm -f "$GIT_DIR"/MERGE_MSG
625 do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \
624 - ${gpg_sign_opt:+"$gpg_sign_opt"} ||
626 + ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
627 die_failed_squash $sha1 "$rest"
628 fi
629 rm -f "$squash_msg" "$fixup_msg"
@@ -754,7 +756,8 @@ case "$action" in
756 continue)
757 if test ! -d "$rewritten"
758 then
757 - exec git rebase--helper ${force_rebase:+--no-ff} --continue
759 + exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
760 + --continue
761 fi
762 # do we have anything to commit?
763 if git diff-index --cached --quiet HEAD --
@@ -794,11 +797,11 @@ In both cases, once you're done, continue with:
797 You have uncommitted changes in your working tree. Please commit them
798 first and then run 'git rebase --continue' again.")"
799 do_with_author git commit --amend --no-verify -F "$msg" -e \
797 - ${gpg_sign_opt:+"$gpg_sign_opt"} ||
800 + ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
801 die "$(gettext "Could not commit staged changes.")"
802 else
803 do_with_author git commit --no-verify -F "$msg" -e \
801 - ${gpg_sign_opt:+"$gpg_sign_opt"} ||
804 + ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
805 die "$(gettext "Could not commit staged changes.")"
806 fi
807 fi
@@ -817,7 +820,8 @@ skip)
820
821 if test ! -d "$rewritten"
822 then
820 - exec git rebase--helper ${force_rebase:+--no-ff} --continue
823 + exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
824 + --continue
825 fi
826 do_rest
827 return 0
@@ -1016,7 +1020,8 @@ checkout_onto
1020 if test -z "$rebase_root" && test ! -d "$rewritten"
1021 then
1022 require_clean_work_tree "rebase"
1019 - exec git rebase--helper ${force_rebase:+--no-ff} --continue
1023 + exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
1024 + --continue
1025 fi
1026 do_rest
1027
git-rebase--merge.sh
+2 -1
@@ -27,7 +27,8 @@ continue_merge () {
27 cmt=$(cat "$state_dir/current")
28 if ! git diff-index --quiet --ignore-submodules HEAD --
29 then
30 - if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt"
30 + if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \
31 + --no-verify -C "$cmt"
32 then
33 echo "Commit failed, please do not call \"git commit\""
34 echo "directly, but instead do one of the following: "
git-rebase.sh
+5
@@ -24,6 +24,7 @@ m,merge! use merging strategies to rebase
24 i,interactive! let the user edit the list of commits to rebase
25 x,exec=! add exec lines after each commit of the editable list
26 k,keep-empty preserve empty commits during rebase
27 +allow-empty-message allow rebasing commits with empty messages
28 f,force-rebase! force rebase even if branch is up to date
29 X,strategy-option=! pass the argument through to the merge strategy
30 stat! display a diffstat of what changed upstream
@@ -89,6 +90,7 @@ action=
90 preserve_merges=
91 autosquash=
92 keep_empty=
93 +allow_empty_message=
94 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
95 case "$(git config --bool commit.gpgsign)" in
96 true) gpg_sign_opt=-S ;;
@@ -262,6 +264,9 @@ do
264 --keep-empty)
265 keep_empty=yes
266 ;;
267 + --allow-empty-message)
268 + allow_empty_message=--allow-empty-message
269 + ;;
270 --preserve-merges)
271 preserve_merges=t
272 test -z "$interactive_rebase" && interactive_rebase=implied
t/t3405-rebase-malformed.sh
+23
@@ -3,6 +3,7 @@
3 test_description='rebase should handle arbitrary git message'
4
5 . ./test-lib.sh
6 +. "$TEST_DIRECTORY"/lib-rebase.sh
7
8 cat >F <<\EOF
9 This is an example of a commit log message
@@ -25,6 +26,7 @@ test_expect_success setup '
26 test_tick &&
27 git commit -m "Initial commit" &&
28 git branch diff-in-message &&
29 + git branch empty-message-merge &&
30
31 git checkout -b multi-line-subject &&
32 cat F >file2 &&
@@ -45,6 +47,11 @@ test_expect_success setup '
47
48 git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
49
50 + git checkout empty-message-merge &&
51 + echo file3 >file3 &&
52 + git add file3 &&
53 + git commit --allow-empty-message -m "" &&
54 +
55 git checkout master &&
56
57 echo One >file1 &&
@@ -69,4 +76,20 @@ test_expect_success 'rebase commit with diff in message' '
76 test_cmp G G0
77 '
78
79 +test_expect_success 'rebase -m commit with empty message' '
80 + test_must_fail git rebase -m master empty-message-merge &&
81 + git rebase --abort &&
82 + git rebase -m --allow-empty-message master empty-message-merge
83 +'
84 +
85 +test_expect_success 'rebase -i commit with empty message' '
86 + git checkout diff-in-message &&
87 + set_fake_editor &&
88 + test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
89 + git rebase -i HEAD^ &&
90 + git rebase --abort &&
91 + FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
92 + git rebase -i --allow-empty-message HEAD^
93 +'
94 +
95 test_done