format-patch: add --no-cc, --no-to, and --no-add-headers
[gitweb.git] / builtin-log.c
index 7b91c914236a8e196190663fdbc3be4581539791..e14c0a2a0191ca8b74ec76cf84b84c9b6b6d6ef5 100644 (file)
@@ -50,8 +50,17 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        if (default_date_mode)
                rev->date_mode = parse_date_format(default_date_mode);
 
+       /*
+        * Check for -h before setup_revisions(), or "git log -h" will
+        * fail when run without a git directory.
+        */
+       if (argc == 2 && !strcmp(argv[1], "-h"))
+               usage(builtin_log_usage);
        argc = setup_revisions(argc, argv, rev, "HEAD");
 
+       if (!rev->show_notes_given && !rev->pretty_given)
+               rev->show_notes = 1;
+
        if (rev->diffopt.pickaxe || rev->diffopt.filter)
                rev->always_show_header = 0;
        if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
@@ -449,35 +458,28 @@ static int auto_number = 1;
 
 static char *default_attach = NULL;
 
-static char **extra_hdr;
-static int extra_hdr_nr;
-static int extra_hdr_alloc;
-
-static char **extra_to;
-static int extra_to_nr;
-static int extra_to_alloc;
-
-static char **extra_cc;
-static int extra_cc_nr;
-static int extra_cc_alloc;
+static struct string_list extra_hdr;
+static struct string_list extra_to;
+static struct string_list extra_cc;
 
 static void add_header(const char *value)
 {
+       struct string_list_item *item;
        int len = strlen(value);
        while (len && value[len - 1] == '\n')
                len--;
+
        if (!strncasecmp(value, "to: ", 4)) {
-               ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc);
-               extra_to[extra_to_nr++] = xstrndup(value + 4, len - 4);
-               return;
+               item = string_list_append(value + 4, &extra_to);
+               len -= 4;
+       } else if (!strncasecmp(value, "cc: ", 4)) {
+               item = string_list_append(value + 4, &extra_cc);
+               len -= 4;
+       } else {
+               item = string_list_append(value, &extra_hdr);
        }
-       if (!strncasecmp(value, "cc: ", 4)) {
-               ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
-               extra_cc[extra_cc_nr++] = xstrndup(value + 4, len - 4);
-               return;
-       }
-       ALLOC_GROW(extra_hdr, extra_hdr_nr + 1, extra_hdr_alloc);
-       extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
+
+       item->string[len] = '\0';
 }
 
 #define THREAD_SHALLOW 1
@@ -495,11 +497,16 @@ static int git_format_config(const char *var, const char *value, void *cb)
        }
        if (!strcmp(var, "format.suffix"))
                return git_config_string(&fmt_patch_suffix, var, value);
+       if (!strcmp(var, "format.to")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               string_list_append(value, &extra_to);
+               return 0;
+       }
        if (!strcmp(var, "format.cc")) {
                if (!value)
                        return config_error_nonbool(var);
-               ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
-               extra_cc[extra_cc_nr++] = xstrdup(value);
+               string_list_append(value, &extra_cc);
                return 0;
        }
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
@@ -561,7 +568,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev)
 
        get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
 
-       if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
+       if (!DIFF_OPT_TST(&rev->diffopt, QUICK))
                fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
 
        if (freopen(filename.buf, "w", stdout) == NULL)
@@ -862,14 +869,31 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
 
 static int header_callback(const struct option *opt, const char *arg, int unset)
 {
-       add_header(arg);
+       if (unset) {
+               string_list_clear(&extra_hdr, 0);
+               string_list_clear(&extra_to, 0);
+               string_list_clear(&extra_cc, 0);
+       } else {
+           add_header(arg);
+       }
+       return 0;
+}
+
+static int to_callback(const struct option *opt, const char *arg, int unset)
+{
+       if (unset)
+               string_list_clear(&extra_to, 0);
+       else
+               string_list_append(arg, &extra_to);
        return 0;
 }
 
 static int cc_callback(const struct option *opt, const char *arg, int unset)
 {
-       ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
-       extra_cc[extra_cc_nr++] = xstrdup(arg);
+       if (unset)
+               string_list_clear(&extra_cc, 0);
+       else
+               string_list_append(arg, &extra_cc);
        return 0;
 }
 
@@ -921,16 +945,18 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                            PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
                OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
                            "don't output binary diffs"),
-               OPT_BOOLEAN('p', NULL, &use_patch_format,
-                       "show patch format instead of default (patch + stat)"),
                OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
                            "don't include a patch matching a commit upstream"),
+               { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
+                 "show patch format instead of default (patch + stat)",
+                 PARSE_OPT_NONEG | PARSE_OPT_NOARG },
                OPT_GROUP("Messaging"),
                { OPTION_CALLBACK, 0, "add-header", NULL, "header",
-                           "add email header", PARSE_OPT_NONEG,
-                           header_callback },
+                           "add email header", 0, header_callback },
+               { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
+                           0, to_callback },
                { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
-                           PARSE_OPT_NONEG, cc_callback },
+                           0, cc_callback },
                OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
                            "make first mail a reply to <message-id>"),
                { OPTION_CALLBACK, 0, "attach", &rev, "boundary",
@@ -946,6 +972,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
+       extra_hdr.strdup_strings = 1;
+       extra_to.strdup_strings = 1;
+       extra_cc.strdup_strings = 1;
        git_config(git_format_config, NULL);
        init_revisions(&rev, prefix);
        rev.commit_format = CMIT_FMT_EMAIL;
@@ -969,7 +998,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
         */
        argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
                             builtin_format_patch_usage,
-                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
+                            PARSE_OPT_KEEP_DASHDASH);
 
        if (do_signoff) {
                const char *committer;
@@ -981,29 +1011,29 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                add_signoff = xmemdupz(committer, endpos - committer + 1);
        }
 
-       for (i = 0; i < extra_hdr_nr; i++) {
-               strbuf_addstr(&buf, extra_hdr[i]);
+       for (i = 0; i < extra_hdr.nr; i++) {
+               strbuf_addstr(&buf, extra_hdr.items[i].string);
                strbuf_addch(&buf, '\n');
        }
 
-       if (extra_to_nr)
+       if (extra_to.nr)
                strbuf_addstr(&buf, "To: ");
-       for (i = 0; i < extra_to_nr; i++) {
+       for (i = 0; i < extra_to.nr; i++) {
                if (i)
                        strbuf_addstr(&buf, "    ");
-               strbuf_addstr(&buf, extra_to[i]);
-               if (i + 1 < extra_to_nr)
+               strbuf_addstr(&buf, extra_to.items[i].string);
+               if (i + 1 < extra_to.nr)
                        strbuf_addch(&buf, ',');
                strbuf_addch(&buf, '\n');
        }
 
-       if (extra_cc_nr)
+       if (extra_cc.nr)
                strbuf_addstr(&buf, "Cc: ");
-       for (i = 0; i < extra_cc_nr; i++) {
+       for (i = 0; i < extra_cc.nr; i++) {
                if (i)
                        strbuf_addstr(&buf, "    ");
-               strbuf_addstr(&buf, extra_cc[i]);
-               if (i + 1 < extra_cc_nr)
+               strbuf_addstr(&buf, extra_cc.items[i].string);
+               if (i + 1 < extra_cc.nr)
                        strbuf_addch(&buf, ',');
                strbuf_addch(&buf, '\n');
        }
@@ -1030,11 +1060,20 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        if (argc > 1)
                die ("unrecognized argument: %s", argv[1]);
 
-       if (use_patch_format)
-               rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
-       else if (!rev.diffopt.output_format ||
-                 rev.diffopt.output_format == DIFF_FORMAT_PATCH)
-               rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH;
+       if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
+               die("--name-only does not make sense");
+       if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
+               die("--name-status does not make sense");
+       if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
+               die("--check does not make sense");
+
+       if (!use_patch_format &&
+               (!rev.diffopt.output_format ||
+                rev.diffopt.output_format == DIFF_FORMAT_PATCH))
+               rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
+
+       /* Always generate a patch */
+       rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
 
        if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
                DIFF_OPT_SET(&rev.diffopt, BINARY);
@@ -1203,6 +1242,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        fclose(stdout);
        }
        free(list);
+       string_list_clear(&extra_to, 0);
+       string_list_clear(&extra_cc, 0);
+       string_list_clear(&extra_hdr, 0);
        if (ignore_if_in_upstream)
                free_patch_ids(&ids);
        return 0;
@@ -1242,6 +1284,9 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                argv++;
        }
 
+       if (argc > 1 && !strcmp(argv[1], "-h"))
+               usage(cherry_usage);
+
        switch (argc) {
        case 4:
                limit = argv[3];
@@ -1309,8 +1354,9 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
 
                if (verbose) {
                        struct strbuf buf = STRBUF_INIT;
+                       struct pretty_print_context ctx = {0};
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                           &buf, 0, NULL, NULL, 0, 0);
+                                           &buf, &ctx);
                        printf("%c %s %s\n", sign,
                               sha1_to_hex(commit->object.sha1), buf.buf);
                        strbuf_release(&buf);