Skip to content

Commit 4c063c8

Browse files
phillipwoodgitster
authored andcommitted
rebase -i: improve error message when picking merge
The only todo commands that accept a merge commit are "merge" and "reset". All the other commands like "pick" or "reword" fail when they try to pick a a merge commit and print the message error: commit abc123 is a merge but no -m option was given. followed by a hint about the command being rescheduled. This message is designed to help the user when they cherry-pick a merge and forget to pass "-m". For users who are rebasing the message is confusing as there is no way for rebase to cherry-pick the merge. Improve the user experience by detecting the error and printing some advice on how to fix it when the todo list is parsed rather than waiting for the "pick" command to fail. The advice recommends "merge" rather than "exec git cherry-pick -m ..." on the assumption that cherry-picking merges is relatively rare and it is more likely that the user chose "pick" by a mistake. It would be possible to support cherry-picking merges by allowing the user to pass "-m" to "pick" commands but that adds complexity to do something that can already be achieved with exec git cherry-pick -m1 abc123 Reported-by: Stefan Haller <[email protected]> Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0c26738 commit 4c063c8

File tree

5 files changed

+110
-2
lines changed

5 files changed

+110
-2
lines changed

Documentation/config/advice.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ advice.*::
9696
`pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`,
9797
`pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate`
9898
simultaneously.
99+
rebaseTodoError::
100+
Shown when there is an error after editing the rebase todo list.
99101
refSyntax::
100102
Shown when the user provides an illegal ref name, to
101103
tell the user about the ref syntax documentation.

advice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ static struct {
6969
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
7070
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
7171
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
72+
[ADVICE_REBASE_TODO_ERROR] = { "rebaseTodoError" },
7273
[ADVICE_REF_SYNTAX] = { "refSyntax" },
7374
[ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
7475
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum advice_type {
3737
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
3838
ADVICE_PUSH_UPDATE_REJECTED,
3939
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
40+
ADVICE_REBASE_TODO_ERROR,
4041
ADVICE_REF_SYNTAX,
4142
ADVICE_RESET_NO_REFRESH_WARNING,
4243
ADVICE_RESOLVE_CONFLICT,

sequencer.c

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2573,7 +2573,61 @@ static int check_label_or_ref_arg(enum todo_command command, const char *arg)
25732573
return 0;
25742574
}
25752575

2576-
static int parse_insn_line(struct repository *r, struct replay_opts *opts UNUSED,
2576+
static int check_merge_commit_insn(enum todo_command command)
2577+
{
2578+
switch(command) {
2579+
case TODO_PICK:
2580+
error(_("'%s' does not accept merge commits"),
2581+
todo_command_info[command].str);
2582+
advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
2583+
/*
2584+
* TRANSLATORS: 'pick' and 'merge -C' should not be
2585+
* translated.
2586+
*/
2587+
"'pick' does not take a merge commit. If you wanted to\n"
2588+
"replay the merge, use 'merge -C' on the commit."));
2589+
return -1;
2590+
2591+
case TODO_REWORD:
2592+
error(_("'%s' does not accept merge commits"),
2593+
todo_command_info[command].str);
2594+
advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
2595+
/*
2596+
* TRANSLATORS: 'reword' and 'merge -c' should not be
2597+
* translated.
2598+
*/
2599+
"'reword' does not take a merge commit. If you wanted to\n"
2600+
"replay the merge and reword the commit message, use\n"
2601+
"'merge -c' on the commit"));
2602+
return -1;
2603+
2604+
case TODO_EDIT:
2605+
error(_("'%s' does not accept merge commits"),
2606+
todo_command_info[command].str);
2607+
advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
2608+
/*
2609+
* TRANSLATORS: 'edit', 'merge -C' and 'break' should
2610+
* not be translated.
2611+
*/
2612+
"'edit' does not take a merge commit. If you wanted to\n"
2613+
"replay the merge, use 'merge -C' on the commit, and then\n"
2614+
"'break' to give the control back to you so that you can\n"
2615+
"do 'git commit --amend && git rebase --continue'."));
2616+
return -1;
2617+
2618+
case TODO_FIXUP:
2619+
case TODO_SQUASH:
2620+
return error(_("cannot squash merge commit into another commit"));
2621+
2622+
case TODO_MERGE:
2623+
return 0;
2624+
2625+
default:
2626+
BUG("unexpected todo_command");
2627+
}
2628+
}
2629+
2630+
static int parse_insn_line(struct repository *r, struct replay_opts *opts,
25772631
struct todo_item *item, const char *buf,
25782632
const char *bol, char *eol)
25792633
{
@@ -2679,7 +2733,12 @@ static int parse_insn_line(struct repository *r, struct replay_opts *opts UNUSED
26792733
return status;
26802734

26812735
item->commit = lookup_commit_reference(r, &commit_oid);
2682-
return item->commit ? 0 : -1;
2736+
if (!item->commit)
2737+
return -1;
2738+
if (is_rebase_i(opts) &&
2739+
item->commit->parents && item->commit->parents->next)
2740+
return check_merge_commit_insn(item->command);
2741+
return 0;
26832742
}
26842743

26852744
int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action)

t/t3404-rebase-interactive.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,51 @@ test_expect_success 'bad labels and refs rejected when parsing todo list' '
22152215
test_path_is_missing execed
22162216
'
22172217

2218+
test_expect_success 'non-merge commands reject merge commits' '
2219+
test_when_finished "test_might_fail git rebase --abort" &&
2220+
git checkout E &&
2221+
git merge I &&
2222+
oid=$(git rev-parse HEAD) &&
2223+
cat >todo <<-EOF &&
2224+
pick $oid
2225+
reword $oid
2226+
edit $oid
2227+
fixup $oid
2228+
squash $oid
2229+
EOF
2230+
(
2231+
set_replace_editor todo &&
2232+
test_must_fail git rebase -i HEAD 2>actual
2233+
) &&
2234+
cat >expect <<-EOF &&
2235+
error: ${SQ}pick${SQ} does not accept merge commits
2236+
hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to
2237+
hint: replay the merge, use ${SQ}merge -C${SQ} on the commit.
2238+
hint: Disable this message with "git config advice.rebaseTodoError false"
2239+
error: invalid line 1: pick $oid
2240+
error: ${SQ}reword${SQ} does not accept merge commits
2241+
hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to
2242+
hint: replay the merge and reword the commit message, use
2243+
hint: ${SQ}merge -c${SQ} on the commit
2244+
hint: Disable this message with "git config advice.rebaseTodoError false"
2245+
error: invalid line 2: reword $oid
2246+
error: ${SQ}edit${SQ} does not accept merge commits
2247+
hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to
2248+
hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then
2249+
hint: ${SQ}break${SQ} to give the control back to you so that you can
2250+
hint: do ${SQ}git commit --amend && git rebase --continue${SQ}.
2251+
hint: Disable this message with "git config advice.rebaseTodoError false"
2252+
error: invalid line 3: edit $oid
2253+
error: cannot squash merge commit into another commit
2254+
error: invalid line 4: fixup $oid
2255+
error: cannot squash merge commit into another commit
2256+
error: invalid line 5: squash $oid
2257+
You can fix this with ${SQ}git rebase --edit-todo${SQ} and then run ${SQ}git rebase --continue${SQ}.
2258+
Or you can abort the rebase with ${SQ}git rebase --abort${SQ}.
2259+
EOF
2260+
test_cmp expect actual
2261+
'
2262+
22182263
# This must be the last test in this file
22192264
test_expect_success '$EDITOR and friends are unchanged' '
22202265
test_editor_unchanged

0 commit comments

Comments
 (0)