Skip to content

Commit 73fdc53

Browse files
phillipwoodgitster
authored andcommitted
rebase -i: use struct rebase_options to parse args
In order to run `rebase -i` without forking `rebase--interactive` it will be convenient to use the same structure when parsing the options in cmd_rebase() and cmd_rebase__interactive(). Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3389853 commit 73fdc53

File tree

1 file changed

+112
-91
lines changed

1 file changed

+112
-91
lines changed

builtin/rebase.c

Lines changed: 112 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,73 @@ enum rebase_type {
5050
REBASE_PRESERVE_MERGES
5151
};
5252

53+
struct rebase_options {
54+
enum rebase_type type;
55+
const char *state_dir;
56+
struct commit *upstream;
57+
const char *upstream_name;
58+
const char *upstream_arg;
59+
char *head_name;
60+
struct object_id orig_head;
61+
struct commit *onto;
62+
const char *onto_name;
63+
const char *revisions;
64+
const char *switch_to;
65+
int root;
66+
struct object_id *squash_onto;
67+
struct commit *restrict_revision;
68+
int dont_finish_rebase;
69+
enum {
70+
REBASE_NO_QUIET = 1<<0,
71+
REBASE_VERBOSE = 1<<1,
72+
REBASE_DIFFSTAT = 1<<2,
73+
REBASE_FORCE = 1<<3,
74+
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
75+
} flags;
76+
struct argv_array git_am_opts;
77+
const char *action;
78+
int signoff;
79+
int allow_rerere_autoupdate;
80+
int keep_empty;
81+
int autosquash;
82+
char *gpg_sign_opt;
83+
int autostash;
84+
char *cmd;
85+
int allow_empty_message;
86+
int rebase_merges, rebase_cousins;
87+
char *strategy, *strategy_opts;
88+
struct strbuf git_format_patch_opt;
89+
int reschedule_failed_exec;
90+
};
91+
92+
#define REBASE_OPTIONS_INIT { \
93+
.type = REBASE_UNSPECIFIED, \
94+
.flags = REBASE_NO_QUIET, \
95+
.git_am_opts = ARGV_ARRAY_INIT, \
96+
.git_format_patch_opt = STRBUF_INIT \
97+
}
98+
99+
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
100+
{
101+
struct replay_opts replay = REPLAY_OPTS_INIT;
102+
103+
replay.action = REPLAY_INTERACTIVE_REBASE;
104+
sequencer_init_config(&replay);
105+
106+
replay.signoff = opts->signoff;
107+
replay.allow_ff = !(opts->flags & REBASE_FORCE);
108+
if (opts->allow_rerere_autoupdate)
109+
replay.allow_rerere_auto = opts->allow_rerere_autoupdate;
110+
replay.allow_empty = 1;
111+
replay.allow_empty_message = opts->allow_empty_message;
112+
replay.verbose = opts->flags & REBASE_VERBOSE;
113+
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
114+
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
115+
replay.strategy = opts->strategy;
116+
117+
return replay;
118+
}
119+
53120
static int add_exec_commands(struct string_list *commands)
54121
{
55122
const char *todo_file = rebase_path_todo();
@@ -265,32 +332,30 @@ static const char * const builtin_rebase_interactive_usage[] = {
265332

266333
int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
267334
{
268-
struct replay_opts opts = REPLAY_OPTS_INIT;
269-
unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;
270-
int abbreviate_commands = 0, rebase_cousins = -1, ret = 0;
271-
const char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,
272-
*cmd = NULL;
273-
struct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;
335+
struct rebase_options opts = REBASE_OPTIONS_INIT;
336+
unsigned flags = 0;
337+
int abbreviate_commands = 0, ret = 0;
274338
struct object_id squash_onto = null_oid;
275-
struct object_id *squash_onto_opt = NULL;
276339
struct string_list commands = STRING_LIST_INIT_DUP;
277-
char *raw_strategies = NULL;
278340
enum {
279341
NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,
280342
SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC
281343
} command = 0;
282344
struct option options[] = {
283-
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
284-
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
345+
OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"),
346+
REBASE_FORCE),
347+
OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")),
285348
OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
286349
N_("allow commits with empty messages")),
287-
OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")),
288-
OPT_BOOL(0, "rebase-cousins", &rebase_cousins,
350+
OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")),
351+
OPT_BOOL(0, "rebase-cousins", &opts.rebase_cousins,
289352
N_("keep original branch points of cousins")),
290-
OPT_BOOL(0, "autosquash", &autosquash,
353+
OPT_BOOL(0, "autosquash", &opts.autosquash,
291354
N_("move commits that begin with squash!/fixup!")),
292355
OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")),
293-
OPT__VERBOSE(&opts.verbose, N_("be verbose")),
356+
OPT_BIT('v', "verbose", &opts.flags,
357+
N_("display a diffstat of what changed upstream"),
358+
REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
294359
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
295360
CONTINUE),
296361
OPT_CMDMODE(0, "skip", &command, N_("skip commit"), SKIP),
@@ -308,86 +373,86 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
308373
N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
309374
OPT_CMDMODE(0, "add-exec-commands", &command,
310375
N_("insert exec commands in todo list"), ADD_EXEC),
311-
{ OPTION_CALLBACK, 0, "onto", &onto, N_("onto"), N_("onto"),
376+
{ OPTION_CALLBACK, 0, "onto", &opts.onto, N_("onto"), N_("onto"),
312377
PARSE_OPT_NONEG, parse_opt_commit, 0 },
313-
{ OPTION_CALLBACK, 0, "restrict-revision", &restrict_revision,
378+
{ OPTION_CALLBACK, 0, "restrict-revision", &opts.restrict_revision,
314379
N_("restrict-revision"), N_("restrict revision"),
315380
PARSE_OPT_NONEG, parse_opt_commit, 0 },
316381
{ OPTION_CALLBACK, 0, "squash-onto", &squash_onto, N_("squash-onto"),
317382
N_("squash onto"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },
318-
{ OPTION_CALLBACK, 0, "upstream", &upstream, N_("upstream"),
383+
{ OPTION_CALLBACK, 0, "upstream", &opts.upstream, N_("upstream"),
319384
N_("the upstream commit"), PARSE_OPT_NONEG, parse_opt_commit,
320385
0 },
321-
OPT_STRING(0, "head-name", &head_name, N_("head-name"), N_("head name")),
322-
{ OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign, N_("key-id"),
386+
OPT_STRING(0, "head-name", &opts.head_name, N_("head-name"), N_("head name")),
387+
{ OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign_opt, N_("key-id"),
323388
N_("GPG-sign commits"),
324389
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
325390
OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"),
326391
N_("rebase strategy")),
327-
OPT_STRING(0, "strategy-opts", &raw_strategies, N_("strategy-opts"),
392+
OPT_STRING(0, "strategy-opts", &opts.strategy_opts, N_("strategy-opts"),
328393
N_("strategy options")),
329-
OPT_STRING(0, "switch-to", &switch_to, N_("switch-to"),
394+
OPT_STRING(0, "switch-to", &opts.switch_to, N_("switch-to"),
330395
N_("the branch or commit to checkout")),
331-
OPT_STRING(0, "onto-name", &onto_name, N_("onto-name"), N_("onto name")),
332-
OPT_STRING(0, "cmd", &cmd, N_("cmd"), N_("the command to run")),
333-
OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),
396+
OPT_STRING(0, "onto-name", &opts.onto_name, N_("onto-name"), N_("onto name")),
397+
OPT_STRING(0, "cmd", &opts.cmd, N_("cmd"), N_("the command to run")),
398+
OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_autoupdate),
334399
OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec,
335400
N_("automatically re-schedule any `exec` that fails")),
336401
OPT_END()
337402
};
338403

339-
sequencer_init_config(&opts);
340-
git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
404+
opts.rebase_cousins = -1;
341405

342-
opts.action = REPLAY_INTERACTIVE_REBASE;
343-
opts.allow_ff = 1;
344-
opts.allow_empty = 1;
406+
git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
345407

346408
if (argc == 1)
347409
usage_with_options(builtin_rebase_interactive_usage, options);
348410

349411
argc = parse_options(argc, argv, NULL, options,
350412
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
351413

352-
opts.gpg_sign = xstrdup_or_null(opts.gpg_sign);
353-
354414
if (!is_null_oid(&squash_onto))
355-
squash_onto_opt = &squash_onto;
415+
opts.squash_onto = &squash_onto;
356416

357-
flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
417+
flags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
358418
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
359-
flags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
360-
flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
419+
flags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
420+
flags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
361421
flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
362422

363-
if (rebase_cousins >= 0 && !rebase_merges)
423+
if (opts.rebase_cousins >= 0 && !opts.rebase_merges)
364424
warning(_("--[no-]rebase-cousins has no effect without "
365425
"--rebase-merges"));
366426

367-
if (cmd && *cmd) {
368-
string_list_split(&commands, cmd, '\n', -1);
427+
if (opts.cmd && *opts.cmd) {
428+
string_list_split(&commands, opts.cmd, '\n', -1);
369429

370430
/* rebase.c adds a new line to cmd after every command,
371431
* so here the last command is always empty */
372432
string_list_remove_empty_items(&commands, 0);
373433
}
374434

375435
switch (command) {
376-
case NONE:
377-
if (!onto && !upstream)
436+
case NONE: {
437+
struct replay_opts replay_opts = get_replay_opts(&opts);
438+
if (!opts.onto && !opts.upstream)
378439
die(_("a base commit must be provided with --upstream or --onto"));
379440

380-
ret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,
381-
onto_name, squash_onto_opt, head_name, restrict_revision,
382-
raw_strategies, &commands, autosquash);
441+
ret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,
442+
opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,
443+
opts.strategy_opts, &commands, opts.autosquash);
383444
break;
445+
}
384446
case SKIP: {
385447
struct string_list merge_rr = STRING_LIST_INIT_DUP;
386448

387449
rerere_clear(the_repository, &merge_rr);
450+
}
388451
/* fallthrough */
389-
case CONTINUE:
390-
ret = sequencer_continue(the_repository, &opts);
452+
case CONTINUE: {
453+
struct replay_opts replay_opts = get_replay_opts(&opts);
454+
455+
ret = sequencer_continue(the_repository, &replay_opts);
391456
break;
392457
}
393458
case EDIT_TODO:
@@ -446,45 +511,6 @@ static int use_builtin_rebase(void)
446511
return ret;
447512
}
448513

449-
struct rebase_options {
450-
enum rebase_type type;
451-
const char *state_dir;
452-
struct commit *upstream;
453-
const char *upstream_name;
454-
const char *upstream_arg;
455-
char *head_name;
456-
struct object_id orig_head;
457-
struct commit *onto;
458-
const char *onto_name;
459-
const char *revisions;
460-
const char *switch_to;
461-
int root;
462-
struct object_id *squash_onto;
463-
struct commit *restrict_revision;
464-
int dont_finish_rebase;
465-
enum {
466-
REBASE_NO_QUIET = 1<<0,
467-
REBASE_VERBOSE = 1<<1,
468-
REBASE_DIFFSTAT = 1<<2,
469-
REBASE_FORCE = 1<<3,
470-
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
471-
} flags;
472-
struct argv_array git_am_opts;
473-
const char *action;
474-
int signoff;
475-
int allow_rerere_autoupdate;
476-
int keep_empty;
477-
int autosquash;
478-
char *gpg_sign_opt;
479-
int autostash;
480-
char *cmd;
481-
int allow_empty_message;
482-
int rebase_merges, rebase_cousins;
483-
char *strategy, *strategy_opts;
484-
struct strbuf git_format_patch_opt;
485-
int reschedule_failed_exec;
486-
};
487-
488514
static int is_interactive(struct rebase_options *opts)
489515
{
490516
return opts->type == REBASE_INTERACTIVE ||
@@ -1380,13 +1406,7 @@ static int check_exec_cmd(const char *cmd)
13801406

13811407
int cmd_rebase(int argc, const char **argv, const char *prefix)
13821408
{
1383-
struct rebase_options options = {
1384-
.type = REBASE_UNSPECIFIED,
1385-
.flags = REBASE_NO_QUIET,
1386-
.git_am_opts = ARGV_ARRAY_INIT,
1387-
.allow_empty_message = 1,
1388-
.git_format_patch_opt = STRBUF_INIT,
1389-
};
1409+
struct rebase_options options = REBASE_OPTIONS_INIT;
13901410
const char *branch_name;
13911411
int ret, flags, total_argc, in_progress = 0;
13921412
int ok_to_skip_pre_rebase = 0;
@@ -1539,6 +1559,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
15391559
trace_repo_setup(prefix);
15401560
setup_work_tree();
15411561

1562+
options.allow_empty_message = 1;
15421563
git_config(rebase_config, &options);
15431564

15441565
strbuf_reset(&buf);

0 commit comments

Comments
 (0)