Merge branch 'mh/packed-ref-store' into next
[gitweb.git] / builtin / shortlog.c
index bfc082e58467953c1e4c96fd27a884abea4f5127..43c4799ea9a9d963f9a44be5cd0ee5bc511e73df 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "config.h"
 #include "commit.h"
 #include "diff.h"
 #include "string-list.h"
@@ -117,11 +118,15 @@ static void read_from_stdin(struct shortlog *log)
 {
        struct strbuf author = STRBUF_INIT;
        struct strbuf oneline = STRBUF_INIT;
+       static const char *author_match[2] = { "Author: ", "author " };
+       static const char *committer_match[2] = { "Commit: ", "committer " };
+       const char **match;
 
+       match = log->committer ? committer_match : author_match;
        while (strbuf_getline_lf(&author, stdin) != EOF) {
                const char *v;
-               if (!skip_prefix(author.buf, "Author: ", &v) &&
-                   !skip_prefix(author.buf, "author ", &v))
+               if (!skip_prefix(author.buf, match[0], &v) &&
+                   !skip_prefix(author.buf, match[1], &v))
                        continue;
                while (strbuf_getline_lf(&oneline, stdin) != EOF &&
                       oneline.len)
@@ -140,15 +145,17 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
        struct strbuf author = STRBUF_INIT;
        struct strbuf oneline = STRBUF_INIT;
        struct pretty_print_context ctx = {0};
+       const char *fmt;
 
        ctx.fmt = CMIT_FMT_USERFORMAT;
        ctx.abbrev = log->abbrev;
-       ctx.subject = "";
-       ctx.after_subject = "";
+       ctx.print_email_subject = 1;
        ctx.date_mode.type = DATE_NORMAL;
        ctx.output_encoding = get_log_output_encoding();
 
-       format_commit_message(commit, "%an <%ae>", &author, &ctx);
+       fmt = log->committer ? "%cn <%ce>" : "%an <%ae>";
+
+       format_commit_message(commit, fmt, &author, &ctx);
        if (!log->summary) {
                if (log->user_format)
                        pretty_print_commit(&ctx, commit, &oneline);
@@ -233,11 +240,13 @@ void shortlog_init(struct shortlog *log)
 
 int cmd_shortlog(int argc, const char **argv, const char *prefix)
 {
-       static struct shortlog log;
-       static struct rev_info rev;
+       struct shortlog log = { STRING_LIST_INIT_NODUP };
+       struct rev_info rev;
        int nongit = !startup_info->have_repository;
 
-       static const struct option options[] = {
+       const struct option options[] = {
+               OPT_BOOL('c', "committer", &log.committer,
+                        N_("Group by committer rather than author")),
                OPT_BOOL('n', "numbered", &log.sort_by_number,
                         N_("sort output according to the number of commits per author")),
                OPT_BOOL('s', "summary", &log.summary,
@@ -276,6 +285,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 
        log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
        log.abbrev = rev.abbrev;
+       log.file = rev.diffopt.file;
 
        /* assume HEAD if from a tty */
        if (!nongit && !rev.pending.nr && isatty(0))
@@ -289,6 +299,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
                get_from_rev(&rev, &log);
 
        shortlog_output(&log);
+       if (log.file != stdout)
+               fclose(log.file);
        return 0;
 }
 
@@ -305,27 +317,29 @@ void shortlog_output(struct shortlog *log)
        struct strbuf sb = STRBUF_INIT;
 
        if (log->sort_by_number)
-               qsort(log->list.items, log->list.nr, sizeof(struct string_list_item),
+               QSORT(log->list.items, log->list.nr,
                      log->summary ? compare_by_counter : compare_by_list);
        for (i = 0; i < log->list.nr; i++) {
                const struct string_list_item *item = &log->list.items[i];
                if (log->summary) {
-                       printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string);
+                       fprintf(log->file, "%6d\t%s\n",
+                               (int)UTIL_TO_INT(item), item->string);
                } else {
                        struct string_list *onelines = item->util;
-                       printf("%s (%d):\n", item->string, onelines->nr);
+                       fprintf(log->file, "%s (%d):\n",
+                               item->string, onelines->nr);
                        for (j = onelines->nr - 1; j >= 0; j--) {
                                const char *msg = onelines->items[j].string;
 
                                if (log->wrap_lines) {
                                        strbuf_reset(&sb);
                                        add_wrapped_shortlog_msg(&sb, msg, log);
-                                       fwrite(sb.buf, sb.len, 1, stdout);
+                                       fwrite(sb.buf, sb.len, 1, log->file);
                                }
                                else
-                                       printf("      %s\n", msg);
+                                       fprintf(log->file, "      %s\n", msg);
                        }
-                       putchar('\n');
+                       putc('\n', log->file);
                        onelines->strdup_strings = 1;
                        string_list_clear(onelines, 0);
                        free(onelines);