revert: pass around rev-list args in already-parsed form
authorJonathan Nieder <jrnieder@gmail.com>
Sat, 13 Aug 2011 17:06:23 +0000 (12:06 -0500)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Dec 2011 21:32:16 +0000 (13:32 -0800)
Since 7e2bfd3f (revert: allow cherry-picking more than one commit,
2010-07-02), the pick/revert machinery has kept track of the set of
commits to be cherry-picked or reverted using commit_argc and
commit_argv variables, storing the corresponding command-line
parameters.

Future callers as other commands are built in (am, rebase, sequencer)
may find it easier to pass rev-list options to this machinery in
already-parsed form.  Teach cmd_cherry_pick and cmd_revert to parse
the rev-list arguments in advance and pass the commit set to
pick_revisions() as a rev_info structure.

Original patch by Jonathan, tweaks and test from Ram.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/revert.c
t/t3510-cherry-pick-sequence.sh

index a43b4d85fbddb8adb024bc23785894ca4cd20ef5..f7f4bb35774db6445348b41c61dd2c27883d2381 100644 (file)
@@ -60,13 +60,14 @@ struct replay_opts {
        int allow_rerere_auto;
 
        int mainline;
-       int commit_argc;
-       const char **commit_argv;
 
        /* Merge strategy */
        const char *strategy;
        const char **xopts;
        size_t xopts_nr, xopts_alloc;
+
+       /* Only used by REPLAY_NONE */
+       struct rev_info *revs;
 };
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -169,9 +170,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
                        die(_("program error"));
        }
 
-       opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
-                                       PARSE_OPT_KEEP_ARGV0 |
-                                       PARSE_OPT_KEEP_UNKNOWN);
+       argc = parse_options(argc, argv, NULL, options, usage_str,
+                       PARSE_OPT_KEEP_ARGV0 |
+                       PARSE_OPT_KEEP_UNKNOWN);
 
        /* Check for incompatible subcommands */
        verify_opt_mutually_compatible(me,
@@ -213,9 +214,6 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
                                NULL);
        }
 
-       else if (opts->commit_argc < 2)
-               usage_with_options(usage_str, options);
-
        if (opts->allow_ff)
                verify_opt_compatible(me, "--ff",
                                "--signoff", opts->signoff,
@@ -223,7 +221,20 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
                                "-x", opts->record_origin,
                                "--edit", opts->edit,
                                NULL);
-       opts->commit_argv = argv;
+
+       if (opts->subcommand != REPLAY_NONE) {
+               opts->revs = NULL;
+       } else {
+               opts->revs = xmalloc(sizeof(*opts->revs));
+               init_revisions(opts->revs, NULL);
+               opts->revs->no_walk = 1;
+               if (argc < 2)
+                       usage_with_options(usage_str, options);
+               argc = setup_revisions(argc, argv, opts->revs, NULL);
+       }
+
+       if (argc > 1)
+               usage_with_options(usage_str, options);
 }
 
 struct commit_message {
@@ -631,23 +642,15 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
        return res;
 }
 
-static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
+static void prepare_revs(struct replay_opts *opts)
 {
-       int argc;
-
-       init_revisions(revs, NULL);
-       revs->no_walk = 1;
        if (opts->action != REVERT)
-               revs->reverse = 1;
+               opts->revs->reverse ^= 1;
 
-       argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
-       if (argc > 1)
-               usage(*revert_or_cherry_pick_usage(opts));
-
-       if (prepare_revision_walk(revs))
+       if (prepare_revision_walk(opts->revs))
                die(_("revision walk setup failed"));
 
-       if (!revs->commits)
+       if (!opts->revs->commits)
                die(_("empty commit set passed"));
 }
 
@@ -844,14 +847,13 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
 static void walk_revs_populate_todo(struct commit_list **todo_list,
                                struct replay_opts *opts)
 {
-       struct rev_info revs;
        struct commit *commit;
        struct commit_list **next;
 
-       prepare_revs(&revs, opts);
+       prepare_revs(opts);
 
        next = todo_list;
-       while ((commit = get_revision(&revs)))
+       while ((commit = get_revision(opts->revs)))
                next = commit_list_append(commit, next);
 }
 
@@ -1075,6 +1077,9 @@ static int pick_revisions(struct replay_opts *opts)
        struct commit_list *todo_list = NULL;
        unsigned char sha1[20];
 
+       if (opts->subcommand == REPLAY_NONE)
+               assert(opts->revs);
+
        read_and_refresh_cache(opts);
 
        /*
index 4d1883b7342670a997b460c398277344021adeb7..56c95ec18c5061ef8ac760503dd6fd16f72779c3 100755 (executable)
@@ -461,4 +461,9 @@ test_expect_success 'malformed instruction sheet 2' '
        test_must_fail git cherry-pick --continue
 '
 
+test_expect_success 'empty commit set' '
+       pristine_detach initial &&
+       test_expect_code 128 git cherry-pick base..base
+'
+
 test_done