Skip to content

Commit ed22530

Browse files
committed
cherry-pick: refuse cherry-pick sequence if index is dirty
Cherry-pick, like merge or rebase, refuses to run when there are changes in the index. However, if a cherry-pick sequence is requested, this refusal happens "too late": when the cherry-pick sequence has already started, and an "--abort" or "--quit" is needed to resume normal operation. Normally, when an operation is "in-progress" and you want to go back to where you were before, "--abort" is the right thing to run. If you run "git cherry-pick --abort" in this specific situation, however, your staged changes are destroyed as part of the abort! Generally speaking, the abort process assumes any changes in the index are part of the operation to be aborted. Add an earlier check in the cherry-pick sequence process to ensure that the index is clean, reusing the already-generalized method used for rebase. Also add a test. Signed-off-by: Tao Klerks <[email protected]>
1 parent 4a714b3 commit ed22530

File tree

4 files changed

+22
-7
lines changed

4 files changed

+22
-7
lines changed

builtin/revert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
224224
return sequencer_rollback(the_repository, opts);
225225
if (cmd == 's')
226226
return sequencer_skip(the_repository, opts);
227-
return sequencer_pick_revisions(the_repository, opts);
227+
return sequencer_pick_revisions(the_repository, opts, me);
228228
}
229229

230230
int cmd_revert(int argc, const char **argv, const char *prefix)

sequencer.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,7 +3162,7 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
31623162
return 0;
31633163
}
31643164

3165-
static int create_seq_dir(struct repository *r)
3165+
static int create_seq_dir(struct repository *r, const char *requested_action)
31663166
{
31673167
enum replay_action action;
31683168
const char *in_progress_error = NULL;
@@ -3194,6 +3194,9 @@ static int create_seq_dir(struct repository *r)
31943194
advise_skip ? "--skip | " : "");
31953195
return -1;
31963196
}
3197+
if (require_clean_work_tree(r, requested_action,
3198+
_("Please commit or stash them."), 1, 1))
3199+
return -1;
31973200
if (mkdir(git_path_seq_dir(), 0777) < 0)
31983201
return error_errno(_("could not create sequencer directory '%s'"),
31993202
git_path_seq_dir());
@@ -5169,7 +5172,8 @@ static int single_pick(struct repository *r,
51695172
}
51705173

51715174
int sequencer_pick_revisions(struct repository *r,
5172-
struct replay_opts *opts)
5175+
struct replay_opts *opts,
5176+
const char *action)
51735177
{
51745178
struct todo_list todo_list = TODO_LIST_INIT;
51755179
struct object_id oid;
@@ -5223,12 +5227,12 @@ int sequencer_pick_revisions(struct repository *r,
52235227

52245228
/*
52255229
* Start a new cherry-pick/ revert sequence; but
5226-
* first, make sure that an existing one isn't in
5227-
* progress
5230+
* first, make sure that the index is clean and that
5231+
* an existing one isn't in progress.
52285232
*/
52295233

52305234
if (walk_revs_populate_todo(&todo_list, opts) ||
5231-
create_seq_dir(r) < 0)
5235+
create_seq_dir(r, action) < 0)
52325236
return -1;
52335237
if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
52345238
return error(_("can't revert as initial commit"));

sequencer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ void todo_list_filter_update_refs(struct repository *r,
159159
/* Call this to setup defaults before parsing command line options */
160160
void sequencer_init_config(struct replay_opts *opts);
161161
int sequencer_pick_revisions(struct repository *repo,
162-
struct replay_opts *opts);
162+
struct replay_opts *opts,
163+
const char *action);
163164
int sequencer_continue(struct repository *repo, struct replay_opts *opts);
164165
int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
165166
int sequencer_skip(struct repository *repo, struct replay_opts *opts);

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 &&

0 commit comments

Comments
 (0)