{"thread":{"id":"20115","subject":"More 'shortlog' statistics models?","startedAt":"2009-07-15T02:07:16Z","lastAt":"2009-07-15T17:56:13Z","messageCount":8,"participants":["Linus Torvalds","Junio C Hamano","Johannes Schindelin","Jakub Narebski","Michał Kiedrowicz","Sverre Rabbelier"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"117997","messageId":"alpine.LFD.2.01.0907141852400.13838@localhost.localdomain","threadId":"20115","inReplyTo":null,"subject":"More 'shortlog' statistics models?","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2009-07-15T02:07:16Z","receivedAt":"2009-07-15T02:07:16Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nSo I was just thinking about one of the things I've wondered about for a \nwhile: when do I (and others) make most of my commits?\n\nI mean literally queries about time-of-day or day-of-week issues. I know \nwe have the information, and I can write silly scripts to get it, but I'm \nwondering if somebody would actually be willing to make our current \n'shortlog' statistics gatherer do it automatically.\n\nRight now shortlog groups by name, and I'd like to group by other things.\n\nHere's an example of what I just played around with:\n\n\tgit log --since=6.months --pretty=format:%cD --author=torvalds |\n\t\tcut -d, -f1 |\n\t\tsort |\n\t\tuniq -c |\n\t\tsort -n\n\ngives you the weekdays on which I've done most of my commits in the last \nsix months. And I think it's kind of interesting. I really do calm down a \nbit on weekends, and do only about half as many commits on Saturday and \nSunday as I do during the week.\n\nThe same is true across the board, btw. Except while _I_ tend to do most \nof my commits on Mondays, while on average, Linux kernel people seem to do \nmost of them on Fridays.\n\nBut what about time zones? Change the 'cut' to use \"-d' ' -f6\" instead, \nand it's clear that -0700 is the top time zone (US West coast), but +0100 \nand +0200 (much of Europe) are pretty active.\n\nHow about time? \"cut -d' ' -f5 | cut -d: -f1\": The least productive time \nhour is 05:xxAM (not a big surprise, perhaps), while the most productive \ntime is apparently early afternoon. But there I'm odd: most of my commits \nby far are in the morning (ie 8AM to noon).\n\nAnyway, I can do all this with sorting, but it's fun enough that I wonder \nif we should make it easier?\n\n\t\tLinus\n"},{"id":"118006","messageId":"7v8wiqfj60.fsf@alter.siamese.dyndns.org","threadId":"20115","inReplyTo":"alpine.LFD.2.01.0907141852400.13838@localhost.localdomain","subject":"Re: More 'shortlog' statistics models?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-07-15T08:24:23Z","receivedAt":"2009-07-15T08:24:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> So I was just thinking about one of the things I've wondered about for a \n> while: when do I (and others) make most of my commits?\n\nI can see that I am more active on Wednesdays and Saturdays for obvious\nreasons.  Thanks for an interesting diversion.\n\n> Anyway, I can do all this with sorting, but it's fun enough that I wonder \n> if we should make it easier?\n\nWasn't one of the GSoC project about git statistics?  Or was it a topic of\nlast year?\n"},{"id":"118010","messageId":"alpine.DEB.1.00.0907151316130.4410@intel-tinevez-2-302","threadId":"20115","inReplyTo":"7v8wiqfj60.fsf@alter.siamese.dyndns.org","subject":"[PATCH 1/2] shortlog: refactor insert_one_record()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-07-15T11:16:25Z","receivedAt":"2009-07-15T11:16:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis just splits insert_one_record() into one part which assumes that\nthe key is an email ident of the form \"A U Thor <author@example.com>\"\n(that needs to respect .mailmap) and a second part which does not.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin-shortlog.c |   81 ++++++++++++++++++++++++++++-----------------------\n 1 files changed, 44 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin-shortlog.c b/builtin-shortlog.c\nindex 6a3812e..a684422 100644\n--- a/builtin-shortlog.c\n+++ b/builtin-shortlog.c\n@@ -32,19 +32,57 @@ static int compare_by_number(const void *a1, const void *a2)\n const char *format_subject(struct strbuf *sb, const char *msg,\n \t\t\t   const char *line_separator);\n \n-static void insert_one_record(struct shortlog *log,\n-\t\t\t      const char *author,\n-\t\t\t      const char *oneline)\n+static void insert_one_record1(struct shortlog *log,\n+\t\tconst char *name, const char *oneline)\n {\n \tconst char *dot3 = log->common_repo_prefix;\n \tchar *buffer, *p;\n \tstruct string_list_item *item;\n+\tconst char *eol;\n+\tstruct strbuf subject = STRBUF_INIT;\n+\n+\titem = string_list_insert(name, &log->list);\n+\tif (item->util == NULL)\n+\t\titem->util = xcalloc(1, sizeof(struct string_list));\n+\n+\t/* Skip any leading whitespace, including any blank lines. */\n+\twhile (*oneline && isspace(*oneline))\n+\t\toneline++;\n+\teol = strchr(oneline, '\\n');\n+\tif (!eol)\n+\t\teol = oneline + strlen(oneline);\n+\tif (!prefixcmp(oneline, \"[PATCH\")) {\n+\t\tchar *eob = strchr(oneline, ']');\n+\t\tif (eob && (!eol || eob < eol))\n+\t\t\toneline = eob + 1;\n+\t}\n+\twhile (*oneline && isspace(*oneline) && *oneline != '\\n')\n+\t\toneline++;\n+\tformat_subject(&subject, oneline, \" \");\n+\tbuffer = strbuf_detach(&subject, NULL);\n+\n+\tif (dot3) {\n+\t\tint dot3len = strlen(dot3);\n+\t\tif (dot3len > 5) {\n+\t\t\twhile ((p = strstr(buffer, dot3)) != NULL) {\n+\t\t\t\tint taillen = strlen(p) - dot3len;\n+\t\t\t\tmemcpy(p, \"/.../\", 5);\n+\t\t\t\tmemmove(p + 5, p + dot3len, taillen + 1);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tstring_list_append(buffer, item->util);\n+}\n+\n+static void insert_one_record(struct shortlog *log,\n+\t\t\t      const char *author,\n+\t\t\t      const char *oneline)\n+{\n \tchar namebuf[1024];\n \tchar emailbuf[1024];\n \tsize_t len;\n-\tconst char *eol;\n \tconst char *boemail, *eoemail;\n-\tstruct strbuf subject = STRBUF_INIT;\n \n \tboemail = strchr(author, '<');\n \tif (!boemail)\n@@ -84,38 +122,7 @@ static void insert_one_record(struct shortlog *log,\n \t\tsnprintf(namebuf + len, room, \" <%.*s>\", maillen, emailbuf);\n \t}\n \n-\titem = string_list_insert(namebuf, &log->list);\n-\tif (item->util == NULL)\n-\t\titem->util = xcalloc(1, sizeof(struct string_list));\n-\n-\t/* Skip any leading whitespace, including any blank lines. */\n-\twhile (*oneline && isspace(*oneline))\n-\t\toneline++;\n-\teol = strchr(oneline, '\\n');\n-\tif (!eol)\n-\t\teol = oneline + strlen(oneline);\n-\tif (!prefixcmp(oneline, \"[PATCH\")) {\n-\t\tchar *eob = strchr(oneline, ']');\n-\t\tif (eob && (!eol || eob < eol))\n-\t\t\toneline = eob + 1;\n-\t}\n-\twhile (*oneline && isspace(*oneline) && *oneline != '\\n')\n-\t\toneline++;\n-\tformat_subject(&subject, oneline, \" \");\n-\tbuffer = strbuf_detach(&subject, NULL);\n-\n-\tif (dot3) {\n-\t\tint dot3len = strlen(dot3);\n-\t\tif (dot3len > 5) {\n-\t\t\twhile ((p = strstr(buffer, dot3)) != NULL) {\n-\t\t\t\tint taillen = strlen(p) - dot3len;\n-\t\t\t\tmemcpy(p, \"/.../\", 5);\n-\t\t\t\tmemmove(p + 5, p + dot3len, taillen + 1);\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tstring_list_append(buffer, item->util);\n+\tinsert_one_record1(log, namebuf, oneline);\n }\n \n static void read_from_stdin(struct shortlog *log)\n-- \n1.6.3.284.g6fecc\n"},{"id":"118011","messageId":"alpine.DEB.1.00.0907151316320.4410@intel-tinevez-2-302","threadId":"20115","inReplyTo":"7v8wiqfj60.fsf@alter.siamese.dyndns.org","subject":"[PATCH 2/2] shortlog: add '--sort-key' and '--sort-key-regexp' options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-07-15T11:17:25Z","receivedAt":"2009-07-15T11:17:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nInstead of always sorting by author, allow to sort by either\na whitespace-delimited field or by a regular expression (first group)\non the oneline.\n\nFor example, this will give you an overview of the weekday/commit\ndistribution:\n\n\tgit shortlog -k 1 --pretty=%cD -s -n\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tPretty obviously, in git.git this shows that Saturday and\n\tWednesday, your designated Git days, are on top of the list, but\n\twhat is interesting to me is that the difference between Wednesday \n\tand Sunday is not all that much.\n\n\tSorry, no time for tests, maybe somebody else can help out?\n\n Documentation/git-shortlog.txt |   13 +++++++-\n builtin-shortlog.c             |   64 +++++++++++++++++++++++++++++++++++++--\n shortlog.h                     |    1 +\n 3 files changed, 73 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt\nindex 42463a9..3155361 100644\n--- a/Documentation/git-shortlog.txt\n+++ b/Documentation/git-shortlog.txt\n@@ -9,7 +9,7 @@ SYNOPSIS\n --------\n [verse]\n git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]\n-git shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...]\n+git shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [(-K|--sort-key-regexp) <regexp>] [(-k|--sort-key) <n>] [<committish>...]\n \n DESCRIPTION\n -----------\n@@ -45,6 +45,17 @@ OPTIONS\n \tand subsequent lines are indented by `indent2` spaces. `width`,\n \t`indent1`, and `indent2` default to 76, 6 and 9 respectively.\n \n+-K <regexp>::\n+--sort-key-regexp <regexp>::\n+\tInstead of sorting by author, sort by a regular expression on the\n+\tcommit subject (or whatever you specified using --pretty)\n+\n+-k <number>::\n+--sort-key <number>::\n+\tInstead of sorting by author, sort by a given whitespace-delimited\n+\tfield of the commit subject (or whatever you specified using\n+\t--pretty).  The first field is 1.\n+\n \n MAPPING AUTHORS\n ---------------\ndiff --git a/builtin-shortlog.c b/builtin-shortlog.c\nindex a684422..2cab5e4 100644\n--- a/builtin-shortlog.c\n+++ b/builtin-shortlog.c\n@@ -145,9 +145,37 @@ static void read_from_stdin(struct shortlog *log)\n \n void shortlog_add_commit(struct shortlog *log, struct commit *commit)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tchar *key = NULL;\n \tconst char *author = NULL, *buffer;\n \n \tbuffer = commit->buffer;\n+\tif (log->user_format)\n+\t\tpretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf,\n+\t\t\tDEFAULT_ABBREV, \"\", \"\", DATE_NORMAL, 0);\n+\n+\tif (log->sort_key) {\n+\t\tconst char *p = buf.buf;\n+\t\tregmatch_t match[2];\n+\n+\t\tif (!log->user_format) {\n+\t\t\tp = strstr(buffer, \"\\n\\n\");\n+\t\t\tif (!p)\n+\t\t\t\treturn;\n+\t\t\tp += 2;\n+\t\t}\n+\n+\t\tif (!regexec(log->sort_key, p, 2, match, 0) &&\n+\t\t\t\tmatch[1].rm_so >= 0)\n+\t\t\tauthor = key = xstrndup(p + match[1].rm_so,\n+\t\t\t\tmatch[1].rm_eo - match[1].rm_so);\n+\t\telse\n+\t\t\tauthor = \"<null>\";\n+\t\tinsert_one_record1(log, key, p);\n+\t\tstrbuf_release(&buf);\n+\t\treturn;\n+\t}\n+\n \twhile (*buffer && *buffer != '\\n') {\n \t\tconst char *eol = strchr(buffer, '\\n');\n \n@@ -164,10 +192,6 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)\n \t\tdie(\"Missing author: %s\",\n \t\t    sha1_to_hex(commit->object.sha1));\n \tif (log->user_format) {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\n-\t\tpretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf,\n-\t\t\tDEFAULT_ABBREV, \"\", \"\", DATE_NORMAL, 0);\n \t\tinsert_one_record(log, author, buf.buf);\n \t\tstrbuf_release(&buf);\n \t\treturn;\n@@ -175,6 +199,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)\n \tif (*buffer)\n \t\tbuffer++;\n \tinsert_one_record(log, author, !*buffer ? \"<none>\" : buffer);\n+\tfree(key);\n }\n \n static void get_from_rev(struct rev_info *rev, struct shortlog *log)\n@@ -250,6 +275,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)\n {\n \tstatic struct shortlog log;\n \tstatic struct rev_info rev;\n+\tstatic const char *sort_key_regexp = NULL;\n+\tstatic int sort_key_field = 0;\n \tint nongit;\n \n \tstatic const struct option options[] = {\n@@ -261,6 +288,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)\n \t\t\t    \"Show the email address of each author\"),\n \t\t{ OPTION_CALLBACK, 'w', NULL, &log, \"w[,i1[,i2]]\",\n \t\t\t\"Linewrap output\", PARSE_OPT_OPTARG, &parse_wrap_args },\n+\t\tOPT_STRING('K', \"sort-key-regexp\", &sort_key_regexp, \"<regexp>\",\n+\t\t\t\"Sort shortlog by the given regular expression\"),\n+\t\tOPT_INTEGER('k', \"sort-key\", &sort_key_field,\n+\t\t\t\"Sort shortlog by the given field \"\n+\t\t\t\"(whitespace-delimited)\"),\n \t\tOPT_END(),\n \t};\n \n@@ -285,6 +317,27 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)\n parse_done:\n \targc = parse_options_end(&ctx);\n \n+\tif (sort_key_regexp && sort_key_field > 0)\n+\t\tdie (\"--sort-key-regexp and --sort-key-field are incompatible\");\n+\n+\tif (sort_key_regexp) {\n+\t\tlog.sort_key = xmalloc(sizeof(*log.sort_key));\n+\t\tif (regcomp(log.sort_key, sort_key_regexp, 0))\n+\t\t\tdie (\"Invalid regular expression: '%s'\",\n+\t\t\t\t\tsort_key_regexp);\n+\t}\n+\tif (sort_key_field > 0) {\n+\t\tstruct strbuf regexp = STRBUF_INIT;\n+\t\tstrbuf_addstr(&regexp, \"^[ \\t\\n]*\");\n+\t\twhile (--sort_key_field)\n+\t\t\tstrbuf_addstr(&regexp, \"[^ \\t\\n]*[ \\t\\n]*\");\n+\t\tstrbuf_addstr(&regexp, \"\\\\([^ \\t\\n]*\\\\)[ \\t\\n]*.*$\");\n+\t\tlog.sort_key = xmalloc(sizeof(*log.sort_key));\n+\t\tif (regcomp(log.sort_key, regexp.buf, 0))\n+\t\t\tdie (\"Invalid regular expression: '%s'\", regexp.buf);\n+\t\tstrbuf_release(&regexp);\n+\t}\n+\n \tif (setup_revisions(argc, argv, &rev, NULL) != 1) {\n \t\terror(\"unrecognized argument: %s\", argv[1]);\n \t\tusage_with_options(shortlog_usage, options);\n@@ -296,6 +349,9 @@ parse_done:\n \tif (!nongit && !rev.pending.nr && isatty(0))\n \t\tadd_head_to_pending(&rev);\n \tif (rev.pending.nr == 0) {\n+\t\tif (log.sort_key)\n+\t\t\tdie (\"Specifying a sort key is incompatible with \"\n+\t\t\t\t\"reading from stdin.\");\n \t\tread_from_stdin(&log);\n \t}\n \telse\ndiff --git a/shortlog.h b/shortlog.h\nindex bc02cc2..9dedaf6 100644\n--- a/shortlog.h\n+++ b/shortlog.h\n@@ -16,6 +16,7 @@ struct shortlog {\n \tchar *common_repo_prefix;\n \tint email;\n \tstruct string_list mailmap;\n+\tregex_t *sort_key;\n };\n \n void shortlog_init(struct shortlog *log);\n-- \n1.6.3.284.g6fecc\n"},{"id":"118020","messageId":"m363duukvb.fsf@localhost.localdomain","threadId":"20115","inReplyTo":"7v8wiqfj60.fsf@alter.siamese.dyndns.org","subject":"Re: More 'shortlog' statistics models?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-07-15T13:38:35Z","receivedAt":"2009-07-15T13:38:35Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Linus Torvalds <torvalds@linux-foundation.org> writes:\n> \n> > Anyway, I can do all this with sorting, but it's fun enough that I wonder \n> > if we should make it easier?\n> \n> Wasn't one of the GSoC project about git statistics?  Or was it a topic of\n> last year?\n\nIt was topic of last year GSoC, see http://git.or.cz/gitwiki/SoC2008Projects\nIt was decided[1] that it would be better for it to remain separate\nfrom git (for support for other SCMs).\n\n  http://repo.or.cz/w/git-stats.git\n\nCC-ed Sverre Rabellier (student for this git-statistic project)\n\n[1]: http://permalink.gmane.org/gmane.comp.version-control.git/90691\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"118031","messageId":"alpine.LFD.2.01.0907150807401.13838@localhost.localdomain","threadId":"20115","inReplyTo":"alpine.DEB.1.00.0907151316320.4410@intel-tinevez-2-302","subject":"Re: [PATCH 2/2] shortlog: add '--sort-key' and '--sort-key-regexp' options","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2009-07-15T15:11:57Z","receivedAt":"2009-07-15T15:11:57Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 15 Jul 2009, Johannes Schindelin wrote:\n> \n> Instead of always sorting by author, allow to sort by either\n> a whitespace-delimited field or by a regular expression (first group)\n> on the oneline.\n\nOk, I got a SIGSEGV on the regexp, because I didn't react to the \"first \ngroup\" part. So I did\n\n\tgit shortlog --pretty=%cD --sort-key-regex ' [0-9]*:' -ns\n\nand it immediately segfaulted for me.\n\nI realize that I _should_ have done\n\n\tgit shortlog --pretty=%cD --sort-key-regex ' \\([0-9]*\\):' -ns\n\nand then I get the expected hourly statistics, but it shouldn't have \nSIGSEGV'd either.\n\nBut cool small patch-series. This was exactly what I was looking for.\n\n\t\tLinus\n"},{"id":"118034","messageId":"20090715173714.1f5240c4@gmail.com","threadId":"20115","inReplyTo":"alpine.DEB.1.00.0907151316320.4410@intel-tinevez-2-302","subject":"Re: [PATCH 2/2] shortlog: add '--sort-key' and '--sort-key-regexp' options","fromName":"Michał Kiedrowicz","fromEmail":"michal.kiedrowicz@gmail.com","sentAt":"2009-07-15T15:37:14Z","receivedAt":"2009-07-15T15:37:14Z","isPatch":true,"sender":{"key":"michal.kiedrowicz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/14072847?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n\n> \n> Instead of always sorting by author, allow to sort by either\n> a whitespace-delimited field or by a regular expression (first group)\n> on the oneline.\n> \n> For example, this will give you an overview of the weekday/commit\n> distribution:\n> \n> \tgit shortlog -k 1 --pretty=%cD -s -n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n> \n> \tPretty obviously, in git.git this shows that Saturday and\n> \tWednesday, your designated Git days, are on top of the list,\n> but what is interesting to me is that the difference between\n> Wednesday and Sunday is not all that much.\n> \n> \tSorry, no time for tests, maybe somebody else can help out?\n> \n>  Documentation/git-shortlog.txt |   13 +++++++-\n>  builtin-shortlog.c             |   64\n> +++++++++++++++++++++++++++++++++++++--\n> shortlog.h                     |    1 + 3 files changed, 73\n> insertions(+), 5 deletions(-)\n> \n> diff --git a/Documentation/git-shortlog.txt\n> b/Documentation/git-shortlog.txt index 42463a9..3155361 100644\n> --- a/Documentation/git-shortlog.txt\n> +++ b/Documentation/git-shortlog.txt\n> @@ -9,7 +9,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]\n> -git shortlog [-n|--numbered] [-s|--summary] [-e|--email]\n> [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...] +git shortlog\n> [-n|--numbered] [-s|--summary] [-e|--email]\n> [-w[<width>[,<indent1>[,<indent2>]]]] [(-K|--sort-key-regexp)\n> <regexp>] [(-k|--sort-key) <n>] [<committish>...] DESCRIPTION\n> ----------- @@ -45,6 +45,17 @@ OPTIONS\n>  \tand subsequent lines are indented by `indent2` spaces.\n> `width`, `indent1`, and `indent2` default to 76, 6 and 9 respectively.\n>  \n> +-K <regexp>::\n> +--sort-key-regexp <regexp>::\n> +\tInstead of sorting by author, sort by a regular expression\n> on the\n> +\tcommit subject (or whatever you specified using --pretty)\n> +\n> +-k <number>::\n> +--sort-key <number>::\n> +\tInstead of sorting by author, sort by a given\n> whitespace-delimited\n> +\tfield of the commit subject (or whatever you specified using\n> +\t--pretty).  The first field is 1.\n> +\n>  \n>  MAPPING AUTHORS\n>  ---------------\n> diff --git a/builtin-shortlog.c b/builtin-shortlog.c\n> index a684422..2cab5e4 100644\n> --- a/builtin-shortlog.c\n> +++ b/builtin-shortlog.c\n> @@ -145,9 +145,37 @@ static void read_from_stdin(struct shortlog *log)\n>  \n>  void shortlog_add_commit(struct shortlog *log, struct commit *commit)\n>  {\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tchar *key = NULL;\n>  \tconst char *author = NULL, *buffer;\n>  \n>  \tbuffer = commit->buffer;\n> +\tif (log->user_format)\n> +\t\tpretty_print_commit(CMIT_FMT_USERFORMAT, commit,\n> &buf,\n> +\t\t\tDEFAULT_ABBREV, \"\", \"\", DATE_NORMAL, 0);\n> +\n> +\tif (log->sort_key) {\n> +\t\tconst char *p = buf.buf;\n> +\t\tregmatch_t match[2];\n> +\n> +\t\tif (!log->user_format) {\n> +\t\t\tp = strstr(buffer, \"\\n\\n\");\n> +\t\t\tif (!p)\n> +\t\t\t\treturn;\n> +\t\t\tp += 2;\n> +\t\t}\n> +\n> +\t\tif (!regexec(log->sort_key, p, 2, match, 0) &&\n> +\t\t\t\tmatch[1].rm_so >= 0)\n> +\t\t\tauthor = key = xstrndup(p + match[1].rm_so,\n> +\t\t\t\tmatch[1].rm_eo - match[1].rm_so);\n> +\t\telse\n> +\t\t\tauthor = \"<null>\";\n> +\t\tinsert_one_record1(log, key, p);\n> +\t\tstrbuf_release(&buf);\n\nMissing free()?\n\n> +\t\treturn;\n> +\t}\n> +\n>  \twhile (*buffer && *buffer != '\\n') {\n>  \t\tconst char *eol = strchr(buffer, '\\n');\n>  \n> @@ -164,10 +192,6 @@ void shortlog_add_commit(struct shortlog *log,\n> struct commit *commit) die(\"Missing author: %s\",\n>  \t\t    sha1_to_hex(commit->object.sha1));\n>  \tif (log->user_format) {\n> -\t\tstruct strbuf buf = STRBUF_INIT;\n> -\n> -\t\tpretty_print_commit(CMIT_FMT_USERFORMAT, commit,\n> &buf,\n> -\t\t\tDEFAULT_ABBREV, \"\", \"\", DATE_NORMAL, 0);\n>  \t\tinsert_one_record(log, author, buf.buf);\n>  \t\tstrbuf_release(&buf);\n>  \t\treturn;\n> @@ -175,6 +199,7 @@ void shortlog_add_commit(struct shortlog *log,\n> struct commit *commit) if (*buffer)\n>  \t\tbuffer++;\n>  \tinsert_one_record(log, author, !*buffer ? \"<none>\" : buffer);\n> +\tfree(key);\n\nIs it the right place for free()?\n\nHere is valgrind output:\n\n==9005== 98,085 bytes in 19,218 blocks are definitely lost in loss record 23 of 25\n==9005==    at 0x4A08CFE: malloc (vg_replace_malloc.c:207\n==9005==    by 0x4A8D25: xmalloc (wrapper.c:20)\n==9005==    by 0x4A8DE1: xmemdupz (wrapper.c:45)\n==9005==    by 0x44AFDD: shortlog_add_commit (builtin-shortlog.c:170)\n==9005==    by 0x44B31C: cmd_shortlog (builtin-shortlog.c:212)\n==9005==    by 0x4049A2: handle_internal_command (git.c:246)\n==9005==    by 0x404B63: main (git.c:438)\n"},{"id":"118040","messageId":"fabb9a1e0907151056q61f73957yd7dda7a199914af7@mail.gmail.com","threadId":"20115","inReplyTo":"m363duukvb.fsf@localhost.localdomain","subject":"Re: More 'shortlog' statistics models?","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-07-15T17:56:13Z","receivedAt":"2009-07-15T17:56:13Z","isPatch":false,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\n[message not culled as I suspect Jakub's reply didn't make the git list]\n\nOn Wed, Jul 15, 2009 at 06:38, Jakub Narebski<jnareb@gmail.com> wrote:\n>> Wasn't one of the GSoC project about git statistics?  Or was it a topic of\n>> last year?\n\nThat would be me indeed, as Jakub said :).\n\n> It was topic of last year GSoC, see http://git.or.cz/gitwiki/SoC2008Projects\n> It was decided[1] that it would be better for it to remain separate\n> from git (for support for other SCMs).\n>\n>  http://repo.or.cz/w/git-stats.git\n>\n> CC-ed Sverre Rabellier (student for this git-statistic project)\n>\n> [1]: http://permalink.gmane.org/gmane.comp.version-control.git/90691\n> --\n> Jakub Narebski\n> Poland\n> ShadeHawk on #git\n\nNot sure what happened but you addressed me (and my old address at\nthat) and the git list in one line, not seperated by a comma. Thanks\nfor the plug regardless :).\n\n-- \nCheers,\n\nSverre Rabbelier\n"}]}