Skip to content

Commit 8645ce7

Browse files
committed
Merge branch 'tk/cherry-pick-sequence-requires-clean-worktree' into jch
"git cherry-pick A" that replays a single commit stopped before clobbering local modification, but "git cherry-pick A..B" did not, which has been corrected. * tk/cherry-pick-sequence-requires-clean-worktree: cherry-pick: refuse cherry-pick sequence if index is dirty
2 parents aa511d8 + fe9cfdb commit 8645ce7

File tree

4 files changed

+94
-35
lines changed

4 files changed

+94
-35
lines changed

sequencer.c

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,38 +3199,48 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
31993199
return 0;
32003200
}
32013201

3202-
static int create_seq_dir(struct repository *r)
3202+
static const char *cherry_pick_action_name(enum replay_action action) {
3203+
switch (action) {
3204+
case REPLAY_REVERT:
3205+
return "revert";
3206+
break;
3207+
case REPLAY_PICK:
3208+
return "cherry-pick";
3209+
break;
3210+
default:
3211+
BUG("unexpected action in cherry_pick_action_name");
3212+
}
3213+
}
3214+
3215+
static int create_seq_dir(struct repository *r, enum replay_action requested_action)
32033216
{
3204-
enum replay_action action;
3217+
enum replay_action in_progress_action;
3218+
const char *in_progress_action_name = NULL;
32053219
const char *in_progress_error = NULL;
32063220
const char *in_progress_advice = NULL;
3221+
const char *requested_action_name = NULL;
32073222
unsigned int advise_skip =
32083223
refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
32093224
refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");
32103225

3211-
if (!sequencer_get_last_command(r, &action)) {
3212-
switch (action) {
3213-
case REPLAY_REVERT:
3214-
in_progress_error = _("revert is already in progress");
3215-
in_progress_advice =
3216-
_("try \"git revert (--continue | %s--abort | --quit)\"");
3217-
break;
3218-
case REPLAY_PICK:
3219-
in_progress_error = _("cherry-pick is already in progress");
3220-
in_progress_advice =
3221-
_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
3222-
break;
3223-
default:
3224-
BUG("unexpected action in create_seq_dir");
3225-
}
3226+
if (!sequencer_get_last_command(r, &in_progress_action)) {
3227+
in_progress_action_name = cherry_pick_action_name(in_progress_action);
3228+
in_progress_error = _("%s is already in progress");
3229+
in_progress_advice =
3230+
_("try \"git %s (--continue | %s--abort | --quit)\"");
32263231
}
32273232
if (in_progress_error) {
3228-
error("%s", in_progress_error);
3233+
error(in_progress_error, in_progress_action_name);
32293234
if (advice_enabled(ADVICE_SEQUENCER_IN_USE))
32303235
advise(in_progress_advice,
3236+
in_progress_action_name,
32313237
advise_skip ? "--skip | " : "");
32323238
return -1;
32333239
}
3240+
requested_action_name = cherry_pick_action_name(requested_action);
3241+
if (require_clean_index(r, requested_action_name,
3242+
_("Please commit or stash them."), 1, 1))
3243+
return -1;
32343244
if (mkdir(git_path_seq_dir(), 0777) < 0)
32353245
return error_errno(_("could not create sequencer directory '%s'"),
32363246
git_path_seq_dir());
@@ -5279,12 +5289,11 @@ int sequencer_pick_revisions(struct repository *r,
52795289

52805290
/*
52815291
* Start a new cherry-pick/ revert sequence; but
5282-
* first, make sure that an existing one isn't in
5283-
* progress
5292+
* first, make sure that the index is clean and that
5293+
* an existing one isn't in progress.
52845294
*/
5285-
52865295
if (walk_revs_populate_todo(&todo_list, opts) ||
5287-
create_seq_dir(r) < 0)
5296+
create_seq_dir(r, opts->action) < 0)
52885297
return -1;
52895298
if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
52905299
return error(_("can't revert as initial commit"));

t/t3510-cherry-pick-sequence.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ test_expect_success 'cherry-pick persists data on failure' '
4747
test_path_is_file .git/sequencer/opts
4848
'
4949

50+
test_expect_success 'cherry-pick sequence refuses to run on dirty index' '
51+
pristine_detach initial &&
52+
touch localindexchange &&
53+
git add localindexchange &&
54+
echo picking &&
55+
test_must_fail git cherry-pick initial..picked &&
56+
test_path_is_missing .git/sequencer &&
57+
test_must_fail git cherry-pick --abort
58+
'
59+
5060
test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
5161
pristine_detach initial &&
5262
test_must_fail git cherry-pick base..anotherpick &&

wt-status.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,15 +2620,12 @@ int has_uncommitted_changes(struct repository *r,
26202620
return result;
26212621
}
26222622

2623-
/**
2624-
* If the work tree has unstaged or uncommitted changes, dies with the
2625-
* appropriate message.
2626-
*/
2627-
int require_clean_work_tree(struct repository *r,
2628-
const char *action,
2629-
const char *hint,
2630-
int ignore_submodules,
2631-
int gently)
2623+
static int require_clean_index_or_work_tree(struct repository *r,
2624+
const char *action,
2625+
const char *hint,
2626+
int ignore_submodules,
2627+
int check_index_only,
2628+
int gently)
26322629
{
26332630
struct lock_file lock_file = LOCK_INIT;
26342631
int err = 0, fd;
@@ -2639,10 +2636,12 @@ int require_clean_work_tree(struct repository *r,
26392636
repo_update_index_if_able(r, &lock_file);
26402637
rollback_lock_file(&lock_file);
26412638

2642-
if (has_unstaged_changes(r, ignore_submodules)) {
2643-
/* TRANSLATORS: the action is e.g. "pull with rebase" */
2644-
error(_("cannot %s: You have unstaged changes."), _(action));
2645-
err = 1;
2639+
if (!check_index_only) {
2640+
if (has_unstaged_changes(r, ignore_submodules)) {
2641+
/* TRANSLATORS: the action is e.g. "pull with rebase" */
2642+
error(_("cannot %s: You have unstaged changes."), _(action));
2643+
err = 1;
2644+
}
26462645
}
26472646

26482647
if (has_uncommitted_changes(r, ignore_submodules)) {
@@ -2667,3 +2666,39 @@ int require_clean_work_tree(struct repository *r,
26672666

26682667
return err;
26692668
}
2669+
2670+
/**
2671+
* If the work tree has unstaged or uncommitted changes, dies with the
2672+
* appropriate message.
2673+
*/
2674+
int require_clean_work_tree(struct repository *r,
2675+
const char *action,
2676+
const char *hint,
2677+
int ignore_submodules,
2678+
int gently)
2679+
{
2680+
return require_clean_index_or_work_tree(r,
2681+
action,
2682+
hint,
2683+
ignore_submodules,
2684+
0,
2685+
gently);
2686+
}
2687+
2688+
/**
2689+
* If the work tree has uncommitted changes, dies with the appropriate
2690+
* message.
2691+
*/
2692+
int require_clean_index(struct repository *r,
2693+
const char *action,
2694+
const char *hint,
2695+
int ignore_submodules,
2696+
int gently)
2697+
{
2698+
return require_clean_index_or_work_tree(r,
2699+
action,
2700+
hint,
2701+
ignore_submodules,
2702+
1,
2703+
gently);
2704+
}

wt-status.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,10 @@ int require_clean_work_tree(struct repository *repo,
181181
const char *hint,
182182
int ignore_submodules,
183183
int gently);
184+
int require_clean_index(struct repository *repo,
185+
const char *action,
186+
const char *hint,
187+
int ignore_submodules,
188+
int gently);
184189

185190
#endif /* STATUS_H */

0 commit comments

Comments
 (0)