X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=builtin%2Frevert.c;h=9215e665046a8991b57f8d4cfda123dae084414c;hb=2eb54692d145a0c2939698302e913975f059ac34;hp=7976b5a3295d4c70f003212485680f4dd3ceead2;hpb=6cd52edbbd9acc7797cffeba1b849538285ed558;p=git.git diff --git a/builtin/revert.c b/builtin/revert.c index 7976b5a32..9215e6650 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -39,7 +39,8 @@ static const char * const cherry_pick_usage[] = { static int edit, no_replay, no_commit, mainline, signoff, allow_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; -static const char *commit_name; +static int commit_argc; +static const char **commit_argv; static int allow_rerere_auto; static const char *me; @@ -49,16 +50,18 @@ static const char *strategy; static char *get_encoding(const char *message); +static const char * const *revert_or_cherry_pick_usage(void) +{ + return action == REVERT ? revert_usage : cherry_pick_usage; +} + static void parse_args(int argc, const char **argv) { - const char * const * usage_str = - action == REVERT ? revert_usage : cherry_pick_usage; - unsigned char sha1[20]; + const char * const * usage_str = revert_or_cherry_pick_usage(); int noop; struct option options[] = { OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"), OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"), - OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"), OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"), OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), OPT_INTEGER('m', "mainline", &mainline, "parent number"), @@ -71,6 +74,7 @@ static void parse_args(int argc, const char **argv) if (action == CHERRY_PICK) { struct option cp_extra[] = { + OPT_BOOLEAN('x', NULL, &no_replay, "append commit name"), OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), OPT_END(), }; @@ -78,15 +82,13 @@ static void parse_args(int argc, const char **argv) die("program error"); } - if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1) + commit_argc = parse_options(argc, argv, NULL, options, usage_str, + PARSE_OPT_KEEP_ARGV0 | + PARSE_OPT_KEEP_UNKNOWN); + if (commit_argc < 2) usage_with_options(usage_str, options); - commit_name = argv[0]; - if (get_sha1(commit_name, sha1)) - die ("Cannot find '%s'", commit_name); - commit = lookup_commit_reference(sha1); - if (!commit) - exit(1); + commit_argv = argv; } struct commit_message { @@ -100,9 +102,9 @@ struct commit_message { static int get_message(const char *raw_message, struct commit_message *out) { const char *encoding; - const char *p, *abbrev, *eol; + const char *abbrev, *subject; + int abbrev_len, subject_len; char *q; - int abbrev_len, oneline_len; if (!raw_message) return -1; @@ -123,27 +125,17 @@ static int get_message(const char *raw_message, struct commit_message *out) abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); abbrev_len = strlen(abbrev); - /* Find beginning and end of commit subject. */ - p = out->message; - while (*p && (*p != '\n' || p[1] != '\n')) - p++; - if (*p) { - p += 2; - for (eol = p + 1; *eol && *eol != '\n'; eol++) - ; /* do nothing */ - } else - eol = p; - oneline_len = eol - p; + subject_len = find_commit_subject(out->message, &subject); out->parent_label = xmalloc(strlen("parent of ") + abbrev_len + - strlen("... ") + oneline_len + 1); + strlen("... ") + subject_len + 1); q = out->parent_label; q = mempcpy(q, "parent of ", strlen("parent of ")); out->label = q; q = mempcpy(q, abbrev, abbrev_len); q = mempcpy(q, "... ", strlen("... ")); out->subject = q; - q = mempcpy(q, p, oneline_len); + q = mempcpy(q, subject, subject_len); *q = '\0'; return 0; } @@ -239,7 +231,7 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } -static char *help_msg(const char *name) +static char *help_msg(void) { struct strbuf helpbuf = STRBUF_INIT; char *msg = getenv("GIT_CHERRY_PICK_HELP"); @@ -255,7 +247,7 @@ static char *help_msg(const char *name) strbuf_addf(&helpbuf, " with: \n" "\n" " git commit -c %s\n", - name); + sha1_to_hex(commit->object.sha1)); } else strbuf_addch(&helpbuf, '.'); @@ -357,7 +349,7 @@ static void do_recursive_merge(struct commit *base, struct commit *next, } write_message(msgbuf, defmsg); fprintf(stderr, "Automatic %s failed.%s\n", - me, help_msg(commit_name)); + me, help_msg()); rerere(allow_rerere_auto); exit(1); } @@ -365,7 +357,7 @@ static void do_recursive_merge(struct commit *base, struct commit *next, fprintf(stderr, "Finished one %s.\n", me); } -static int revert_or_cherry_pick(int argc, const char **argv) +static int do_pick_commit(void) { unsigned char head[20]; struct commit *base, *next, *parent; @@ -374,28 +366,6 @@ static int revert_or_cherry_pick(int argc, const char **argv) char *defmsg = NULL; struct strbuf msgbuf = STRBUF_INIT; - git_config(git_default_config, NULL); - me = action == REVERT ? "revert" : "cherry-pick"; - setenv(GIT_REFLOG_ACTION, me, 0); - parse_args(argc, argv); - - /* this is copied from the shell script, but it's never triggered... */ - if (action == REVERT && !no_replay) - die("revert is incompatible with replay"); - - if (allow_ff) { - if (signoff) - die("cherry-pick --ff cannot be used with --signoff"); - if (no_commit) - die("cherry-pick --ff cannot be used with --no-commit"); - if (no_replay) - die("cherry-pick --ff cannot be used with -x"); - if (edit) - die("cherry-pick --ff cannot be used with --edit"); - } - - if (read_cache() < 0) - die("git %s: failed to read the index", me); if (no_commit) { /* * We do not intend to commit immediately. We just want to @@ -506,12 +476,14 @@ static int revert_or_cherry_pick(int argc, const char **argv) free_commit_list(remotes); if (res) { fprintf(stderr, "Automatic %s with strategy %s failed.%s\n", - me, strategy, help_msg(commit_name)); + me, strategy, help_msg()); rerere(allow_rerere_auto); exit(1); } } + free_message(&msg); + /* * * If we are cherry-pick, and if the merge did not result in @@ -524,7 +496,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (!no_commit) { /* 6 is max possible length of our args array including NULL */ const char *args[6]; + int res; int i = 0; + args[i++] = "commit"; args[i++] = "-n"; if (signoff) @@ -534,26 +508,81 @@ static int revert_or_cherry_pick(int argc, const char **argv) args[i++] = defmsg; } args[i] = NULL; - return execv_git_cmd(args); + res = run_command_v_opt(args, RUN_GIT_CMD); + free(defmsg); + + return res; } - free_message(&msg); + free(defmsg); return 0; } +static void prepare_revs(struct rev_info *revs) +{ + int argc; + + init_revisions(revs, NULL); + revs->no_walk = 1; + if (action != REVERT) + revs->reverse = 1; + + argc = setup_revisions(commit_argc, commit_argv, revs, NULL); + if (argc > 1) + usage(*revert_or_cherry_pick_usage()); + + if (prepare_revision_walk(revs)) + die("revision walk setup failed"); + + if (!revs->commits) + die("empty commit set passed"); +} + +static int revert_or_cherry_pick(int argc, const char **argv) +{ + struct rev_info revs; + + git_config(git_default_config, NULL); + me = action == REVERT ? "revert" : "cherry-pick"; + setenv(GIT_REFLOG_ACTION, me, 0); + parse_args(argc, argv); + + if (allow_ff) { + if (signoff) + die("cherry-pick --ff cannot be used with --signoff"); + if (no_commit) + die("cherry-pick --ff cannot be used with --no-commit"); + if (no_replay) + die("cherry-pick --ff cannot be used with -x"); + if (edit) + die("cherry-pick --ff cannot be used with --edit"); + } + + if (read_cache() < 0) + die("git %s: failed to read the index", me); + + prepare_revs(&revs); + + while ((commit = get_revision(&revs))) { + int res = do_pick_commit(); + if (res) + return res; + } + + return 0; +} + int cmd_revert(int argc, const char **argv, const char *prefix) { if (isatty(0)) edit = 1; - no_replay = 1; action = REVERT; return revert_or_cherry_pick(argc, argv); } int cmd_cherry_pick(int argc, const char **argv, const char *prefix) { - no_replay = 0; action = CHERRY_PICK; return revert_or_cherry_pick(argc, argv); }