Introduce advise() to print hints
[gitweb.git] / builtin / revert.c
index 853e9e406c7fe258c39fa7e5c53f15f739a935b1..74c1581fdc73129e61c2ade90701900586e3ee82 100644 (file)
@@ -50,10 +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;
+       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,8 +82,10 @@ static void parse_args(int argc, const char **argv)
                        die("program error");
        }
 
-       commit_argc = parse_options(argc, argv, NULL, options, usage_str, 0);
-       if (commit_argc < 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_argv = argv;
@@ -235,6 +241,15 @@ static void set_author_ident_env(const char *message)
                        sha1_to_hex(commit->object.sha1));
 }
 
+static void advise(const char *advice, ...)
+{
+       va_list params;
+
+       va_start(params, advice);
+       vreportf("hint: ", advice, params);
+       va_end(params);
+}
+
 static char *help_msg(void)
 {
        struct strbuf helpbuf = STRBUF_INIT;
@@ -305,10 +320,9 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from)
        return write_ref_sha1(ref_lock, to, "cherry-pick");
 }
 
-static void do_recursive_merge(struct commit *base, struct commit *next,
-                              const char *base_label, const char *next_label,
-                              unsigned char *head, struct strbuf *msgbuf,
-                              char *defmsg)
+static int do_recursive_merge(struct commit *base, struct commit *next,
+                             const char *base_label, const char *next_label,
+                             unsigned char *head, struct strbuf *msgbuf)
 {
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
@@ -351,14 +365,35 @@ static void do_recursive_merge(struct commit *base, struct commit *next,
                                        i++;
                        }
                }
-               write_message(msgbuf, defmsg);
-               fprintf(stderr, "Automatic %s failed.%s\n",
-                       me, help_msg());
-               rerere(allow_rerere_auto);
-               exit(1);
        }
-       write_message(msgbuf, defmsg);
-       fprintf(stderr, "Finished one %s.\n", me);
+
+       return !clean;
+}
+
+/*
+ * If we are cherry-pick, and if the merge did not result in
+ * hand-editing, we will hit this commit and inherit the original
+ * author date and name.
+ * If we are revert, or if our cherry-pick results in a hand merge,
+ * we had better say that the current user is responsible for that.
+ */
+static int run_git_commit(const char *defmsg)
+{
+       /* 6 is max possible length of our args array including NULL */
+       const char *args[6];
+       int i = 0;
+
+       args[i++] = "commit";
+       args[i++] = "-n";
+       if (signoff)
+               args[i++] = "-s";
+       if (!edit) {
+               args[i++] = "-F";
+               args[i++] = defmsg;
+       }
+       args[i] = NULL;
+
+       return run_command_v_opt(args, RUN_GIT_CMD);
 }
 
 static int do_pick_commit(void)
@@ -369,6 +404,8 @@ static int do_pick_commit(void)
        struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        char *defmsg = NULL;
        struct strbuf msgbuf = STRBUF_INIT;
+       struct strbuf mebuf = STRBUF_INIT;
+       int res;
 
        if (no_commit) {
                /*
@@ -464,88 +501,62 @@ static int do_pick_commit(void)
                }
        }
 
-       if (!strategy || !strcmp(strategy, "recursive") || action == REVERT)
-               do_recursive_merge(base, next, base_label, next_label,
-                                  head, &msgbuf, defmsg);
-       else {
-               int res;
+       strbuf_addf(&mebuf, "%s of commit %s", me,
+                   find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
+
+       if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
+               res = do_recursive_merge(base, next, base_label, next_label,
+                                        head, &msgbuf);
+               write_message(&msgbuf, defmsg);
+       } else {
                struct commit_list *common = NULL;
                struct commit_list *remotes = NULL;
+
+               strbuf_addf(&mebuf, " with strategy %s", strategy);
                write_message(&msgbuf, defmsg);
+
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
                res = try_merge_command(strategy, common,
                                        sha1_to_hex(head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
-               if (res) {
-                       fprintf(stderr, "Automatic %s with strategy %s failed.%s\n",
-                               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
-        * hand-editing, we will hit this commit and inherit the original
-        * author date and name.
-        * If we are revert, or if our cherry-pick results in a hand merge,
-        * we had better say that the current user is responsible for that.
-        */
-
-       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)
-                       args[i++] = "-s";
-               if (!edit) {
-                       args[i++] = "-F";
-                       args[i++] = defmsg;
-               }
-               args[i] = NULL;
-               res = run_command_v_opt(args, RUN_GIT_CMD);
-               free(defmsg);
-
-               return res;
+       if (res) {
+               fprintf(stderr, "Automatic %s failed.%s\n",
+                       mebuf.buf, help_msg());
+               rerere(allow_rerere_auto);
+       } else {
+               if (!no_commit)
+                       res = run_git_commit(defmsg);
        }
 
+       strbuf_release(&mebuf);
+       free_message(&msg);
        free(defmsg);
 
-       return 0;
+       return res;
 }
 
 static void prepare_revs(struct rev_info *revs)
 {
-       int argc = 0;
-       int i;
-       const char **argv = xmalloc((commit_argc + 4) * sizeof(*argv));
+       int argc;
 
-       argv[argc++] = NULL;
-       argv[argc++] = "--no-walk";
+       init_revisions(revs, NULL);
+       revs->no_walk = 1;
        if (action != REVERT)
-               argv[argc++] = "--reverse";
-       for (i = 0; i < commit_argc; i++)
-               argv[argc++] = commit_argv[i];
-       argv[argc++] = NULL;
+               revs->reverse = 1;
+
+       argc = setup_revisions(commit_argc, commit_argv, revs, NULL);
+       if (argc > 1)
+               usage(*revert_or_cherry_pick_usage());
 
-       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)