From 2db6b83d189bb82d1d45805fa6c85a9c8b507920 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jan 2016 15:02:48 -0500 Subject: [PATCH] shortlog: replace hand-parsing of author with pretty-printer When gathering the author and oneline subject for each commit, we hand-parse the commit headers to find the "author" line, and then continue past to the blank line at the end of the header. We can replace this tricky hand-parsing by simply asking the pretty-printer for the relevant items. This also decouples the author and oneline parsing, opening up some new optimizations in further commits. One reason to avoid the pretty-printer is that it might be less efficient than hand-parsing. However, I measured no slowdown at all running "git shortlog -ns HEAD" on linux.git. As a bonus, we also fix a memory leak in the (uncommon) case that the author field is blank. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/shortlog.c | 58 +++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 6c0a72edef..1261ec4dd0 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -113,45 +113,35 @@ static void read_from_stdin(struct shortlog *log) void shortlog_add_commit(struct shortlog *log, struct commit *commit) { - const char *author = NULL, *buffer; - struct strbuf buf = STRBUF_INIT; - struct strbuf ufbuf = STRBUF_INIT; + struct strbuf author = STRBUF_INIT; + struct strbuf oneline = STRBUF_INIT; + struct pretty_print_context ctx = {0}; - pp_commit_easy(CMIT_FMT_RAW, commit, &buf); - buffer = buf.buf; - while (*buffer && *buffer != '\n') { - const char *eol = strchr(buffer, '\n'); + ctx.fmt = CMIT_FMT_USERFORMAT; + ctx.abbrev = log->abbrev; + ctx.subject = ""; + ctx.after_subject = ""; + ctx.date_mode.type = DATE_NORMAL; + ctx.output_encoding = get_log_output_encoding(); - if (eol == NULL) - eol = buffer + strlen(buffer); - else - eol++; - - if (starts_with(buffer, "author ")) - author = buffer + 7; - buffer = eol; - } - if (!author) { + format_commit_message(commit, "%an <%ae>", &author, &ctx); + /* we can detect a total failure only by seeing " <>" in the output */ + if (author.len <= 3) { warning(_("Missing author: %s"), oid_to_hex(&commit->object.oid)); - return; + goto out; } - if (log->user_format) { - struct pretty_print_context ctx = {0}; - ctx.fmt = CMIT_FMT_USERFORMAT; - ctx.abbrev = log->abbrev; - ctx.subject = ""; - ctx.after_subject = ""; - ctx.date_mode.type = DATE_NORMAL; - ctx.output_encoding = get_log_output_encoding(); - pretty_print_commit(&ctx, commit, &ufbuf); - buffer = ufbuf.buf; - } else if (*buffer) { - buffer++; - } - insert_one_record(log, author, !*buffer ? "" : buffer); - strbuf_release(&ufbuf); - strbuf_release(&buf); + + if (log->user_format) + pretty_print_commit(&ctx, commit, &oneline); + else + format_commit_message(commit, "%s", &oneline, &ctx); + + insert_one_record(log, author.buf, oneline.len ? oneline.buf : ""); + +out: + strbuf_release(&author); + strbuf_release(&oneline); } static void get_from_rev(struct rev_info *rev, struct shortlog *log)