Code

revert: do not rebuild argv on heap
[git.git] / builtin / revert.c
index aee10692ba07238ffe11dfdfa06edaf48d829774..8b9d829a73a0862dfdf2c2499b18878489620f16 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;
@@ -49,11 +50,14 @@ 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"),
@@ -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 {
@@ -527,8 +529,30 @@ static int do_pick_commit(void)
        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);
@@ -548,7 +572,15 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        if (read_cache() < 0)
                die("git %s: failed to read the index", me);
 
-       return do_pick_commit();
+       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)