Skip to content

Commit

Permalink
shortlog: introduce --email-only to only show emails
Browse files Browse the repository at this point in the history
When a shortlog caller wants to group output by, say, author email, they
can easily express this with:

    $ git shortlog --group=format:%ae

and restrict output to specific email(s) with the new `--group-filter`
option introduced by the previous commit.

But they are not able to apply the same treatment to identities that
appear in trailers. Doing:

    $ git shortlog -e --group=format:%ae --group=trailer:Co-authored-by

will produce funky results, interspersing proper emails with full "Name
<email>" identities from the Co-authored-by trailer (or anything else
that might appear there), like:

    461  [email protected]
     11  Taylor Blau <[email protected]>

So if the caller wants to restrict output to a set of matching email
addresses (say, "[email protected]"), they cannot do it with a
`--group-filter`, since it would discard the group "Taylor Blau
<[email protected]>".

Introduce a new `--email-only` option, which extracts the email
component of an identity from all shortlog groups, including trailers.
It behaves similarly to the `-e` option, but replaces its output with
just the email component, instead of adding it on to the end.

Now, `shortlog` callers can perform:

    $ git shortlog -s --group=author --group=trailer:Co-authored-by \
        --email-only --group-filter="<[email protected]>"
       472  <[email protected]>

to obtain the output they want.

Signed-off-by: Taylor Blau <[email protected]>
  • Loading branch information
ttaylorr committed Jun 7, 2023
1 parent 5cec04b commit 44179d2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 9 deletions.
5 changes: 5 additions & 0 deletions Documentation/git-shortlog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ OPTIONS
--email::
Show the email address of each author.

--email-only::
Show only the email address of each author, or committer. If
using a different kind of group (e.g. trailers, custom format,
etc.), only values which contain name/email-pairs will be shown.

--format[=<format>]::
Instead of the commit subject, use some other information to
describe each commit. '<format>' can be any string accepted
Expand Down
33 changes: 24 additions & 9 deletions builtin/shortlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,13 @@ static int parse_ident(struct shortlog *log,
maillen = ident.mail_end - ident.mail_begin;

map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
strbuf_add(out, namebuf, namelen);
if (log->email)
strbuf_addf(out, " <%.*s>", (int)maillen, mailbuf);
if (log->email_only) {
strbuf_addf(out, "<%.*s>", (int)maillen, mailbuf);
} else {
strbuf_add(out, namebuf, namelen);
if (log->email)
strbuf_addf(out, " <%.*s>", (int)maillen, mailbuf);
}

return 0;
}
Expand Down Expand Up @@ -198,6 +202,8 @@ static void insert_records_from_trailers(struct shortlog *log,
strbuf_reset(&ident);
if (!parse_ident(log, &ident, value))
value = ident.buf;
else if (log->email_only)
continue;

if (!strset_add(dups, value))
continue;
Expand Down Expand Up @@ -370,12 +376,19 @@ void shortlog_init(struct shortlog *log)

void shortlog_finish_setup(struct shortlog *log)
{
if (log->groups & SHORTLOG_GROUP_AUTHOR)
string_list_append(&log->format,
log->email ? "%aN <%aE>" : "%aN");
if (log->groups & SHORTLOG_GROUP_COMMITTER)
string_list_append(&log->format,
log->email ? "%cN <%cE>" : "%cN");
if (log->email_only) {
if (log->groups & SHORTLOG_GROUP_AUTHOR)
string_list_append(&log->format, "<%aE>");
if (log->groups & SHORTLOG_GROUP_COMMITTER)
string_list_append(&log->format, "<%cE>");
} else {
if (log->groups & SHORTLOG_GROUP_AUTHOR)
string_list_append(&log->format,
log->email ? "%aN <%aE>" : "%aN");
if (log->groups & SHORTLOG_GROUP_COMMITTER)
string_list_append(&log->format,
log->email ? "%cN <%cE>" : "%cN");
}

string_list_sort(&log->trailers);
string_list_sort(&log->group_filter);
Expand All @@ -397,6 +410,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
N_("suppress commit descriptions, only provides commit count")),
OPT_BOOL('e', "email", &log.email,
N_("show the email address of each author")),
OPT_BOOL(0, "email-only", &log.email_only,
N_("only show the email address of each author")),
OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
N_("linewrap output"), PARSE_OPT_OPTARG,
&parse_wrap_args),
Expand Down
1 change: 1 addition & 0 deletions shortlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct shortlog {
struct string_list format;

int email;
int email_only;
struct string_list mailmap;
FILE *file;
};
Expand Down
28 changes: 28 additions & 0 deletions t/t4201-shortlog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,34 @@ test_expect_success '--no-group-filter reset group filters' '
test_cmp expect actual
'

test_expect_success '--email-only shows emails from author' '
cat >expect <<-\EOF &&
2 <[email protected]>
EOF
git shortlog -ns --group=author --email-only -2 HEAD >actual &&
test_cmp expect actual
'

test_expect_success '--email-only shows emails from committer' '
cat >expect <<-\EOF &&
2 <[email protected]>
EOF
git shortlog -ns --group=committer --email-only -2 HEAD >actual &&
test_cmp expect actual
'

test_expect_success '--email-only shows emails from trailers with idents' '
cat >expect <<-\EOF &&
1 <[email protected]>
1 <[email protected]>
EOF
# at this point, HEAD~3 has a trailer "Repeated-trailer: Foo",
# which is not shown here since it cannot be parsed as an ident
git shortlog -ns --group=trailer:some-trailer --email-only -3 \
HEAD >actual &&
test_cmp expect actual
'

test_expect_success 'shortlog can match multiple format groups' '
GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" \
git commit --allow-empty -m "identical names" &&
Expand Down

0 comments on commit 44179d2

Please sign in to comment.