Skip to content

Commit f576968

Browse files
dschogitster
authored andcommitted
rebase: really just passthru the git am options
Currently, we parse the options intended for `git am` as if we wanted to handle them in `git rebase`, and then reconstruct them painstakingly to define the `git_am_opt` variable. However, there is a much better way (that I was unaware of, at the time when I mentored Pratik to implement these options): OPT_PASSTHRU_ARGV. It is intended for exactly this use case, where command-line options want to be parsed into a separate `argv_array`. Let's use this feature. Incidentally, this also allows us to address a bug discovered by Phillip Wood, where the built-in rebase failed to understand that the `-C` option takes an optional argument. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d166e6a commit f576968

File tree

1 file changed

+35
-63
lines changed

1 file changed

+35
-63
lines changed

builtin/rebase.c

Lines changed: 35 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ struct rebase_options {
8787
REBASE_FORCE = 1<<3,
8888
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
8989
} flags;
90-
struct strbuf git_am_opt;
90+
struct argv_array git_am_opts;
9191
const char *action;
9292
int signoff;
9393
int allow_rerere_autoupdate;
@@ -339,7 +339,7 @@ N_("Resolve all conflicts manually, mark them as resolved with\n"
339339
static int run_specific_rebase(struct rebase_options *opts)
340340
{
341341
const char *argv[] = { NULL, NULL };
342-
struct strbuf script_snippet = STRBUF_INIT;
342+
struct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT;
343343
int status;
344344
const char *backend, *backend_func;
345345

@@ -433,7 +433,9 @@ static int run_specific_rebase(struct rebase_options *opts)
433433
oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
434434
add_var(&script_snippet, "GIT_QUIET",
435435
opts->flags & REBASE_NO_QUIET ? "" : "t");
436-
add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
436+
sq_quote_argv_pretty(&buf, opts->git_am_opts.argv);
437+
add_var(&script_snippet, "git_am_opt", buf.buf);
438+
strbuf_release(&buf);
437439
add_var(&script_snippet, "verbose",
438440
opts->flags & REBASE_VERBOSE ? "t" : "");
439441
add_var(&script_snippet, "diffstat",
@@ -756,7 +758,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
756758
struct rebase_options options = {
757759
.type = REBASE_UNSPECIFIED,
758760
.flags = REBASE_NO_QUIET,
759-
.git_am_opt = STRBUF_INIT,
761+
.git_am_opts = ARGV_ARRAY_INIT,
760762
.allow_rerere_autoupdate = -1,
761763
.allow_empty_message = 1,
762764
.git_format_patch_opt = STRBUF_INIT,
@@ -777,12 +779,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
777779
ACTION_EDIT_TODO,
778780
ACTION_SHOW_CURRENT_PATCH,
779781
} action = NO_ACTION;
780-
int committer_date_is_author_date = 0;
781-
int ignore_date = 0;
782-
int ignore_whitespace = 0;
783782
const char *gpg_sign = NULL;
784-
int opt_c = -1;
785-
struct string_list whitespace = STRING_LIST_INIT_NODUP;
786783
struct string_list exec = STRING_LIST_INIT_NODUP;
787784
const char *rebase_merges = NULL;
788785
int fork_point = -1;
@@ -804,15 +801,20 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
804801
{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
805802
N_("do not show diffstat of what changed upstream"),
806803
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
807-
OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
808-
N_("passed to 'git apply'")),
809804
OPT_BOOL(0, "signoff", &options.signoff,
810805
N_("add a Signed-off-by: line to each commit")),
811-
OPT_BOOL(0, "committer-date-is-author-date",
812-
&committer_date_is_author_date,
813-
N_("passed to 'git am'")),
814-
OPT_BOOL(0, "ignore-date", &ignore_date,
815-
N_("passed to 'git am'")),
806+
OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
807+
NULL, N_("passed to 'git am'"),
808+
PARSE_OPT_NOARG),
809+
OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
810+
&options.git_am_opts, NULL,
811+
N_("passed to 'git am'"), PARSE_OPT_NOARG),
812+
OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
813+
N_("passed to 'git am'"), PARSE_OPT_NOARG),
814+
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
815+
N_("passed to 'git apply'"), 0),
816+
OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
817+
N_("action"), N_("passed to 'git apply'"), 0),
816818
OPT_BIT('f', "force-rebase", &options.flags,
817819
N_("cherry-pick all commits, even if unchanged"),
818820
REBASE_FORCE),
@@ -856,10 +858,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
856858
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
857859
N_("GPG-sign commits"),
858860
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
859-
OPT_STRING_LIST(0, "whitespace", &whitespace,
860-
N_("whitespace"), N_("passed to 'git apply'")),
861-
OPT_SET_INT('C', NULL, &opt_c, N_("passed to 'git apply'"),
862-
REBASE_AM),
863861
OPT_BOOL(0, "autostash", &options.autostash,
864862
N_("automatically stash/stash pop before and after")),
865863
OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
@@ -884,6 +882,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
884882
N_("rebase all reachable commits up to the root(s)")),
885883
OPT_END(),
886884
};
885+
int i;
887886

888887
/*
889888
* NEEDSWORK: Once the builtin rebase has been tested enough
@@ -1064,22 +1063,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
10641063
state_dir_base, cmd_live_rebase, buf.buf);
10651064
}
10661065

1067-
if (!(options.flags & REBASE_NO_QUIET))
1068-
strbuf_addstr(&options.git_am_opt, " -q");
1069-
1070-
if (committer_date_is_author_date) {
1071-
strbuf_addstr(&options.git_am_opt,
1072-
" --committer-date-is-author-date");
1073-
options.flags |= REBASE_FORCE;
1066+
for (i = 0; i < options.git_am_opts.argc; i++) {
1067+
const char *option = options.git_am_opts.argv[i];
1068+
if (!strcmp(option, "--committer-date-is-author-date") ||
1069+
!strcmp(option, "--ignore-date") ||
1070+
!strcmp(option, "--whitespace=fix") ||
1071+
!strcmp(option, "--whitespace=strip"))
1072+
options.flags |= REBASE_FORCE;
10741073
}
10751074

1076-
if (ignore_whitespace)
1077-
strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
1078-
1079-
if (ignore_date) {
1080-
strbuf_addstr(&options.git_am_opt, " --ignore-date");
1081-
options.flags |= REBASE_FORCE;
1082-
}
1075+
if (!(options.flags & REBASE_NO_QUIET))
1076+
argv_array_push(&options.git_am_opts, "-q");
10831077

10841078
if (options.keep_empty)
10851079
imply_interactive(&options, "--keep-empty");
@@ -1089,23 +1083,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
10891083
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
10901084
}
10911085

1092-
if (opt_c >= 0)
1093-
strbuf_addf(&options.git_am_opt, " -C%d", opt_c);
1094-
1095-
if (whitespace.nr) {
1096-
int i;
1097-
1098-
for (i = 0; i < whitespace.nr; i++) {
1099-
const char *item = whitespace.items[i].string;
1100-
1101-
strbuf_addf(&options.git_am_opt, " --whitespace=%s",
1102-
item);
1103-
1104-
if ((!strcmp(item, "fix")) || (!strcmp(item, "strip")))
1105-
options.flags |= REBASE_FORCE;
1106-
}
1107-
}
1108-
11091086
if (exec.nr) {
11101087
int i;
11111088

@@ -1181,23 +1158,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
11811158
break;
11821159
}
11831160

1184-
if (options.git_am_opt.len) {
1185-
const char *p;
1186-
1161+
if (options.git_am_opts.argc) {
11871162
/* all am options except -q are compatible only with --am */
1188-
strbuf_reset(&buf);
1189-
strbuf_addbuf(&buf, &options.git_am_opt);
1190-
strbuf_addch(&buf, ' ');
1191-
while ((p = strstr(buf.buf, " -q ")))
1192-
strbuf_splice(&buf, p - buf.buf, 4, " ", 1);
1193-
strbuf_trim(&buf);
1163+
for (i = options.git_am_opts.argc - 1; i >= 0; i--)
1164+
if (strcmp(options.git_am_opts.argv[i], "-q"))
1165+
break;
11941166

1195-
if (is_interactive(&options) && buf.len)
1167+
if (is_interactive(&options) && i >= 0)
11961168
die(_("error: cannot combine interactive options "
11971169
"(--interactive, --exec, --rebase-merges, "
11981170
"--preserve-merges, --keep-empty, --root + "
11991171
"--onto) with am options (%s)"), buf.buf);
1200-
if (options.type == REBASE_MERGE && buf.len)
1172+
if (options.type == REBASE_MERGE && i >= 0)
12011173
die(_("error: cannot combine merge options (--merge, "
12021174
"--strategy, --strategy-option) with am options "
12031175
"(%s)"), buf.buf);
@@ -1207,7 +1179,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
12071179
if (options.type == REBASE_PRESERVE_MERGES)
12081180
die("cannot combine '--signoff' with "
12091181
"'--preserve-merges'");
1210-
strbuf_addstr(&options.git_am_opt, " --signoff");
1182+
argv_array_push(&options.git_am_opts, "--signoff");
12111183
options.flags |= REBASE_FORCE;
12121184
}
12131185

0 commit comments

Comments
 (0)