in builtin/am.c [2308:2557]
int cmd_am(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
{
struct am_state state;
int binary = -1;
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_type resume_mode = RESUME_FALSE;
int in_progress;
int ret = 0;
const char * const usage[] = {
N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
N_("git am [<options>] (--continue | --skip | --abort)"),
NULL
};
struct option options[] = {
OPT_BOOL('i', "interactive", &state.interactive,
N_("run interactively")),
OPT_BOOL('n', "no-verify", &state.no_verify,
N_("bypass pre-applypatch and applypatch-msg hooks")),
OPT_HIDDEN_BOOL('b', "binary", &binary,
N_("historical option -- no-op")),
OPT_BOOL('3', "3way", &state.threeway,
N_("allow fall back on 3way merging if needed")),
OPT__QUIET(&state.quiet, N_("be quiet")),
OPT_SET_INT('s', "signoff", &state.signoff,
N_("add a Signed-off-by trailer to the commit message"),
SIGNOFF_EXPLICIT),
OPT_BOOL('u', "utf8", &state.utf8,
N_("recode into utf8 (default)")),
OPT_SET_INT('k', "keep", &state.keep,
N_("pass -k flag to git-mailinfo"), KEEP_TRUE),
OPT_SET_INT(0, "keep-non-patch", &state.keep,
N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
OPT_BOOL('m', "message-id", &state.message_id,
N_("pass -m flag to git-mailinfo")),
OPT_SET_INT(0, "keep-cr", &keep_cr,
N_("pass --keep-cr flag to git-mailsplit for mbox format"),
1),
OPT_BOOL('c', "scissors", &state.scissors,
N_("strip everything before a scissors line")),
OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
N_("pass it through git-mailinfo"),
PARSE_OPT_NONEG, am_option_parse_quoted_cr),
OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),
N_("pass it through git-apply"),
0),
OPT_PASSTHRU_ARGV(0, "ignore-space-change", &state.git_apply_opts, NULL,
N_("pass it through git-apply"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &state.git_apply_opts, NULL,
N_("pass it through git-apply"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "directory", &state.git_apply_opts, N_("root"),
N_("pass it through git-apply"),
0),
OPT_PASSTHRU_ARGV(0, "exclude", &state.git_apply_opts, N_("path"),
N_("pass it through git-apply"),
0),
OPT_PASSTHRU_ARGV(0, "include", &state.git_apply_opts, N_("path"),
N_("pass it through git-apply"),
0),
OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts, N_("n"),
N_("pass it through git-apply"),
0),
OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts, N_("num"),
N_("pass it through git-apply"),
0),
OPT_CALLBACK(0, "patch-format", &patch_format, N_("format"),
N_("format the patch(es) are in"),
parse_opt_patchformat),
OPT_PASSTHRU_ARGV(0, "reject", &state.git_apply_opts, NULL,
N_("pass it through git-apply"),
PARSE_OPT_NOARG),
OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
N_("override error message when patch failure occurs")),
OPT_CMDMODE(0, "continue", &resume_mode,
N_("continue applying patches after resolving a conflict"),
RESUME_RESOLVED),
OPT_CMDMODE('r', "resolved", &resume_mode,
N_("synonyms for --continue"),
RESUME_RESOLVED),
OPT_CMDMODE(0, "skip", &resume_mode,
N_("skip the current patch"),
RESUME_SKIP),
OPT_CMDMODE(0, "abort", &resume_mode,
N_("restore the original branch and abort the patching operation"),
RESUME_ABORT),
OPT_CMDMODE(0, "quit", &resume_mode,
N_("abort the patching operation but keep HEAD where it is"),
RESUME_QUIT),
{
.type = OPTION_CALLBACK,
.long_name = "show-current-patch",
.value = &resume_mode,
.argh = "(diff|raw)",
.help = N_("show the patch being applied"),
.flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
.callback = parse_opt_show_current_patch,
.defval = RESUME_SHOW_PATCH_RAW,
},
OPT_CMDMODE(0, "retry", &resume_mode,
N_("try to apply current patch again"),
RESUME_APPLY),
OPT_CMDMODE(0, "allow-empty", &resume_mode,
N_("record the empty patch as an empty commit"),
RESUME_ALLOW_EMPTY),
OPT_BOOL(0, "committer-date-is-author-date",
&state.committer_date_is_author_date,
N_("lie about committer date")),
OPT_BOOL(0, "ignore-date", &state.ignore_date,
N_("use current timestamp for author date")),
OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),
{
.type = OPTION_STRING,
.short_name = 'S',
.long_name = "gpg-sign",
.value = &state.sign_commit,
.argh = N_("key-id"),
.help = N_("GPG-sign commits"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
N_("how to handle empty patches"),
PARSE_OPT_NONEG, am_option_parse_empty),
OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
N_("(internal use for git-rebase)")),
OPT_END()
};
show_usage_with_options_if_asked(argc, argv, usage, options);
git_config(git_default_config, NULL);
am_state_init(&state);
in_progress = am_in_progress(&state);
if (in_progress)
am_load(&state);
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (binary >= 0)
fprintf_ln(stderr, _("The -b/--binary option has been a no-op for long time, and\n"
"it will be removed. Please do not use it anymore."));
/* Ensure a valid committer ident can be constructed */
git_committer_info(IDENT_STRICT);
if (repo_read_index_preload(the_repository, NULL, 0) < 0)
die(_("failed to read the index"));
if (in_progress) {
/*
* Catch user error to feed us patches when there is a session
* in progress:
*
* 1. mbox path(s) are provided on the command-line.
* 2. stdin is not a tty: the user is trying to feed us a patch
* from standard input. This is somewhat unreliable -- stdin
* could be /dev/null for example and the caller did not
* intend to feed us a patch but wanted to continue
* unattended.
*/
if (argc || (resume_mode == RESUME_FALSE && !isatty(0)))
die(_("previous rebase directory %s still exists but mbox given."),
state.dir);
if (resume_mode == RESUME_FALSE)
resume_mode = RESUME_APPLY;
if (state.signoff == SIGNOFF_EXPLICIT)
am_append_signoff(&state);
} else {
struct strvec paths = STRVEC_INIT;
int i;
/*
* Handle stray state directory in the independent-run case. In
* the --rebasing case, it is up to the caller to take care of
* stray directories.
*/
if (file_exists(state.dir) && !state.rebasing) {
if (resume_mode == RESUME_ABORT || resume_mode == RESUME_QUIT) {
am_destroy(&state);
am_state_release(&state);
return 0;
}
die(_("Stray %s directory found.\n"
"Use \"git am --abort\" to remove it."),
state.dir);
}
if (resume_mode)
die(_("Resolve operation not in progress, we are not resuming."));
for (i = 0; i < argc; i++) {
if (is_absolute_path(argv[i]) || !prefix)
strvec_push(&paths, argv[i]);
else
strvec_push(&paths, mkpath("%s/%s", prefix, argv[i]));
}
if (state.interactive && !paths.nr)
die(_("interactive mode requires patches on the command line"));
am_setup(&state, patch_format, paths.v, keep_cr);
strvec_clear(&paths);
}
switch (resume_mode) {
case RESUME_FALSE:
am_run(&state, 0);
break;
case RESUME_APPLY:
am_run(&state, 1);
break;
case RESUME_RESOLVED:
case RESUME_ALLOW_EMPTY:
am_resolve(&state, resume_mode == RESUME_ALLOW_EMPTY ? 1 : 0);
break;
case RESUME_SKIP:
am_skip(&state);
break;
case RESUME_ABORT:
am_abort(&state);
break;
case RESUME_QUIT:
am_rerere_clear();
am_destroy(&state);
break;
case RESUME_SHOW_PATCH_RAW:
case RESUME_SHOW_PATCH_DIFF:
ret = show_patch(&state, resume_mode);
break;
default:
BUG("invalid resume value");
}
am_state_release(&state);
return ret;
}