sequencer: fix --allow-empty-message behavior, make it smarter

In commit b00bf1c9a8 ("git-rebase: make --allow-empty-message the
default", 2018-06-27), several arguments were given for transplanting
empty commits without halting and asking the user for confirmation on
each commit.  These arguments were incomplete because the logic clearly
assumed the only cases under consideration were transplanting of commits
with empty messages (see the comment about "There are two sources for
commits with empty messages).  It didn't discuss or even consider
rewords, squashes, etc. where the user is explicitly asked for a new
commit message and provides an empty one.  (My bad, I totally should
have thought about that at the time, but just didn't.)

Rewords and squashes are significantly different, though, as described
by SZEDER:

    Let's suppose you start an interactive rebase, choose a commit to
    squash, save the instruction sheet, rebase fires up your editor, and
    then you notice that you mistakenly chose the wrong commit to
    squash.  What do you do, how do you abort?

    Before [that commit] you could clear the commit message, exit the
    editor, and then rebase would say "Aborting commit due to empty
    commit message.", and you get to run 'git rebase --abort', and start
    over.

    But [since that commit, ...] saving the commit message as is would
    let rebase continue and create a bunch of unnecessary objects, and
    then you would have to use the reflog to return to the pre-rebase
    state.

Also, he states:

    The instructions in the commit message template, which is shown for
    'reword' and 'squash', too, still say...

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.

These are sound arguments that when editing commit messages during a
sequencer operation, that if the commit message is empty then the
operation should halt and ask the user to correct.  The arguments in
commit b00bf1c9a8 (referenced above) still apply when transplanting
previously created commits with empty commit messages, so the sequencer
should not halt for those.

Furthermore, all rationale so far applies equally for cherry-pick as for
rebase.  Therefore, make the code default to --allow-empty-message when
transplanting an existing commit, and to default to halting when the
user is asked to edit a commit message and provides an empty one -- for
both rebase and cherry-pick.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Elijah Newren 2018-09-12 14:18:48 -07:00 committed by Junio C Hamano
parent b00bf1c9a8
commit a3ec9eaf38
4 changed files with 14 additions and 17 deletions

View File

@ -858,7 +858,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
if ((flags & ALLOW_EMPTY)) if ((flags & ALLOW_EMPTY))
argv_array_push(&cmd.args, "--allow-empty"); argv_array_push(&cmd.args, "--allow-empty");
if (opts->allow_empty_message) if (!(flags & EDIT_MSG))
argv_array_push(&cmd.args, "--allow-empty-message"); argv_array_push(&cmd.args, "--allow-empty-message");
if (cmd.err == -1) { if (cmd.err == -1) {
@ -1272,7 +1272,7 @@ static int try_to_commit(struct strbuf *msg, const char *author,
if (cleanup != COMMIT_MSG_CLEANUP_NONE) if (cleanup != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL); strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) { if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */ res = 1; /* run 'git commit' to display error message */
goto out; goto out;
} }

View File

@ -553,16 +553,15 @@ test_expect_success '--continue tries to commit, even for "edit"' '
' '
test_expect_success 'aborted --continue does not squash commits after "edit"' ' test_expect_success 'aborted --continue does not squash commits after "edit"' '
test_when_finished "git rebase --abort" &&
old=$(git rev-parse HEAD) && old=$(git rev-parse HEAD) &&
test_tick && test_tick &&
set_fake_editor && set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ && FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 && echo "edited again" > file7 &&
git add file7 && git add file7 &&
echo all the things >>conflict && test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue &&
test_must_fail git rebase --continue && test $old = $(git rev-parse HEAD) &&
test $old = $(git rev-parse HEAD) git rebase --abort
' '
test_expect_success 'auto-amend only edited commits after "edit"' ' test_expect_success 'auto-amend only edited commits after "edit"' '

View File

@ -83,7 +83,7 @@ test_expect_success 'rebase -m commit with empty message' '
test_expect_success 'rebase -i commit with empty message' ' test_expect_success 'rebase -i commit with empty message' '
git checkout diff-in-message && git checkout diff-in-message &&
set_fake_editor && set_fake_editor &&
env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
git rebase -i HEAD^ git rebase -i HEAD^
' '

View File

@ -11,17 +11,14 @@ test_expect_success setup '
test_tick && test_tick &&
git commit -m "first" && git commit -m "first" &&
git checkout -b empty-branch && git checkout -b empty-message-branch &&
test_tick &&
git commit --allow-empty -m "empty" &&
echo third >> file1 && echo third >> file1 &&
git add file1 && git add file1 &&
test_tick && test_tick &&
git commit --allow-empty-message -m "" && git commit --allow-empty-message -m "" &&
git checkout master && git checkout master &&
git checkout -b empty-branch2 && git checkout -b empty-change-branch &&
test_tick && test_tick &&
git commit --allow-empty -m "empty" git commit --allow-empty -m "empty"
@ -29,7 +26,7 @@ test_expect_success setup '
test_expect_success 'cherry-pick an empty commit' ' test_expect_success 'cherry-pick an empty commit' '
git checkout master && git checkout master &&
test_expect_code 1 git cherry-pick empty-branch^ test_expect_code 1 git cherry-pick empty-change-branch
' '
test_expect_success 'index lockfile was removed' ' test_expect_success 'index lockfile was removed' '
@ -37,8 +34,9 @@ test_expect_success 'index lockfile was removed' '
' '
test_expect_success 'cherry-pick a commit with an empty message' ' test_expect_success 'cherry-pick a commit with an empty message' '
test_when_finished "git reset --hard empty-message-branch~1" &&
git checkout master && git checkout master &&
test_expect_code 1 git cherry-pick empty-branch git cherry-pick empty-message-branch
' '
test_expect_success 'index lockfile was removed' ' test_expect_success 'index lockfile was removed' '
@ -47,7 +45,7 @@ test_expect_success 'index lockfile was removed' '
test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' ' test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
git checkout -f master && git checkout -f master &&
git cherry-pick --allow-empty-message empty-branch git cherry-pick --allow-empty-message empty-message-branch
' '
test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' ' test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
@ -55,12 +53,12 @@ test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
echo fourth >>file2 && echo fourth >>file2 &&
git add file2 && git add file2 &&
git commit -m "fourth" && git commit -m "fourth" &&
test_must_fail git cherry-pick empty-branch2 test_must_fail git cherry-pick empty-change-branch
' '
test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' ' test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
git checkout master && git checkout master &&
git cherry-pick --allow-empty empty-branch2 git cherry-pick --allow-empty empty-change-branch
' '
test_expect_success 'cherry pick with --keep-redundant-commits' ' test_expect_success 'cherry pick with --keep-redundant-commits' '