Skip to content

Commit 430b75f

Browse files
phillipwoodgitster
authored andcommitted
commit: give correct advice for empty commit during a rebase
In dcb500d (cherry-pick/revert: advise using --skip, 2019-07-02), `git commit` learned to suggest to run `git cherry-pick --skip` when trying to cherry-pick an empty patch. However, it was overlooked that there are more conditions than just a `git cherry-pick` when this advice is printed (which originally suggested the neutral `git reset`): the same can happen during a rebase. Let's suggest the correct command, even during a rebase. While at it, we adjust more places in `builtin/commit.c` that incorrectly assumed that the presence of a `CHERRY_PICK_HEAD` meant that surely this must be a `cherry-pick` in progress. Note: we take pains to handle the situation when a user runs a `git cherry-pick` _during_ a rebase. This is quite valid (e.g. in an `exec` line in an interactive rebase). On the other hand, it is not possible to run a rebase during a cherry-pick, meaning: if both `rebase-merge/` and `sequencer/` exist or CHERRY_PICK_HEAD and REBASE_HEAD point to the same commit , we still want to advise to use `git cherry-pick --skip`. Original-patch-by: Johannes Schindelin <[email protected]> Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 901ba7b commit 430b75f

File tree

5 files changed

+114
-19
lines changed

5 files changed

+114
-19
lines changed

builtin/commit.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
5959
" git commit --allow-empty\n"
6060
"\n");
6161

62+
static const char empty_rebase_pick_advice[] =
63+
N_("Otherwise, please use 'git rebase --skip'\n");
64+
6265
static const char empty_cherry_pick_advice_single[] =
6366
N_("Otherwise, please use 'git cherry-pick --skip'\n");
6467

@@ -449,6 +452,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
449452
die(_("cannot do a partial commit during a merge."));
450453
else if (is_from_cherry_pick(whence))
451454
die(_("cannot do a partial commit during a cherry-pick."));
455+
else if (is_from_rebase(whence))
456+
die(_("cannot do a partial commit during a rebase."));
452457
}
453458

454459
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
@@ -765,7 +770,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
765770
*/
766771
else if (whence == FROM_MERGE)
767772
hook_arg1 = "merge";
768-
else if (is_from_cherry_pick(whence)) {
773+
else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) {
769774
hook_arg1 = "commit";
770775
hook_arg2 = "CHERRY_PICK_HEAD";
771776
}
@@ -942,12 +947,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
942947
run_status(stdout, index_file, prefix, 0, s);
943948
if (amend)
944949
fputs(_(empty_amend_advice), stderr);
945-
else if (is_from_cherry_pick(whence)) {
950+
else if (is_from_cherry_pick(whence) ||
951+
whence == FROM_REBASE_PICK) {
946952
fputs(_(empty_cherry_pick_advice), stderr);
947953
if (whence == FROM_CHERRY_PICK_SINGLE)
948954
fputs(_(empty_cherry_pick_advice_single), stderr);
949-
else
955+
else if (whence == FROM_CHERRY_PICK_MULTI)
950956
fputs(_(empty_cherry_pick_advice_multi), stderr);
957+
else
958+
fputs(_(empty_rebase_pick_advice), stderr);
951959
}
952960
return 0;
953961
}
@@ -1152,6 +1160,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
11521160
die(_("You are in the middle of a merge -- cannot amend."));
11531161
else if (is_from_cherry_pick(whence))
11541162
die(_("You are in the middle of a cherry-pick -- cannot amend."));
1163+
else if (whence == FROM_REBASE_PICK)
1164+
die(_("You are in the middle of a rebase -- cannot amend."));
11551165
}
11561166
if (fixup_message && squash_message)
11571167
die(_("Options --squash and --fixup cannot be used together"));
@@ -1173,7 +1183,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
11731183
use_message = edit_message;
11741184
if (amend && !use_message && !fixup_message)
11751185
use_message = "HEAD";
1176-
if (!use_message && !is_from_cherry_pick(whence) && renew_authorship)
1186+
if (!use_message && !is_from_cherry_pick(whence) &&
1187+
!is_from_rebase(whence) && renew_authorship)
11771188
die(_("--reset-author can be used only with -C, -c or --amend."));
11781189
if (use_message) {
11791190
use_message_buffer = read_commit_message(use_message);
@@ -1182,7 +1193,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
11821193
author_message_buffer = use_message_buffer;
11831194
}
11841195
}
1185-
if (is_from_cherry_pick(whence) && !renew_authorship) {
1196+
if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) &&
1197+
!renew_authorship) {
11861198
author_message = "CHERRY_PICK_HEAD";
11871199
author_message_buffer = read_commit_message(author_message);
11881200
}
@@ -1602,6 +1614,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
16021614
if (!reflog_msg)
16031615
reflog_msg = is_from_cherry_pick(whence)
16041616
? "commit (cherry-pick)"
1617+
: is_from_rebase(whence)
1618+
? "commit (rebase)"
16051619
: "commit";
16061620
commit_list_insert(current_head, &parents);
16071621
}

sequencer.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,9 +1429,19 @@ static int try_to_commit(struct repository *r,
14291429
return res;
14301430
}
14311431

1432+
static int write_rebase_head(struct object_id *oid)
1433+
{
1434+
if (update_ref("rebase", "REBASE_HEAD", oid,
1435+
NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
1436+
return error(_("could not update %s"), "REBASE_HEAD");
1437+
1438+
return 0;
1439+
}
1440+
14321441
static int do_commit(struct repository *r,
14331442
const char *msg_file, const char *author,
1434-
struct replay_opts *opts, unsigned int flags)
1443+
struct replay_opts *opts, unsigned int flags,
1444+
struct object_id *oid)
14351445
{
14361446
int res = 1;
14371447

@@ -1456,8 +1466,12 @@ static int do_commit(struct repository *r,
14561466
return res;
14571467
}
14581468
}
1459-
if (res == 1)
1469+
if (res == 1) {
1470+
if (is_rebase_i(opts) && oid)
1471+
if (write_rebase_head(oid))
1472+
return -1;
14601473
return run_git_commit(r, msg_file, opts, flags);
1474+
}
14611475

14621476
return res;
14631477
}
@@ -1945,7 +1959,8 @@ static int do_pick_commit(struct repository *r,
19451959
flags |= ALLOW_EMPTY;
19461960
if (!opts->no_commit) {
19471961
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
1948-
res = do_commit(r, msg_file, author, opts, flags);
1962+
res = do_commit(r, msg_file, author, opts, flags,
1963+
commit? &commit->object.oid : NULL);
19491964
else
19501965
res = error(_("unable to parse commit author"));
19511966
*check_todo = !!(flags & EDIT_MSG);
@@ -2964,9 +2979,7 @@ static int make_patch(struct repository *r,
29642979
p = short_commit_name(commit);
29652980
if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
29662981
return -1;
2967-
if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
2968-
NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
2969-
res |= error(_("could not update %s"), "REBASE_HEAD");
2982+
res |= write_rebase_head(&commit->object.oid);
29702983

29712984
strbuf_addf(&buf, "%s/patch", get_dir(opts));
29722985
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
@@ -5316,8 +5329,18 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
53165329
int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
53175330
{
53185331
if (file_exists(git_path_cherry_pick_head(r))) {
5319-
*whence = file_exists(git_path_seq_dir()) ?
5320-
FROM_CHERRY_PICK_MULTI : FROM_CHERRY_PICK_SINGLE;
5332+
struct object_id cherry_pick_head, rebase_head;
5333+
5334+
if (file_exists(git_path_seq_dir()))
5335+
*whence = FROM_CHERRY_PICK_MULTI;
5336+
if (file_exists(rebase_path()) &&
5337+
!get_oid("REBASE_HEAD", &rebase_head) &&
5338+
!get_oid("CHERRY_PICK_HEAD", &cherry_pick_head) &&
5339+
oideq(&rebase_head, &cherry_pick_head))
5340+
*whence = FROM_REBASE_PICK;
5341+
else
5342+
*whence = FROM_CHERRY_PICK_SINGLE;
5343+
53215344
return 1;
53225345
}
53235346

t/t3403-rebase-skip.sh

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ test_expect_success 'correct advice upon picking empty commit' '
9797
test_must_fail git rebase -i --onto goodbye \
9898
amended-goodbye^ amended-goodbye 2>err &&
9999
test_i18ngrep "previous cherry-pick is now empty" err &&
100-
test_i18ngrep "git cherry-pick --skip" err &&
100+
test_i18ngrep "git rebase --skip" err &&
101101
test_must_fail git commit &&
102-
test_i18ngrep "git cherry-pick --skip" err
102+
test_i18ngrep "git rebase --skip" err
103103
'
104104

105105
test_expect_success 'correct authorship when committing empty pick' '
@@ -120,9 +120,9 @@ test_expect_success 'correct advice upon rewording empty commit' '
120120
--onto goodbye amended-goodbye^ amended-goodbye 2>err
121121
) &&
122122
test_i18ngrep "previous cherry-pick is now empty" err &&
123-
test_i18ngrep "git cherry-pick --skip" err &&
123+
test_i18ngrep "git rebase --skip" err &&
124124
test_must_fail git commit &&
125-
test_i18ngrep "git cherry-pick --skip" err
125+
test_i18ngrep "git rebase --skip" err
126126
'
127127

128128
test_expect_success 'correct advice upon editing empty commit' '
@@ -133,8 +133,34 @@ test_expect_success 'correct advice upon editing empty commit' '
133133
--onto goodbye amended-goodbye^ amended-goodbye 2>err
134134
) &&
135135
test_i18ngrep "previous cherry-pick is now empty" err &&
136-
test_i18ngrep "git cherry-pick --skip" err &&
136+
test_i18ngrep "git rebase --skip" err &&
137137
test_must_fail git commit &&
138+
test_i18ngrep "git rebase --skip" err
139+
'
140+
141+
test_expect_success 'correct advice upon cherry-picking an empty commit during a rebase' '
142+
test_when_finished "git rebase --abort" &&
143+
(
144+
set_fake_editor &&
145+
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_amended-goodbye" \
146+
git rebase -i goodbye^ goodbye 2>err
147+
) &&
148+
test_i18ngrep "previous cherry-pick is now empty" err &&
149+
test_i18ngrep "git cherry-pick --skip" err &&
150+
test_must_fail git commit 2>err &&
151+
test_i18ngrep "git cherry-pick --skip" err
152+
'
153+
154+
test_expect_success 'correct advice upon multi cherry-pick picking an empty commit during a rebase' '
155+
test_when_finished "git rebase --abort" &&
156+
(
157+
set_fake_editor &&
158+
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_goodbye_amended-goodbye" \
159+
git rebase -i goodbye^^ goodbye 2>err
160+
) &&
161+
test_i18ngrep "previous cherry-pick is now empty" err &&
162+
test_i18ngrep "git cherry-pick --skip" err &&
163+
test_must_fail git commit 2>err &&
138164
test_i18ngrep "git cherry-pick --skip" err
139165
'
140166

t/t3404-rebase-interactive.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,32 @@ test_expect_success 'post-commit hook is called' '
15991599
test_cmp expect actual
16001600
'
16011601

1602+
test_expect_success 'correct error message for partial commit after empty pick' '
1603+
test_when_finished "git rebase --abort" &&
1604+
(
1605+
set_fake_editor &&
1606+
FAKE_LINES="2 1 1" &&
1607+
export FAKE_LINES &&
1608+
test_must_fail git rebase -i A D
1609+
) &&
1610+
echo x >file1 &&
1611+
test_must_fail git commit file1 2>err &&
1612+
test_i18ngrep "cannot do a partial commit during a rebase." err
1613+
'
1614+
1615+
test_expect_success 'correct error message for commit --amend after empty pick' '
1616+
test_when_finished "git rebase --abort" &&
1617+
(
1618+
set_fake_editor &&
1619+
FAKE_LINES="1 1" &&
1620+
export FAKE_LINES &&
1621+
test_must_fail git rebase -i A D
1622+
) &&
1623+
echo x>file1 &&
1624+
test_must_fail git commit -a --amend 2>err &&
1625+
test_i18ngrep "middle of a rebase -- cannot amend." err
1626+
'
1627+
16021628
# This must be the last test in this file
16031629
test_expect_success '$EDITOR and friends are unchanged' '
16041630
test_editor_unchanged

wt-status.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ enum commit_whence {
3939
FROM_COMMIT, /* normal */
4040
FROM_MERGE, /* commit came from merge */
4141
FROM_CHERRY_PICK_SINGLE, /* commit came from cherry-pick */
42-
FROM_CHERRY_PICK_MULTI /* commit came from a sequence of cherry-picks */
42+
FROM_CHERRY_PICK_MULTI, /* commit came from a sequence of cherry-picks */
43+
FROM_REBASE_PICK /* commit came from a pick/reword/edit */
4344
};
4445

4546
static inline int is_from_cherry_pick(enum commit_whence whence)
@@ -48,6 +49,11 @@ static inline int is_from_cherry_pick(enum commit_whence whence)
4849
whence == FROM_CHERRY_PICK_MULTI;
4950
}
5051

52+
static inline int is_from_rebase(enum commit_whence whence)
53+
{
54+
return whence == FROM_REBASE_PICK;
55+
}
56+
5157
struct wt_status_change_data {
5258
int worktree_status;
5359
int index_status;

0 commit comments

Comments
 (0)