From 8fe700ae2970e85887c4f4ae8c5f0ee4e3dff611 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 15 Jul 2009 13:08:36 +0200 Subject: [PATCH] shortlog: add '--sort-key' and '--sort-key-regexp' options Instead of always sorting by author, allow to sort by either a whitespace-delimited field or by a regular expression (first group) on the oneline. For example, this will give you an overview of the weekday/commit distribution: git shortlog -k 1 --pretty=%cD -s -n Signed-off-by: Johannes Schindelin --- Documentation/git-shortlog.txt | 13 ++++++++- builtin-shortlog.c | 64 +++++++++++++++++++++++++++++++++++++++--- shortlog.h | 1 + 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 42463a955d..3155361bb0 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w] -git shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[[,[,]]]] [...] +git shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[[,[,]]]] [(-K|--sort-key-regexp) ] [(-k|--sort-key) ] [...] DESCRIPTION ----------- @@ -45,6 +45,17 @@ OPTIONS and subsequent lines are indented by `indent2` spaces. `width`, `indent1`, and `indent2` default to 76, 6 and 9 respectively. +-K :: +--sort-key-regexp :: + Instead of sorting by author, sort by a regular expression on the + commit subject (or whatever you specified using --pretty) + +-k :: +--sort-key :: + Instead of sorting by author, sort by a given whitespace-delimited + field of the commit subject (or whatever you specified using + --pretty). The first field is 1. + MAPPING AUTHORS --------------- diff --git a/builtin-shortlog.c b/builtin-shortlog.c index a684422667..2cab5e4e67 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -145,9 +145,37 @@ static void read_from_stdin(struct shortlog *log) void shortlog_add_commit(struct shortlog *log, struct commit *commit) { + struct strbuf buf = STRBUF_INIT; + char *key = NULL; const char *author = NULL, *buffer; buffer = commit->buffer; + if (log->user_format) + pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, + DEFAULT_ABBREV, "", "", DATE_NORMAL, 0); + + if (log->sort_key) { + const char *p = buf.buf; + regmatch_t match[2]; + + if (!log->user_format) { + p = strstr(buffer, "\n\n"); + if (!p) + return; + p += 2; + } + + if (!regexec(log->sort_key, p, 2, match, 0) && + match[1].rm_so >= 0) + author = key = xstrndup(p + match[1].rm_so, + match[1].rm_eo - match[1].rm_so); + else + author = ""; + insert_one_record1(log, key, p); + strbuf_release(&buf); + return; + } + while (*buffer && *buffer != '\n') { const char *eol = strchr(buffer, '\n'); @@ -164,10 +192,6 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) die("Missing author: %s", sha1_to_hex(commit->object.sha1)); if (log->user_format) { - struct strbuf buf = STRBUF_INIT; - - pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, - DEFAULT_ABBREV, "", "", DATE_NORMAL, 0); insert_one_record(log, author, buf.buf); strbuf_release(&buf); return; @@ -175,6 +199,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) if (*buffer) buffer++; insert_one_record(log, author, !*buffer ? "" : buffer); + free(key); } static void get_from_rev(struct rev_info *rev, struct shortlog *log) @@ -250,6 +275,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) { static struct shortlog log; static struct rev_info rev; + static const char *sort_key_regexp = NULL; + static int sort_key_field = 0; int nongit; static const struct option options[] = { @@ -261,6 +288,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) "Show the email address of each author"), { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]", "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args }, + OPT_STRING('K', "sort-key-regexp", &sort_key_regexp, "", + "Sort shortlog by the given regular expression"), + OPT_INTEGER('k', "sort-key", &sort_key_field, + "Sort shortlog by the given field " + "(whitespace-delimited)"), OPT_END(), }; @@ -285,6 +317,27 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) parse_done: argc = parse_options_end(&ctx); + if (sort_key_regexp && sort_key_field > 0) + die ("--sort-key-regexp and --sort-key-field are incompatible"); + + if (sort_key_regexp) { + log.sort_key = xmalloc(sizeof(*log.sort_key)); + if (regcomp(log.sort_key, sort_key_regexp, 0)) + die ("Invalid regular expression: '%s'", + sort_key_regexp); + } + if (sort_key_field > 0) { + struct strbuf regexp = STRBUF_INIT; + strbuf_addstr(®exp, "^[ \t\n]*"); + while (--sort_key_field) + strbuf_addstr(®exp, "[^ \t\n]*[ \t\n]*"); + strbuf_addstr(®exp, "\\([^ \t\n]*\\)[ \t\n]*.*$"); + log.sort_key = xmalloc(sizeof(*log.sort_key)); + if (regcomp(log.sort_key, regexp.buf, 0)) + die ("Invalid regular expression: '%s'", regexp.buf); + strbuf_release(®exp); + } + if (setup_revisions(argc, argv, &rev, NULL) != 1) { error("unrecognized argument: %s", argv[1]); usage_with_options(shortlog_usage, options); @@ -296,6 +349,9 @@ parse_done: if (!nongit && !rev.pending.nr && isatty(0)) add_head_to_pending(&rev); if (rev.pending.nr == 0) { + if (log.sort_key) + die ("Specifying a sort key is incompatible with " + "reading from stdin."); read_from_stdin(&log); } else diff --git a/shortlog.h b/shortlog.h index bc02cc29ef..9dedaf6fbd 100644 --- a/shortlog.h +++ b/shortlog.h @@ -16,6 +16,7 @@ struct shortlog { char *common_repo_prefix; int email; struct string_list mailmap; + regex_t *sort_key; }; void shortlog_init(struct shortlog *log); -- 2.11.4.GIT