rebase: add --allow-empty-message option
authorGenki Sky <sky@genki.is>
Sun, 4 Feb 2018 20:08:13 +0000 (15:08 -0500)
committerJunio C Hamano <gitster@pobox.com>
Wed, 7 Feb 2018 19:26:46 +0000 (11:26 -0800)
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>
Documentation/git-rebase.txt
builtin/rebase--helper.c
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
t/t3405-rebase-malformed.sh
index 8a861c1e0d69eda71fa2eec791e67c136b63b177..d713951b86abaa3fbea48703f87cce5cf0330019 100644 (file)
@@ -244,6 +244,11 @@ leave out at most one of A and B, in which case it defaults to HEAD.
        Keep the commits that do not change anything from its
        parents in the result.
 
        Keep the commits that do not change anything from its
        parents in the result.
 
+--allow-empty-message::
+       By default, rebasing commits with an empty message will fail.
+       This option overrides that behavior, allowing commits with empty
+       messages to be rebased.
+
 --skip::
        Restart the rebasing process by skipping the current patch.
 
 --skip::
        Restart the rebasing process by skipping the current patch.
 
index 7daee544b7b4cf3495355e1c6e597272d7b66440..2090114e9a33cfd7cf289b43883cbad4b984d8bb 100644 (file)
@@ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
                OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
        struct option options[] = {
                OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
                OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
+               OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
+                       N_("allow commits with empty messages")),
                OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
                                CONTINUE),
                OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
                OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
                                CONTINUE),
                OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
index 14c50782e096966b860d49cbaed7658e9f56958f..0f78051792fae93f7966c2a3f9fc670b4fca9188 100644 (file)
@@ -46,6 +46,7 @@ then
        # makes this easy
        git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
                $allow_rerere_autoupdate --right-only "$revisions" \
        # 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
                ${restrict_revision+^$restrict_revision}
        ret=$?
 else
index d47bd29593ad8711448293f3b6bf2e059323ff78..81c5b42875771ab98ca86e718e14a5a393aa1a86 100644 (file)
@@ -281,7 +281,7 @@ pick_one () {
 
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
 
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
-       output eval git cherry-pick $allow_rerere_autoupdate \
+       output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
 
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
 
@@ -406,6 +406,7 @@ pick_one_preserving_merges () {
                        ;;
                *)
                        output eval git cherry-pick $allow_rerere_autoupdate \
                        ;;
                *)
                        output eval git cherry-pick $allow_rerere_autoupdate \
+                               $allow_empty_message \
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
                                die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
                                die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
@@ -559,7 +560,8 @@ do_next () {
 
                mark_action_done
                do_pick $sha1 "$rest"
 
                mark_action_done
                do_pick $sha1 "$rest"
-               git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
+               git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \
+                       $allow_empty_message || {
                        warn "$(eval_gettext "\
 Could not amend commit after successfully picking \$sha1... \$rest
 This is most likely due to an empty commit message, or the pre-commit hook
                        warn "$(eval_gettext "\
 Could not amend commit after successfully picking \$sha1... \$rest
 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.")"
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
                        do_with_author output git commit --amend --no-verify -F "$squash_msg" \
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
                        do_with_author output git commit --amend --no-verify -F "$squash_msg" \
-                               ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
@@ -615,13 +617,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" \
                        if test -f "$fixup_msg"
                        then
                                do_with_author git commit --amend --no-verify -F "$fixup_msg" \
-                                       ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                                       ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        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 \
                                        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"} ||
+                                       ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@ -754,7 +756,8 @@ case "$action" in
 continue)
        if test ! -d "$rewritten"
        then
 continue)
        if test ! -d "$rewritten"
        then
-               exec git rebase--helper ${force_rebase:+--no-ff} --continue
+               exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+                       --continue
        fi
        # do we have anything to commit?
        if git diff-index --cached --quiet HEAD --
        fi
        # do we have anything to commit?
        if git diff-index --cached --quiet HEAD --
@@ -794,11 +797,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 \
 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"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                else
                        do_with_author git commit --no-verify -F "$msg" -e \
                                die "$(gettext "Could not commit staged changes.")"
                else
                        do_with_author git commit --no-verify -F "$msg" -e \
-                               ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                fi
        fi
                                die "$(gettext "Could not commit staged changes.")"
                fi
        fi
@@ -817,7 +820,8 @@ skip)
 
        if test ! -d "$rewritten"
        then
 
        if test ! -d "$rewritten"
        then
-               exec git rebase--helper ${force_rebase:+--no-ff} --continue
+               exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+                       --continue
        fi
        do_rest
        return 0
        fi
        do_rest
        return 0
@@ -1016,7 +1020,8 @@ checkout_onto
 if test -z "$rebase_root" && test ! -d "$rewritten"
 then
        require_clean_work_tree "rebase"
 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} $allow_empty_message \
+               --continue
 fi
 do_rest
 
 fi
 do_rest
 
index 06a4723d4db3db74ea17ace60d824e83cdee25e9..1831e589b8c94b3fbcee710c5742b71a3e7e8f9e 100644 (file)
@@ -27,7 +27,8 @@ continue_merge () {
        cmt=$(cat "$state_dir/current")
        if ! git diff-index --quiet --ignore-submodules HEAD --
        then
        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 ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \
+                       --no-verify -C "$cmt"
                then
                        echo "Commit failed, please do not call \"git commit\""
                        echo "directly, but instead do one of the following: "
                then
                        echo "Commit failed, please do not call \"git commit\""
                        echo "directly, but instead do one of the following: "
index fd72a35c65b43537b292445b87ffb7e682cc076a..b353c33d417a913c2b356b3c070b1dbbc033f162 100755 (executable)
@@ -24,6 +24,7 @@ m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
 x,exec=!           add exec lines after each commit of the editable list
 k,keep-empty      preserve empty commits during rebase
 i,interactive!     let the user edit the list of commits to rebase
 x,exec=!           add exec lines after each commit of the editable list
 k,keep-empty      preserve empty commits during rebase
+allow-empty-message allow rebasing commits with empty messages
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -89,6 +90,7 @@ action=
 preserve_merges=
 autosquash=
 keep_empty=
 preserve_merges=
 autosquash=
 keep_empty=
+allow_empty_message=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 case "$(git config --bool commit.gpgsign)" in
 true)  gpg_sign_opt=-S ;;
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 case "$(git config --bool commit.gpgsign)" in
 true)  gpg_sign_opt=-S ;;
@@ -262,6 +264,9 @@ do
        --keep-empty)
                keep_empty=yes
                ;;
        --keep-empty)
                keep_empty=yes
                ;;
+       --allow-empty-message)
+               allow_empty_message=--allow-empty-message
+               ;;
        --preserve-merges)
                preserve_merges=t
                test -z "$interactive_rebase" && interactive_rebase=implied
        --preserve-merges)
                preserve_merges=t
                test -z "$interactive_rebase" && interactive_rebase=implied
index ff8c360cd58bc11366ac2cf9e7c0b141e4ac3a39..cb7c6de84abf88bf90ac9716bb24ac91b8f64bf9 100755 (executable)
@@ -3,6 +3,7 @@
 test_description='rebase should handle arbitrary git message'
 
 . ./test-lib.sh
 test_description='rebase should handle arbitrary git message'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
 
 cat >F <<\EOF
 This is an example of a commit log message
 
 cat >F <<\EOF
 This is an example of a commit log message
@@ -25,6 +26,7 @@ test_expect_success setup '
        test_tick &&
        git commit -m "Initial commit" &&
        git branch diff-in-message &&
        test_tick &&
        git commit -m "Initial commit" &&
        git branch diff-in-message &&
+       git branch empty-message-merge &&
 
        git checkout -b multi-line-subject &&
        cat F >file2 &&
 
        git checkout -b multi-line-subject &&
        cat F >file2 &&
@@ -45,6 +47,11 @@ test_expect_success setup '
 
        git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
 
 
        git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
 
+       git checkout empty-message-merge &&
+       echo file3 >file3 &&
+       git add file3 &&
+       git commit --allow-empty-message -m "" &&
+
        git checkout master &&
 
        echo One >file1 &&
        git checkout master &&
 
        echo One >file1 &&
@@ -69,4 +76,20 @@ test_expect_success 'rebase commit with diff in message' '
        test_cmp G G0
 '
 
        test_cmp G G0
 '
 
+test_expect_success 'rebase -m commit with empty message' '
+       test_must_fail git rebase -m master empty-message-merge &&
+       git rebase --abort &&
+       git rebase -m --allow-empty-message master empty-message-merge
+'
+
+test_expect_success 'rebase -i commit with empty message' '
+       git checkout diff-in-message &&
+       set_fake_editor &&
+       test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+               git rebase -i HEAD^ &&
+       git rebase --abort &&
+       FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+               git rebase -i --allow-empty-message HEAD^
+'
+
 test_done
 test_done