Skip to content

Commit

Permalink
Merge branch 'tk/cherry-pick-sequence-requires-clean-worktree' into jch
Browse files Browse the repository at this point in the history
"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
  • Loading branch information
gitster committed Jun 13, 2023
2 parents 858bc9e + fe9cfdb commit a595a9e
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 35 deletions.
53 changes: 31 additions & 22 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -3171,38 +3171,48 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
return 0;
}

static int create_seq_dir(struct repository *r)
static const char *cherry_pick_action_name(enum replay_action action) {
switch (action) {
case REPLAY_REVERT:
return "revert";
break;
case REPLAY_PICK:
return "cherry-pick";
break;
default:
BUG("unexpected action in cherry_pick_action_name");
}
}

static int create_seq_dir(struct repository *r, enum replay_action requested_action)
{
enum replay_action action;
enum replay_action in_progress_action;
const char *in_progress_action_name = NULL;
const char *in_progress_error = NULL;
const char *in_progress_advice = NULL;
const char *requested_action_name = NULL;
unsigned int advise_skip =
refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");

if (!sequencer_get_last_command(r, &action)) {
switch (action) {
case REPLAY_REVERT:
in_progress_error = _("revert is already in progress");
in_progress_advice =
_("try \"git revert (--continue | %s--abort | --quit)\"");
break;
case REPLAY_PICK:
in_progress_error = _("cherry-pick is already in progress");
in_progress_advice =
_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
break;
default:
BUG("unexpected action in create_seq_dir");
}
if (!sequencer_get_last_command(r, &in_progress_action)) {
in_progress_action_name = cherry_pick_action_name(in_progress_action);
in_progress_error = _("%s is already in progress");
in_progress_advice =
_("try \"git %s (--continue | %s--abort | --quit)\"");
}
if (in_progress_error) {
error("%s", in_progress_error);
error(in_progress_error, in_progress_action_name);
if (advice_enabled(ADVICE_SEQUENCER_IN_USE))
advise(in_progress_advice,
in_progress_action_name,
advise_skip ? "--skip | " : "");
return -1;
}
requested_action_name = cherry_pick_action_name(requested_action);
if (require_clean_index(r, requested_action_name,
_("Please commit or stash them."), 1, 1))
return -1;
if (mkdir(git_path_seq_dir(), 0777) < 0)
return error_errno(_("could not create sequencer directory '%s'"),
git_path_seq_dir());
Expand Down Expand Up @@ -5238,12 +5248,11 @@ int sequencer_pick_revisions(struct repository *r,

/*
* Start a new cherry-pick/ revert sequence; but
* first, make sure that an existing one isn't in
* progress
* first, make sure that the index is clean and that
* an existing one isn't in progress.
*/

if (walk_revs_populate_todo(&todo_list, opts) ||
create_seq_dir(r) < 0)
create_seq_dir(r, opts->action) < 0)
return -1;
if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
return error(_("can't revert as initial commit"));
Expand Down
10 changes: 10 additions & 0 deletions t/t3510-cherry-pick-sequence.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ test_expect_success 'cherry-pick persists data on failure' '
test_path_is_file .git/sequencer/opts
'

test_expect_success 'cherry-pick sequence refuses to run on dirty index' '
pristine_detach initial &&
touch localindexchange &&
git add localindexchange &&
echo picking &&
test_must_fail git cherry-pick initial..picked &&
test_path_is_missing .git/sequencer &&
test_must_fail git cherry-pick --abort
'

test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
pristine_detach initial &&
test_must_fail git cherry-pick base..anotherpick &&
Expand Down
61 changes: 48 additions & 13 deletions wt-status.c
Original file line number Diff line number Diff line change
Expand Up @@ -2619,15 +2619,12 @@ int has_uncommitted_changes(struct repository *r,
return result;
}

/**
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
int require_clean_work_tree(struct repository *r,
const char *action,
const char *hint,
int ignore_submodules,
int gently)
static int require_clean_index_or_work_tree(struct repository *r,
const char *action,
const char *hint,
int ignore_submodules,
int check_index_only,
int gently)
{
struct lock_file lock_file = LOCK_INIT;
int err = 0, fd;
Expand All @@ -2638,10 +2635,12 @@ int require_clean_work_tree(struct repository *r,
repo_update_index_if_able(r, &lock_file);
rollback_lock_file(&lock_file);

if (has_unstaged_changes(r, ignore_submodules)) {
/* TRANSLATORS: the action is e.g. "pull with rebase" */
error(_("cannot %s: You have unstaged changes."), _(action));
err = 1;
if (!check_index_only) {
if (has_unstaged_changes(r, ignore_submodules)) {
/* TRANSLATORS: the action is e.g. "pull with rebase" */
error(_("cannot %s: You have unstaged changes."), _(action));
err = 1;
}
}

if (has_uncommitted_changes(r, ignore_submodules)) {
Expand All @@ -2662,3 +2661,39 @@ int require_clean_work_tree(struct repository *r,

return err;
}

/**
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
int require_clean_work_tree(struct repository *r,
const char *action,
const char *hint,
int ignore_submodules,
int gently)
{
return require_clean_index_or_work_tree(r,
action,
hint,
ignore_submodules,
0,
gently);
}

/**
* If the work tree has uncommitted changes, dies with the appropriate
* message.
*/
int require_clean_index(struct repository *r,
const char *action,
const char *hint,
int ignore_submodules,
int gently)
{
return require_clean_index_or_work_tree(r,
action,
hint,
ignore_submodules,
1,
gently);
}
5 changes: 5 additions & 0 deletions wt-status.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,10 @@ int require_clean_work_tree(struct repository *repo,
const char *hint,
int ignore_submodules,
int gently);
int require_clean_index(struct repository *repo,
const char *action,
const char *hint,
int ignore_submodules,
int gently);

#endif /* STATUS_H */

0 comments on commit a595a9e

Please sign in to comment.