merge-recursive --renormalize
[gitweb.git] / builtin / revert.c
index 02f18c2208ed67db5f8eb93c1e408e97173d7031..11132533c6d597ee6f920f5e78e8171cc5f30a44 100644 (file)
@@ -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;
@@ -53,7 +54,6 @@ 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];
        int noop;
        struct option options[] = {
                OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"),
@@ -78,15 +78,11 @@ 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, 0);
+       if (commit_argc < 1)
                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 {
@@ -239,7 +235,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 +251,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, '.');
@@ -322,6 +318,13 @@ static void do_recursive_merge(struct commit *base, struct commit *next,
        index_fd = hold_locked_index(&index_lock, 1);
 
        read_cache();
+
+       /*
+        * NEEDSWORK: cherry-picking between branches with
+        * different end-of-line normalization is a pain;
+        * plumb in an option to set o.renormalize?
+        * (or better: arbitrary -X options)
+        */
        init_merge_options(&o);
        o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
@@ -357,7 +360,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 +368,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,24 +377,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);
-
-       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
@@ -502,7 +487,7 @@ 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);
                }
@@ -545,6 +530,65 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        return 0;
 }
 
+static void prepare_revs(struct rev_info *revs)
+{
+       int argc = 0;
+       int i;
+       const char **argv = xmalloc((commit_argc + 4) * sizeof(*argv));
+
+       argv[argc++] = NULL;
+       argv[argc++] = "--no-walk";
+       if (action != REVERT)
+               argv[argc++] = "--reverse";
+       for (i = 0; i < commit_argc; i++)
+               argv[argc++] = commit_argv[i];
+       argv[argc++] = NULL;
+
+       init_revisions(revs, NULL);
+       setup_revisions(argc - 1, argv, revs, NULL);
+       if (prepare_revision_walk(revs))
+               die("revision walk setup failed");
+
+       if (!revs->commits)
+               die("empty commit set passed");
+
+       free(argv);
+}
+
+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))