Skip to content

Commit 577f63e

Browse files
committed
Merge branch 'ap/log-mailmap'
Teach commands in the "log" family to optionally pay attention to the mailmap. * ap/log-mailmap: log --use-mailmap: optimize for cases without --author/--committer search log: add log.mailmap configuration option log: grep author/committer using mailmap test: add test for --use-mailmap option log: add --use-mailmap option pretty: use mailmap to display username and email mailmap: add mailmap structure to rev_info and pp mailmap: simplify map_user() interface mailmap: remove email copy and length limitation Use split_ident_line to parse author and committer string-list: allow case-insensitive string list
2 parents 02f55e6 + df874fa commit 577f63e

File tree

15 files changed

+393
-229
lines changed

15 files changed

+393
-229
lines changed

Documentation/config.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,10 @@ log.showroot::
15251525
Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
15261526
normally hide the root commit will now show it. True by default.
15271527

1528+
log.mailmap::
1529+
If true, makes linkgit:git-log[1], linkgit:git-show[1], and
1530+
linkgit:git-whatchanged[1] assume `--use-mailmap`.
1531+
15281532
mailmap.file::
15291533
The location of an augmenting mailmap file. The default
15301534
mailmap, located in the root of the repository, is loaded

Documentation/git-log.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ OPTIONS
4747
Print out the ref name given on the command line by which each
4848
commit was reached.
4949

50+
--use-mailmap::
51+
Use mailmap file to map author and committer names and email
52+
to canonical real names and email addresses. See
53+
linkgit:git-shortlog[1].
54+
5055
--full-diff::
5156
Without this flag, "git log -p <path>..." shows commits that
5257
touch the specified paths, and diffs about the same specified

builtin/blame.c

Lines changed: 86 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,30 +1322,31 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
13221322
* Information on commits, used for output.
13231323
*/
13241324
struct commit_info {
1325-
const char *author;
1326-
const char *author_mail;
1325+
struct strbuf author;
1326+
struct strbuf author_mail;
13271327
unsigned long author_time;
1328-
const char *author_tz;
1328+
struct strbuf author_tz;
13291329

13301330
/* filled only when asked for details */
1331-
const char *committer;
1332-
const char *committer_mail;
1331+
struct strbuf committer;
1332+
struct strbuf committer_mail;
13331333
unsigned long committer_time;
1334-
const char *committer_tz;
1334+
struct strbuf committer_tz;
13351335

1336-
const char *summary;
1336+
struct strbuf summary;
13371337
};
13381338

13391339
/*
13401340
* Parse author/committer line in the commit object buffer
13411341
*/
13421342
static void get_ac_line(const char *inbuf, const char *what,
1343-
int person_len, char *person,
1344-
int mail_len, char *mail,
1345-
unsigned long *time, const char **tz)
1343+
struct strbuf *name, struct strbuf *mail,
1344+
unsigned long *time, struct strbuf *tz)
13461345
{
1347-
int len, tzlen, maillen;
1348-
char *tmp, *endp, *timepos, *mailpos;
1346+
struct ident_split ident;
1347+
size_t len, maillen, namelen;
1348+
char *tmp, *endp;
1349+
const char *namebuf, *mailbuf;
13491350

13501351
tmp = strstr(inbuf, what);
13511352
if (!tmp)
@@ -1356,69 +1357,61 @@ static void get_ac_line(const char *inbuf, const char *what,
13561357
len = strlen(tmp);
13571358
else
13581359
len = endp - tmp;
1359-
if (person_len <= len) {
1360+
1361+
if (split_ident_line(&ident, tmp, len)) {
13601362
error_out:
13611363
/* Ugh */
1362-
*tz = "(unknown)";
1363-
strcpy(person, *tz);
1364-
strcpy(mail, *tz);
1364+
tmp = "(unknown)";
1365+
strbuf_addstr(name, tmp);
1366+
strbuf_addstr(mail, tmp);
1367+
strbuf_addstr(tz, tmp);
13651368
*time = 0;
13661369
return;
13671370
}
1368-
memcpy(person, tmp, len);
13691371

1370-
tmp = person;
1371-
tmp += len;
1372-
*tmp = 0;
1373-
while (person < tmp && *tmp != ' ')
1374-
tmp--;
1375-
if (tmp <= person)
1376-
goto error_out;
1377-
*tz = tmp+1;
1378-
tzlen = (person+len)-(tmp+1);
1372+
namelen = ident.name_end - ident.name_begin;
1373+
namebuf = ident.name_begin;
13791374

1380-
*tmp = 0;
1381-
while (person < tmp && *tmp != ' ')
1382-
tmp--;
1383-
if (tmp <= person)
1384-
goto error_out;
1385-
*time = strtoul(tmp, NULL, 10);
1386-
timepos = tmp;
1375+
maillen = ident.mail_end - ident.mail_begin;
1376+
mailbuf = ident.mail_begin;
13871377

1388-
*tmp = 0;
1389-
while (person < tmp && !(*tmp == ' ' && tmp[1] == '<'))
1390-
tmp--;
1391-
if (tmp <= person)
1392-
return;
1393-
mailpos = tmp + 1;
1394-
*tmp = 0;
1395-
maillen = timepos - tmp;
1396-
memcpy(mail, mailpos, maillen);
1378+
*time = strtoul(ident.date_begin, NULL, 10);
13971379

1398-
if (!mailmap.nr)
1399-
return;
1400-
1401-
/*
1402-
* mailmap expansion may make the name longer.
1403-
* make room by pushing stuff down.
1404-
*/
1405-
tmp = person + person_len - (tzlen + 1);
1406-
memmove(tmp, *tz, tzlen);
1407-
tmp[tzlen] = 0;
1408-
*tz = tmp;
1380+
len = ident.tz_end - ident.tz_begin;
1381+
strbuf_add(tz, ident.tz_begin, len);
14091382

14101383
/*
14111384
* Now, convert both name and e-mail using mailmap
14121385
*/
1413-
if (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) {
1414-
/* Add a trailing '>' to email, since map_user returns plain emails
1415-
Note: It already has '<', since we replace from mail+1 */
1416-
mailpos = memchr(mail, '\0', mail_len);
1417-
if (mailpos && mailpos-mail < mail_len - 1) {
1418-
*mailpos = '>';
1419-
*(mailpos+1) = '\0';
1420-
}
1421-
}
1386+
map_user(&mailmap, &mailbuf, &maillen,
1387+
&namebuf, &namelen);
1388+
1389+
strbuf_addf(mail, "<%.*s>", (int)maillen, mailbuf);
1390+
strbuf_add(name, namebuf, namelen);
1391+
}
1392+
1393+
static void commit_info_init(struct commit_info *ci)
1394+
{
1395+
1396+
strbuf_init(&ci->author, 0);
1397+
strbuf_init(&ci->author_mail, 0);
1398+
strbuf_init(&ci->author_tz, 0);
1399+
strbuf_init(&ci->committer, 0);
1400+
strbuf_init(&ci->committer_mail, 0);
1401+
strbuf_init(&ci->committer_tz, 0);
1402+
strbuf_init(&ci->summary, 0);
1403+
}
1404+
1405+
static void commit_info_destroy(struct commit_info *ci)
1406+
{
1407+
1408+
strbuf_release(&ci->author);
1409+
strbuf_release(&ci->author_mail);
1410+
strbuf_release(&ci->author_tz);
1411+
strbuf_release(&ci->committer);
1412+
strbuf_release(&ci->committer_mail);
1413+
strbuf_release(&ci->committer_tz);
1414+
strbuf_release(&ci->summary);
14221415
}
14231416

14241417
static void get_commit_info(struct commit *commit,
@@ -1428,11 +1421,8 @@ static void get_commit_info(struct commit *commit,
14281421
int len;
14291422
const char *subject, *encoding;
14301423
char *reencoded, *message;
1431-
static char author_name[1024];
1432-
static char author_mail[1024];
1433-
static char committer_name[1024];
1434-
static char committer_mail[1024];
1435-
static char summary_buf[1024];
1424+
1425+
commit_info_init(ret);
14361426

14371427
/*
14381428
* We've operated without save_commit_buffer, so
@@ -1450,33 +1440,25 @@ static void get_commit_info(struct commit *commit,
14501440
encoding = get_log_output_encoding();
14511441
reencoded = logmsg_reencode(commit, encoding);
14521442
message = reencoded ? reencoded : commit->buffer;
1453-
ret->author = author_name;
1454-
ret->author_mail = author_mail;
14551443
get_ac_line(message, "\nauthor ",
1456-
sizeof(author_name), author_name,
1457-
sizeof(author_mail), author_mail,
1444+
&ret->author, &ret->author_mail,
14581445
&ret->author_time, &ret->author_tz);
14591446

14601447
if (!detailed) {
14611448
free(reencoded);
14621449
return;
14631450
}
14641451

1465-
ret->committer = committer_name;
1466-
ret->committer_mail = committer_mail;
14671452
get_ac_line(message, "\ncommitter ",
1468-
sizeof(committer_name), committer_name,
1469-
sizeof(committer_mail), committer_mail,
1453+
&ret->committer, &ret->committer_mail,
14701454
&ret->committer_time, &ret->committer_tz);
14711455

1472-
ret->summary = summary_buf;
14731456
len = find_commit_subject(message, &subject);
1474-
if (len && len < sizeof(summary_buf)) {
1475-
memcpy(summary_buf, subject, len);
1476-
summary_buf[len] = 0;
1477-
} else {
1478-
sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
1479-
}
1457+
if (len)
1458+
strbuf_add(&ret->summary, subject, len);
1459+
else
1460+
strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
1461+
14801462
free(reencoded);
14811463
}
14821464

@@ -1505,22 +1487,25 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
15051487

15061488
suspect->commit->object.flags |= METAINFO_SHOWN;
15071489
get_commit_info(suspect->commit, &ci, 1);
1508-
printf("author %s\n", ci.author);
1509-
printf("author-mail %s\n", ci.author_mail);
1490+
printf("author %s\n", ci.author.buf);
1491+
printf("author-mail %s\n", ci.author_mail.buf);
15101492
printf("author-time %lu\n", ci.author_time);
1511-
printf("author-tz %s\n", ci.author_tz);
1512-
printf("committer %s\n", ci.committer);
1513-
printf("committer-mail %s\n", ci.committer_mail);
1493+
printf("author-tz %s\n", ci.author_tz.buf);
1494+
printf("committer %s\n", ci.committer.buf);
1495+
printf("committer-mail %s\n", ci.committer_mail.buf);
15141496
printf("committer-time %lu\n", ci.committer_time);
1515-
printf("committer-tz %s\n", ci.committer_tz);
1516-
printf("summary %s\n", ci.summary);
1497+
printf("committer-tz %s\n", ci.committer_tz.buf);
1498+
printf("summary %s\n", ci.summary.buf);
15171499
if (suspect->commit->object.flags & UNINTERESTING)
15181500
printf("boundary\n");
15191501
if (suspect->previous) {
15201502
struct origin *prev = suspect->previous;
15211503
printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
15221504
write_name_quoted(prev->path, stdout, '\n');
15231505
}
1506+
1507+
commit_info_destroy(&ci);
1508+
15241509
return 1;
15251510
}
15261511

@@ -1707,11 +1692,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
17071692
if (opt & OUTPUT_ANNOTATE_COMPAT) {
17081693
const char *name;
17091694
if (opt & OUTPUT_SHOW_EMAIL)
1710-
name = ci.author_mail;
1695+
name = ci.author_mail.buf;
17111696
else
1712-
name = ci.author;
1697+
name = ci.author.buf;
17131698
printf("\t(%10s\t%10s\t%d)", name,
1714-
format_time(ci.author_time, ci.author_tz,
1699+
format_time(ci.author_time, ci.author_tz.buf,
17151700
show_raw_time),
17161701
ent->lno + 1 + cnt);
17171702
} else {
@@ -1730,14 +1715,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
17301715
const char *name;
17311716
int pad;
17321717
if (opt & OUTPUT_SHOW_EMAIL)
1733-
name = ci.author_mail;
1718+
name = ci.author_mail.buf;
17341719
else
1735-
name = ci.author;
1720+
name = ci.author.buf;
17361721
pad = longest_author - utf8_strwidth(name);
17371722
printf(" (%s%*s %10s",
17381723
name, pad, "",
17391724
format_time(ci.author_time,
1740-
ci.author_tz,
1725+
ci.author_tz.buf,
17411726
show_raw_time));
17421727
}
17431728
printf(" %*d) ",
@@ -1752,6 +1737,8 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
17521737

17531738
if (sb->final_buf_size && cp[-1] != '\n')
17541739
putchar('\n');
1740+
1741+
commit_info_destroy(&ci);
17551742
}
17561743

17571744
static void output(struct scoreboard *sb, int option)
@@ -1876,9 +1863,9 @@ static void find_alignment(struct scoreboard *sb, int *option)
18761863
suspect->commit->object.flags |= METAINFO_SHOWN;
18771864
get_commit_info(suspect->commit, &ci, 1);
18781865
if (*option & OUTPUT_SHOW_EMAIL)
1879-
num = utf8_strwidth(ci.author_mail);
1866+
num = utf8_strwidth(ci.author_mail.buf);
18801867
else
1881-
num = utf8_strwidth(ci.author);
1868+
num = utf8_strwidth(ci.author.buf);
18821869
if (longest_author < num)
18831870
longest_author = num;
18841871
}
@@ -1890,6 +1877,8 @@ static void find_alignment(struct scoreboard *sb, int *option)
18901877
longest_dst_lines = num;
18911878
if (largest_score < ent_score(sb, e))
18921879
largest_score = ent_score(sb, e);
1880+
1881+
commit_info_destroy(&ci);
18931882
}
18941883
max_orig_digits = decimal_width(longest_src_lines);
18951884
max_digits = decimal_width(longest_dst_lines);

builtin/log.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "branch.h"
2323
#include "streaming.h"
2424
#include "version.h"
25+
#include "mailmap.h"
2526

2627
/* Set a default date-time format for git log ("log.date" config variable) */
2728
static const char *default_date_mode = NULL;
@@ -30,6 +31,7 @@ static int default_abbrev_commit;
3031
static int default_show_root = 1;
3132
static int decoration_style;
3233
static int decoration_given;
34+
static int use_mailmap_config;
3335
static const char *fmt_patch_subject_prefix = "PATCH";
3436
static const char *fmt_pretty;
3537

@@ -94,16 +96,18 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
9496
struct rev_info *rev, struct setup_revision_opt *opt)
9597
{
9698
struct userformat_want w;
97-
int quiet = 0, source = 0;
99+
int quiet = 0, source = 0, mailmap = 0;
98100

99101
const struct option builtin_log_options[] = {
100102
OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
101103
OPT_BOOLEAN(0, "source", &source, N_("show source")),
104+
OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
102105
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
103106
PARSE_OPT_OPTARG, decorate_callback},
104107
OPT_END()
105108
};
106109

110+
mailmap = use_mailmap_config;
107111
argc = parse_options(argc, argv, prefix,
108112
builtin_log_options, builtin_log_usage,
109113
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
@@ -136,6 +140,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
136140
if (source)
137141
rev->show_source = 1;
138142

143+
if (mailmap) {
144+
rev->mailmap = xcalloc(1, sizeof(struct string_list));
145+
read_mailmap(rev->mailmap, NULL);
146+
}
147+
139148
if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
140149
/*
141150
* "log --pretty=raw" is special; ignore UI oriented
@@ -351,6 +360,11 @@ static int git_log_config(const char *var, const char *value, void *cb)
351360
}
352361
if (!prefixcmp(var, "color.decorate."))
353362
return parse_decorate_color_config(var, 15, value);
363+
if (!strcmp(var, "log.mailmap")) {
364+
use_mailmap_config = git_config_bool(var, value);
365+
return 0;
366+
}
367+
354368
if (grep_config(var, value, cb) < 0)
355369
return -1;
356370
return git_diff_ui_config(var, value, cb);

0 commit comments

Comments
 (0)