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 <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Phillip Wood committed
Apr 17, 2019 at 15:30 UTC
73fdc535d269ba1ac25cdb832d72d47abdede049
1 file changed
+112
-91
builtin/rebase.c
+112
-91
@@ -50,6 +50,73 @@ enum rebase_type {
50
REBASE_PRESERVE_MERGES
51
};
52
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
+
120
static int add_exec_commands(struct string_list *commands)
121
{
122
const char *todo_file = rebase_path_todo();
@@ -265,32 +332,30 @@ static const char * const builtin_rebase_interactive_usage[] = {
332
333
int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
334
{
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;
338
struct object_id squash_onto = null_oid;
275
- struct object_id *squash_onto_opt = NULL;
339
struct string_list commands = STRING_LIST_INIT_DUP;
277
- char *raw_strategies = NULL;
340
enum {
341
NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,
342
SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC
343
} command = 0;
344
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")),
348
OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
349
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,
352
N_("keep original branch points of cousins")),
290
- OPT_BOOL(0, "autosquash", &autosquash,
353
+ OPT_BOOL(0, "autosquash", &opts.autosquash,
354
N_("move commits that begin with squash!/fixup!")),
355
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),
359
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
360
CONTINUE),
361
OPT_CMDMODE(0, "skip", &command, N_("skip commit"), SKIP),
@@ -308,40 +373,37 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
373
N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
374
OPT_CMDMODE(0, "add-exec-commands", &command,
375
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"),
377
PARSE_OPT_NONEG, parse_opt_commit, 0 },
313
- { OPTION_CALLBACK, 0, "restrict-revision", &restrict_revision,
378
+ { OPTION_CALLBACK, 0, "restrict-revision", &opts.restrict_revision,
379
N_("restrict-revision"), N_("restrict revision"),
380
PARSE_OPT_NONEG, parse_opt_commit, 0 },
381
{ OPTION_CALLBACK, 0, "squash-onto", &squash_onto, N_("squash-onto"),
382
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"),
384
N_("the upstream commit"), PARSE_OPT_NONEG, parse_opt_commit,
385
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"),
388
N_("GPG-sign commits"),
389
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
390
OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"),
391
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"),
393
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"),
395
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),
399
OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec,
400
N_("automatically re-schedule any `exec` that fails")),
401
OPT_END()
402
};
403
339
- sequencer_init_config(&opts);
340
- git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
404
+ opts.rebase_cousins = -1;
405
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);
407
408
if (argc == 1)
409
usage_with_options(builtin_rebase_interactive_usage, options);
@@ -349,23 +411,21 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
411
argc = parse_options(argc, argv, NULL, options,
412
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
413
352
- opts.gpg_sign = xstrdup_or_null(opts.gpg_sign);
353
-
414
if (!is_null_oid(&squash_onto))
355
- squash_onto_opt = &squash_onto;
415
+ opts.squash_onto = &squash_onto;
416
357
- flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
417
+ flags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
418
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;
421
flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
422
363
- if (rebase_cousins >= 0 && !rebase_merges)
423
+ if (opts.rebase_cousins >= 0 && !opts.rebase_merges)
424
warning(_("--[no-]rebase-cousins has no effect without "
425
"--rebase-merges"));
426
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);
429
430
/* rebase.c adds a new line to cmd after every command,
431
* so here the last command is always empty */
@@ -373,21 +433,26 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
433
}
434
435
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)
439
die(_("a base commit must be provided with --upstream or --onto"));
440
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);
444
break;
445
+ }
446
case SKIP: {
447
struct string_list merge_rr = STRING_LIST_INIT_DUP;
448
449
rerere_clear(the_repository, &merge_rr);
450
+ }
451
/* 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);
456
break;
457
}
458
case EDIT_TODO:
@@ -446,45 +511,6 @@ static int use_builtin_rebase(void)
511
return ret;
512
}
513
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
-
514
static int is_interactive(struct rebase_options *opts)
515
{
516
return opts->type == REBASE_INTERACTIVE ||
@@ -1380,13 +1406,7 @@ static int check_exec_cmd(const char *cmd)
1406
1407
int cmd_rebase(int argc, const char **argv, const char *prefix)
1408
{
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;
1410
const char *branch_name;
1411
int ret, flags, total_argc, in_progress = 0;
1412
int ok_to_skip_pre_rebase = 0;
@@ -1539,6 +1559,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1559
trace_repo_setup(prefix);
1560
setup_work_tree();
1561
1562
+ options.allow_empty_message = 1;
1563
git_config(rebase_config, &options);
1564
1565
strbuf_reset(&buf);