rebase -i: use struct rebase_options to parse args
authorPhillip Wood <phillip.wood@dunelm.org.uk>
Wed, 17 Apr 2019 14:30:41 +0000 (15:30 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Apr 2019 08:32:10 +0000 (17:32 +0900)
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>
builtin/rebase.c
index 3b9da694733194a6343c32b9394795ca7cbb8729..aa97d81ab8b34b11752c251508e6914560fe4e6f 100644 (file)
@@ -50,6 +50,73 @@ enum rebase_type {
        REBASE_PRESERVE_MERGES
 };
 
+struct rebase_options {
+       enum rebase_type type;
+       const char *state_dir;
+       struct commit *upstream;
+       const char *upstream_name;
+       const char *upstream_arg;
+       char *head_name;
+       struct object_id orig_head;
+       struct commit *onto;
+       const char *onto_name;
+       const char *revisions;
+       const char *switch_to;
+       int root;
+       struct object_id *squash_onto;
+       struct commit *restrict_revision;
+       int dont_finish_rebase;
+       enum {
+               REBASE_NO_QUIET = 1<<0,
+               REBASE_VERBOSE = 1<<1,
+               REBASE_DIFFSTAT = 1<<2,
+               REBASE_FORCE = 1<<3,
+               REBASE_INTERACTIVE_EXPLICIT = 1<<4,
+       } flags;
+       struct argv_array git_am_opts;
+       const char *action;
+       int signoff;
+       int allow_rerere_autoupdate;
+       int keep_empty;
+       int autosquash;
+       char *gpg_sign_opt;
+       int autostash;
+       char *cmd;
+       int allow_empty_message;
+       int rebase_merges, rebase_cousins;
+       char *strategy, *strategy_opts;
+       struct strbuf git_format_patch_opt;
+       int reschedule_failed_exec;
+};
+
+#define REBASE_OPTIONS_INIT {                          \
+               .type = REBASE_UNSPECIFIED,             \
+               .flags = REBASE_NO_QUIET,               \
+               .git_am_opts = ARGV_ARRAY_INIT,         \
+               .git_format_patch_opt = STRBUF_INIT     \
+       }
+
+static struct replay_opts get_replay_opts(const struct rebase_options *opts)
+{
+       struct replay_opts replay = REPLAY_OPTS_INIT;
+
+       replay.action = REPLAY_INTERACTIVE_REBASE;
+       sequencer_init_config(&replay);
+
+       replay.signoff = opts->signoff;
+       replay.allow_ff = !(opts->flags & REBASE_FORCE);
+       if (opts->allow_rerere_autoupdate)
+               replay.allow_rerere_auto = opts->allow_rerere_autoupdate;
+       replay.allow_empty = 1;
+       replay.allow_empty_message = opts->allow_empty_message;
+       replay.verbose = opts->flags & REBASE_VERBOSE;
+       replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+       replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
+       replay.strategy = opts->strategy;
+
+       return replay;
+}
+
 static int add_exec_commands(struct string_list *commands)
 {
        const char *todo_file = rebase_path_todo();
@@ -265,32 +332,30 @@ static const char * const builtin_rebase_interactive_usage[] = {
 
 int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
 {
-       struct replay_opts opts = REPLAY_OPTS_INIT;
-       unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;
-       int abbreviate_commands = 0, rebase_cousins = -1, ret = 0;
-       const char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,
-               *cmd = NULL;
-       struct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;
+       struct rebase_options opts = REBASE_OPTIONS_INIT;
+       unsigned flags = 0;
+       int abbreviate_commands = 0, ret = 0;
        struct object_id squash_onto = null_oid;
-       struct object_id *squash_onto_opt = NULL;
        struct string_list commands = STRING_LIST_INIT_DUP;
-       char *raw_strategies = NULL;
        enum {
                NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,
                SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC
        } command = 0;
        struct option options[] = {
-               OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
-               OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
+               OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"),
+                          REBASE_FORCE),
+               OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")),
                OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
                         N_("allow commits with empty messages")),
-               OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")),
-               OPT_BOOL(0, "rebase-cousins", &rebase_cousins,
+               OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")),
+               OPT_BOOL(0, "rebase-cousins", &opts.rebase_cousins,
                         N_("keep original branch points of cousins")),
-               OPT_BOOL(0, "autosquash", &autosquash,
+               OPT_BOOL(0, "autosquash", &opts.autosquash,
                         N_("move commits that begin with squash!/fixup!")),
                OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")),
-               OPT__VERBOSE(&opts.verbose, N_("be verbose")),
+               OPT_BIT('v', "verbose", &opts.flags,
+                       N_("display a diffstat of what changed upstream"),
+                       REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
                OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
                            CONTINUE),
                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)
                        N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
                OPT_CMDMODE(0, "add-exec-commands", &command,
                        N_("insert exec commands in todo list"), ADD_EXEC),
-               { OPTION_CALLBACK, 0, "onto", &onto, N_("onto"), N_("onto"),
+               { OPTION_CALLBACK, 0, "onto", &opts.onto, N_("onto"), N_("onto"),
                  PARSE_OPT_NONEG, parse_opt_commit, 0 },
-               { OPTION_CALLBACK, 0, "restrict-revision", &restrict_revision,
+               { OPTION_CALLBACK, 0, "restrict-revision", &opts.restrict_revision,
                  N_("restrict-revision"), N_("restrict revision"),
                  PARSE_OPT_NONEG, parse_opt_commit, 0 },
                { OPTION_CALLBACK, 0, "squash-onto", &squash_onto, N_("squash-onto"),
                  N_("squash onto"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },
-               { OPTION_CALLBACK, 0, "upstream", &upstream, N_("upstream"),
+               { OPTION_CALLBACK, 0, "upstream", &opts.upstream, N_("upstream"),
                  N_("the upstream commit"), PARSE_OPT_NONEG, parse_opt_commit,
                  0 },
-               OPT_STRING(0, "head-name", &head_name, N_("head-name"), N_("head name")),
-               { OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign, N_("key-id"),
+               OPT_STRING(0, "head-name", &opts.head_name, N_("head-name"), N_("head name")),
+               { OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign_opt, N_("key-id"),
                        N_("GPG-sign commits"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
                OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"),
                           N_("rebase strategy")),
-               OPT_STRING(0, "strategy-opts", &raw_strategies, N_("strategy-opts"),
+               OPT_STRING(0, "strategy-opts", &opts.strategy_opts, N_("strategy-opts"),
                           N_("strategy options")),
-               OPT_STRING(0, "switch-to", &switch_to, N_("switch-to"),
+               OPT_STRING(0, "switch-to", &opts.switch_to, N_("switch-to"),
                           N_("the branch or commit to checkout")),
-               OPT_STRING(0, "onto-name", &onto_name, N_("onto-name"), N_("onto name")),
-               OPT_STRING(0, "cmd", &cmd, N_("cmd"), N_("the command to run")),
-               OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),
+               OPT_STRING(0, "onto-name", &opts.onto_name, N_("onto-name"), N_("onto name")),
+               OPT_STRING(0, "cmd", &opts.cmd, N_("cmd"), N_("the command to run")),
+               OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_autoupdate),
                OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec,
                         N_("automatically re-schedule any `exec` that fails")),
                OPT_END()
        };
 
-       sequencer_init_config(&opts);
-       git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
+       opts.rebase_cousins = -1;
 
-       opts.action = REPLAY_INTERACTIVE_REBASE;
-       opts.allow_ff = 1;
-       opts.allow_empty = 1;
+       git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
        if (argc == 1)
                usage_with_options(builtin_rebase_interactive_usage, options);
@@ -349,23 +411,21 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, NULL, options,
                        builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
 
-       opts.gpg_sign = xstrdup_or_null(opts.gpg_sign);
-
        if (!is_null_oid(&squash_onto))
-               squash_onto_opt = &squash_onto;
+               opts.squash_onto = &squash_onto;
 
-       flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
+       flags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
        flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
-       flags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
-       flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
+       flags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
+       flags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
        flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
 
-       if (rebase_cousins >= 0 && !rebase_merges)
+       if (opts.rebase_cousins >= 0 && !opts.rebase_merges)
                warning(_("--[no-]rebase-cousins has no effect without "
                          "--rebase-merges"));
 
-       if (cmd && *cmd) {
-               string_list_split(&commands, cmd, '\n', -1);
+       if (opts.cmd && *opts.cmd) {
+               string_list_split(&commands, opts.cmd, '\n', -1);
 
                /* rebase.c adds a new line to cmd after every command,
                 * so here the last command is always empty */
@@ -373,21 +433,26 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
        }
 
        switch (command) {
-       case NONE:
-               if (!onto && !upstream)
+       case NONE: {
+               struct replay_opts replay_opts = get_replay_opts(&opts);
+               if (!opts.onto && !opts.upstream)
                        die(_("a base commit must be provided with --upstream or --onto"));
 
-               ret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,
-                                           onto_name, squash_onto_opt, head_name, restrict_revision,
-                                           raw_strategies, &commands, autosquash);
+               ret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,
+                                           opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,
+                                           opts.strategy_opts, &commands, opts.autosquash);
                break;
+       }
        case SKIP: {
                struct string_list merge_rr = STRING_LIST_INIT_DUP;
 
                rerere_clear(the_repository, &merge_rr);
+       }
                /* fallthrough */
-       case CONTINUE:
-               ret = sequencer_continue(the_repository, &opts);
+       case CONTINUE: {
+               struct replay_opts replay_opts = get_replay_opts(&opts);
+
+               ret = sequencer_continue(the_repository, &replay_opts);
                break;
        }
        case EDIT_TODO:
@@ -446,45 +511,6 @@ static int use_builtin_rebase(void)
        return ret;
 }
 
-struct rebase_options {
-       enum rebase_type type;
-       const char *state_dir;
-       struct commit *upstream;
-       const char *upstream_name;
-       const char *upstream_arg;
-       char *head_name;
-       struct object_id orig_head;
-       struct commit *onto;
-       const char *onto_name;
-       const char *revisions;
-       const char *switch_to;
-       int root;
-       struct object_id *squash_onto;
-       struct commit *restrict_revision;
-       int dont_finish_rebase;
-       enum {
-               REBASE_NO_QUIET = 1<<0,
-               REBASE_VERBOSE = 1<<1,
-               REBASE_DIFFSTAT = 1<<2,
-               REBASE_FORCE = 1<<3,
-               REBASE_INTERACTIVE_EXPLICIT = 1<<4,
-       } flags;
-       struct argv_array git_am_opts;
-       const char *action;
-       int signoff;
-       int allow_rerere_autoupdate;
-       int keep_empty;
-       int autosquash;
-       char *gpg_sign_opt;
-       int autostash;
-       char *cmd;
-       int allow_empty_message;
-       int rebase_merges, rebase_cousins;
-       char *strategy, *strategy_opts;
-       struct strbuf git_format_patch_opt;
-       int reschedule_failed_exec;
-};
-
 static int is_interactive(struct rebase_options *opts)
 {
        return opts->type == REBASE_INTERACTIVE ||
@@ -1380,13 +1406,7 @@ static int check_exec_cmd(const char *cmd)
 
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
-       struct rebase_options options = {
-               .type = REBASE_UNSPECIFIED,
-               .flags = REBASE_NO_QUIET,
-               .git_am_opts = ARGV_ARRAY_INIT,
-               .allow_empty_message = 1,
-               .git_format_patch_opt = STRBUF_INIT,
-       };
+       struct rebase_options options = REBASE_OPTIONS_INIT;
        const char *branch_name;
        int ret, flags, total_argc, in_progress = 0;
        int ok_to_skip_pre_rebase = 0;
@@ -1539,6 +1559,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        trace_repo_setup(prefix);
        setup_work_tree();
 
+       options.allow_empty_message = 1;
        git_config(rebase_config, &options);
 
        strbuf_reset(&buf);