Skip to content

Commit 770dd00

Browse files
committed
Merge branch 'jn/maint-sequencer-fixes' into maint
* jn/maint-sequencer-fixes: revert: stop creating and removing sequencer-old directory Revert "reset: Make reset remove the sequencer state" revert: do not remove state until sequence is finished revert: allow single-pick in the middle of cherry-pick sequence revert: pass around rev-list args in already-parsed form revert: allow cherry-pick --continue to commit before resuming revert: give --continue handling its own function
2 parents 7fc1495 + d596118 commit 770dd00

File tree

6 files changed

+252
-126
lines changed

6 files changed

+252
-126
lines changed

branch.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include "refs.h"
44
#include "remote.h"
55
#include "commit.h"
6-
#include "sequencer.h"
76

87
struct tracking {
98
struct refspec spec;
@@ -249,5 +248,4 @@ void remove_branch_state(void)
249248
unlink(git_path("MERGE_MSG"));
250249
unlink(git_path("MERGE_MODE"));
251250
unlink(git_path("SQUASH_MSG"));
252-
remove_sequencer_state(0);
253251
}

builtin/revert.c

Lines changed: 92 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,14 @@ struct replay_opts {
6060
int allow_rerere_auto;
6161

6262
int mainline;
63-
int commit_argc;
64-
const char **commit_argv;
6563

6664
/* Merge strategy */
6765
const char *strategy;
6866
const char **xopts;
6967
size_t xopts_nr, xopts_alloc;
68+
69+
/* Only used by REPLAY_NONE */
70+
struct rev_info *revs;
7071
};
7172

7273
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -169,9 +170,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
169170
die(_("program error"));
170171
}
171172

172-
opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
173-
PARSE_OPT_KEEP_ARGV0 |
174-
PARSE_OPT_KEEP_UNKNOWN);
173+
argc = parse_options(argc, argv, NULL, options, usage_str,
174+
PARSE_OPT_KEEP_ARGV0 |
175+
PARSE_OPT_KEEP_UNKNOWN);
175176

176177
/* Check for incompatible subcommands */
177178
verify_opt_mutually_compatible(me,
@@ -213,17 +214,27 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
213214
NULL);
214215
}
215216

216-
else if (opts->commit_argc < 2)
217-
usage_with_options(usage_str, options);
218-
219217
if (opts->allow_ff)
220218
verify_opt_compatible(me, "--ff",
221219
"--signoff", opts->signoff,
222220
"--no-commit", opts->no_commit,
223221
"-x", opts->record_origin,
224222
"--edit", opts->edit,
225223
NULL);
226-
opts->commit_argv = argv;
224+
225+
if (opts->subcommand != REPLAY_NONE) {
226+
opts->revs = NULL;
227+
} else {
228+
opts->revs = xmalloc(sizeof(*opts->revs));
229+
init_revisions(opts->revs, NULL);
230+
opts->revs->no_walk = 1;
231+
if (argc < 2)
232+
usage_with_options(usage_str, options);
233+
argc = setup_revisions(argc, argv, opts->revs, NULL);
234+
}
235+
236+
if (argc > 1)
237+
usage_with_options(usage_str, options);
227238
}
228239

229240
struct commit_message {
@@ -631,23 +642,15 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
631642
return res;
632643
}
633644

634-
static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
645+
static void prepare_revs(struct replay_opts *opts)
635646
{
636-
int argc;
637-
638-
init_revisions(revs, NULL);
639-
revs->no_walk = 1;
640647
if (opts->action != REVERT)
641-
revs->reverse = 1;
642-
643-
argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
644-
if (argc > 1)
645-
usage(*revert_or_cherry_pick_usage(opts));
648+
opts->revs->reverse ^= 1;
646649

647-
if (prepare_revision_walk(revs))
650+
if (prepare_revision_walk(opts->revs))
648651
die(_("revision walk setup failed"));
649652

650-
if (!revs->commits)
653+
if (!opts->revs->commits)
651654
die(_("empty commit set passed"));
652655
}
653656

@@ -844,14 +847,13 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
844847
static void walk_revs_populate_todo(struct commit_list **todo_list,
845848
struct replay_opts *opts)
846849
{
847-
struct rev_info revs;
848850
struct commit *commit;
849851
struct commit_list **next;
850852

851-
prepare_revs(&revs, opts);
853+
prepare_revs(opts);
852854

853855
next = todo_list;
854-
while ((commit = get_revision(&revs)))
856+
while ((commit = get_revision(opts->revs)))
855857
next = commit_list_append(commit, next);
856858
}
857859

@@ -942,7 +944,7 @@ static int sequencer_rollback(struct replay_opts *opts)
942944
}
943945
if (reset_for_rollback(sha1))
944946
goto fail;
945-
remove_sequencer_state(1);
947+
remove_sequencer_state();
946948
strbuf_release(&buf);
947949
return 0;
948950
fail:
@@ -1016,33 +1018,64 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
10161018
for (cur = todo_list; cur; cur = cur->next) {
10171019
save_todo(cur, opts);
10181020
res = do_pick_commit(cur->item, opts);
1019-
if (res) {
1020-
if (!cur->next)
1021-
/*
1022-
* An error was encountered while
1023-
* picking the last commit; the
1024-
* sequencer state is useless now --
1025-
* the user simply needs to resolve
1026-
* the conflict and commit
1027-
*/
1028-
remove_sequencer_state(0);
1021+
if (res)
10291022
return res;
1030-
}
10311023
}
10321024

10331025
/*
10341026
* Sequence of picks finished successfully; cleanup by
10351027
* removing the .git/sequencer directory
10361028
*/
1037-
remove_sequencer_state(1);
1029+
remove_sequencer_state();
10381030
return 0;
10391031
}
10401032

1033+
static int continue_single_pick(void)
1034+
{
1035+
const char *argv[] = { "commit", NULL };
1036+
1037+
if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
1038+
!file_exists(git_path("REVERT_HEAD")))
1039+
return error(_("no cherry-pick or revert in progress"));
1040+
return run_command_v_opt(argv, RUN_GIT_CMD);
1041+
}
1042+
1043+
static int sequencer_continue(struct replay_opts *opts)
1044+
{
1045+
struct commit_list *todo_list = NULL;
1046+
1047+
if (!file_exists(git_path(SEQ_TODO_FILE)))
1048+
return continue_single_pick();
1049+
read_populate_opts(&opts);
1050+
read_populate_todo(&todo_list, opts);
1051+
1052+
/* Verify that the conflict has been resolved */
1053+
if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
1054+
file_exists(git_path("REVERT_HEAD"))) {
1055+
int ret = continue_single_pick();
1056+
if (ret)
1057+
return ret;
1058+
}
1059+
if (index_differs_from("HEAD", 0))
1060+
return error_dirty_index(opts);
1061+
todo_list = todo_list->next;
1062+
return pick_commits(todo_list, opts);
1063+
}
1064+
1065+
static int single_pick(struct commit *cmit, struct replay_opts *opts)
1066+
{
1067+
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
1068+
return do_pick_commit(cmit, opts);
1069+
}
1070+
10411071
static int pick_revisions(struct replay_opts *opts)
10421072
{
10431073
struct commit_list *todo_list = NULL;
10441074
unsigned char sha1[20];
10451075

1076+
if (opts->subcommand == REPLAY_NONE)
1077+
assert(opts->revs);
1078+
10461079
read_and_refresh_cache(opts);
10471080

10481081
/*
@@ -1051,21 +1084,32 @@ static int pick_revisions(struct replay_opts *opts)
10511084
* one that is being continued
10521085
*/
10531086
if (opts->subcommand == REPLAY_REMOVE_STATE) {
1054-
remove_sequencer_state(1);
1087+
remove_sequencer_state();
10551088
return 0;
10561089
}
10571090
if (opts->subcommand == REPLAY_ROLLBACK)
10581091
return sequencer_rollback(opts);
1059-
if (opts->subcommand == REPLAY_CONTINUE) {
1060-
if (!file_exists(git_path(SEQ_TODO_FILE)))
1061-
return error(_("No %s in progress"), action_name(opts));
1062-
read_populate_opts(&opts);
1063-
read_populate_todo(&todo_list, opts);
1064-
1065-
/* Verify that the conflict has been resolved */
1066-
if (!index_differs_from("HEAD", 0))
1067-
todo_list = todo_list->next;
1068-
return pick_commits(todo_list, opts);
1092+
if (opts->subcommand == REPLAY_CONTINUE)
1093+
return sequencer_continue(opts);
1094+
1095+
/*
1096+
* If we were called as "git cherry-pick <commit>", just
1097+
* cherry-pick/revert it, set CHERRY_PICK_HEAD /
1098+
* REVERT_HEAD, and don't touch the sequencer state.
1099+
* This means it is possible to cherry-pick in the middle
1100+
* of a cherry-pick sequence.
1101+
*/
1102+
if (opts->revs->cmdline.nr == 1 &&
1103+
opts->revs->cmdline.rev->whence == REV_CMD_REV &&
1104+
opts->revs->no_walk &&
1105+
!opts->revs->cmdline.rev->flags) {
1106+
struct commit *cmit;
1107+
if (prepare_revision_walk(opts->revs))
1108+
die(_("revision walk setup failed"));
1109+
cmit = get_revision(opts->revs);
1110+
if (!cmit || get_revision(opts->revs))
1111+
die("BUG: expected exactly one commit from walk");
1112+
return single_pick(cmit, opts);
10691113
}
10701114

10711115
/*

sequencer.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@
33
#include "strbuf.h"
44
#include "dir.h"
55

6-
void remove_sequencer_state(int aggressive)
6+
void remove_sequencer_state(void)
77
{
88
struct strbuf seq_dir = STRBUF_INIT;
9-
struct strbuf seq_old_dir = STRBUF_INIT;
109

1110
strbuf_addf(&seq_dir, "%s", git_path(SEQ_DIR));
12-
strbuf_addf(&seq_old_dir, "%s", git_path(SEQ_OLD_DIR));
13-
remove_dir_recursively(&seq_old_dir, 0);
14-
rename(git_path(SEQ_DIR), git_path(SEQ_OLD_DIR));
15-
if (aggressive)
16-
remove_dir_recursively(&seq_old_dir, 0);
11+
remove_dir_recursively(&seq_dir, 0);
1712
strbuf_release(&seq_dir);
18-
strbuf_release(&seq_old_dir);
1913
}

sequencer.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,11 @@
22
#define SEQUENCER_H
33

44
#define SEQ_DIR "sequencer"
5-
#define SEQ_OLD_DIR "sequencer-old"
65
#define SEQ_HEAD_FILE "sequencer/head"
76
#define SEQ_TODO_FILE "sequencer/todo"
87
#define SEQ_OPTS_FILE "sequencer/opts"
98

10-
/*
11-
* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring
12-
* any errors. Intended to be used by 'git reset'.
13-
*
14-
* With the aggressive flag, it additionally removes SEQ_OLD_DIR,
15-
* ignoring any errors. Inteded to be used by the sequencer's
16-
* '--quit' subcommand.
17-
*/
18-
void remove_sequencer_state(int aggressive);
9+
/* Removes SEQ_DIR. */
10+
extern void remove_sequencer_state(void);
1911

2012
#endif

0 commit comments

Comments
 (0)