Skip to content

Commit

Permalink
Merge branch 'ms/mailmap'
Browse files Browse the repository at this point in the history
* ms/mailmap:
  Move mailmap documentation into separate file
  Change current mailmap usage to do matching on both name and email of author/committer.
  Add map_user() and clear_mailmap() to mailmap
  Add find_insert_index, insert_at_index and clear_func functions to string_list
  Add mailmap.file as configurational option for mailmap location
  • Loading branch information
Junio C Hamano committed Feb 15, 2009
2 parents 2a8644c + 7d48e9e commit 160d2bc
Show file tree
Hide file tree
Showing 15 changed files with 644 additions and 130 deletions.
8 changes: 8 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,14 @@ log.showroot::
Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
normally hide the root commit will now show it. True by default.

mailmap.file::
The location of an augmenting mailmap file. The default
mailmap, located in the root of the repository, is loaded
first, then the mailmap file pointed to by this variable.
The location of the mailmap file may be in a repository
subdirectory, or somewhere outside of the repository itself.
See linkgit:git-shortlog[1] and linkgit:git-blame[1].

man.viewer::
Specify the programs that may be used to display help in the
'man' format. See linkgit:git-help[1].
Expand Down
6 changes: 6 additions & 0 deletions Documentation/git-blame.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ there is ever added information (like the commit encoding or extended
commit commentary), a blame viewer won't ever care.


MAPPING AUTHORS
---------------

include::mailmap.txt[]


SEE ALSO
--------
linkgit:git-annotate[1]
Expand Down
49 changes: 10 additions & 39 deletions Documentation/git-shortlog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,45 +45,16 @@ OPTIONS
and subsequent lines are indented by `indent2` spaces. `width`,
`indent1`, and `indent2` default to 76, 6 and 9 respectively.

FILES
-----

If a file `.mailmap` exists at the toplevel of the repository,
it is used to map an author email address to a canonical real name. This
can be used to coalesce together commits by the same person where their
name was spelled differently (whether with the same email address or
not).

Each line in the file consists, in this order, of the canonical real name
of an author, whitespace, and an email address (enclosed by '<' and '>')
to map to the name. Use hash '#' for comments, either on their own line,
or after the email address.

A canonical name may appear in more than one line, associated with
different email addresses, but it doesn't make sense for a given address
to appear more than once (if that happens, a later line overrides the
earlier ones).

So, for example, if your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:

------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>
------------

Then, supposing Joe wants his middle name initial used, and Jane prefers
her family name fully spelled out, a proper `.mailmap` file would look like:

------------
# Note how we don't need an entry for <jane@laptop.(none)>, because the
# real name of that author is correct already, and coalesced directly.
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------

MAPPING AUTHORS
---------------

The `.mailmap` feature is used to coalesce together commits by the same
person in the shortlog, where their name and/or email address was
spelled differently.

include::mailmap.txt[]


Author
------
Expand Down
75 changes: 75 additions & 0 deletions Documentation/mailmap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
If the file `.mailmap` exists at the toplevel of the repository, or at
the location pointed to by the mailmap.file configuration option, it
is used to map author and committer names and email addresses to
canonical real names and email addresses.

In the simple form, each line in the file consists of the canonical
real name of an author, whitespace, and an email address used in the
commit (enclosed by '<' and '>') to map to the name. Thus, looks like
this
--
Proper Name <commit@email.xx>
--

The more complex forms are
--
<proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace only the email part of a commit, and
--
Proper Name <proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching the specified commit email address, and
--
Proper Name <proper@email.xx> Commit Name <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching both the specified commit name and email address.

Example 1: Your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:

------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>
------------

Now suppose that Joe wants his middle name initial used, and Jane
prefers her family name fully spelled out. A proper `.mailmap` file
would look like:

------------
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------

Note how we don't need an entry for <jane@laptop.(none)>, because the
real name of that author is correct already.

Example 2: Your repository contains commits from the following
authors:

------------
nick1 <bugs@company.xx>
nick2 <bugs@company.xx>
nick2 <nick2@company.xx>
santa <me@company.xx>
claus <me@company.xx>
CTO <cto@coompany.xx>
------------

Then, you might want a `.mailmap` file looking like:
------------
<cto@company.xx> <cto@coompany.xx>
Some Dude <some@dude.xx> nick1 <bugs@company.xx>
Other Author <other@author.xx> nick2 <bugs@company.xx>
Other Author <other@author.xx> <nick2@company.xx>
Santa Claus <santa.claus@northpole.xx> <me@company.xx>
------------

Use hash '#' for comments that are either on their own line, or after
the email address.
6 changes: 4 additions & 2 deletions Documentation/pretty-formats.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,18 @@ The placeholders are:
- '%P': parent hashes
- '%p': abbreviated parent hashes
- '%an': author name
- '%aN': author name (respecting .mailmap)
- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ae': author email
- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ad': author date (format respects --date= option)
- '%aD': author date, RFC2822 style
- '%ar': author date, relative
- '%at': author date, UNIX timestamp
- '%ai': author date, ISO 8601 format
- '%cn': committer name
- '%cN': committer name (respecting .mailmap)
- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ce': committer email
- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%cd': committer date
- '%cD': committer date, RFC2822 style
- '%cr': committer date, relative
Expand Down
52 changes: 32 additions & 20 deletions builtin-blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -1264,11 +1264,12 @@ struct commit_info
* Parse author/committer line in the commit object buffer
*/
static void get_ac_line(const char *inbuf, const char *what,
int bufsz, char *person, const char **mail,
int person_len, char *person,
int mail_len, char *mail,
unsigned long *time, const char **tz)
{
int len, tzlen, maillen;
char *tmp, *endp, *timepos;
char *tmp, *endp, *timepos, *mailpos;

tmp = strstr(inbuf, what);
if (!tmp)
Expand All @@ -1279,10 +1280,11 @@ static void get_ac_line(const char *inbuf, const char *what,
len = strlen(tmp);
else
len = endp - tmp;
if (bufsz <= len) {
if (person_len <= len) {
error_out:
/* Ugh */
*mail = *tz = "(unknown)";
*tz = "(unknown)";
strcpy(mail, *tz);
*time = 0;
return;
}
Expand All @@ -1305,9 +1307,10 @@ static void get_ac_line(const char *inbuf, const char *what,
*tmp = 0;
while (*tmp != ' ')
tmp--;
*mail = tmp + 1;
mailpos = tmp + 1;
*tmp = 0;
maillen = timepos - tmp;
memcpy(mail, mailpos, maillen);

if (!mailmap.nr)
return;
Expand All @@ -1316,20 +1319,23 @@ static void get_ac_line(const char *inbuf, const char *what,
* mailmap expansion may make the name longer.
* make room by pushing stuff down.
*/
tmp = person + bufsz - (tzlen + 1);
tmp = person + person_len - (tzlen + 1);
memmove(tmp, *tz, tzlen);
tmp[tzlen] = 0;
*tz = tmp;

tmp = tmp - (maillen + 1);
memmove(tmp, *mail, maillen);
tmp[maillen] = 0;
*mail = tmp;

/*
* Now, convert e-mail using mailmap
* Now, convert both name and e-mail using mailmap
*/
map_email(&mailmap, tmp + 1, person, tmp-person-1);
if(map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) {
/* Add a trailing '>' to email, since map_user returns plain emails
Note: It already has '<', since we replace from mail+1 */
mailpos = memchr(mail, '\0', mail_len);
if (mailpos && mailpos-mail < mail_len - 1) {
*mailpos = '>';
*(mailpos+1) = '\0';
}
}
}

static void get_commit_info(struct commit *commit,
Expand All @@ -1338,8 +1344,10 @@ static void get_commit_info(struct commit *commit,
{
int len;
char *tmp, *endp, *reencoded, *message;
static char author_buf[1024];
static char committer_buf[1024];
static char author_name[1024];
static char author_mail[1024];
static char committer_name[1024];
static char committer_mail[1024];
static char summary_buf[1024];

/*
Expand All @@ -1357,19 +1365,23 @@ static void get_commit_info(struct commit *commit,
}
reencoded = reencode_commit_message(commit, NULL);
message = reencoded ? reencoded : commit->buffer;
ret->author = author_buf;
ret->author = author_name;
ret->author_mail = author_mail;
get_ac_line(message, "\nauthor ",
sizeof(author_buf), author_buf, &ret->author_mail,
sizeof(author_name), author_name,
sizeof(author_mail), author_mail,
&ret->author_time, &ret->author_tz);

if (!detailed) {
free(reencoded);
return;
}

ret->committer = committer_buf;
ret->committer = committer_name;
ret->committer_mail = committer_mail;
get_ac_line(message, "\ncommitter ",
sizeof(committer_buf), committer_buf, &ret->committer_mail,
sizeof(committer_name), committer_name,
sizeof(committer_mail), committer_mail,
&ret->committer_time, &ret->committer_tz);

ret->summary = summary_buf;
Expand Down Expand Up @@ -2396,7 +2408,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
die("reading graft file %s failed: %s",
revs_file, strerror(errno));

read_mailmap(&mailmap, ".mailmap", NULL);
read_mailmap(&mailmap, NULL);

if (!incremental)
setup_pager();
Expand Down
25 changes: 19 additions & 6 deletions builtin-shortlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static void insert_one_record(struct shortlog *log,
char *buffer, *p;
struct string_list_item *item;
char namebuf[1024];
char emailbuf[1024];
size_t len;
const char *eol;
const char *boemail, *eoemail;
Expand All @@ -51,7 +52,19 @@ static void insert_one_record(struct shortlog *log,
eoemail = strchr(boemail, '>');
if (!eoemail)
return;
if (!map_email(&log->mailmap, boemail+1, namebuf, sizeof(namebuf))) {

/* copy author name to namebuf, to support matching on both name and email */
memcpy(namebuf, author, boemail - author);
len = boemail - author;
while(len > 0 && isspace(namebuf[len-1]))
len--;
namebuf[len] = 0;

/* copy email name to emailbuf, to allow email replacement as well */
memcpy(emailbuf, boemail+1, eoemail - boemail);
emailbuf[eoemail - boemail - 1] = 0;

if (!map_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf))) {
while (author < boemail && isspace(*author))
author++;
for (len = 0;
Expand All @@ -67,8 +80,8 @@ static void insert_one_record(struct shortlog *log,

if (log->email) {
size_t room = sizeof(namebuf) - len - 1;
int maillen = eoemail - boemail + 1;
snprintf(namebuf + len, room, " %.*s", maillen, boemail);
int maillen = strlen(emailbuf);
snprintf(namebuf + len, room, " <%.*s>", maillen, emailbuf);
}

item = string_list_insert(namebuf, &log->list);
Expand Down Expand Up @@ -219,7 +232,7 @@ void shortlog_init(struct shortlog *log)
{
memset(log, 0, sizeof(*log));

read_mailmap(&log->mailmap, ".mailmap", &log->common_repo_prefix);
read_mailmap(&log->mailmap, &log->common_repo_prefix);

log->list.strdup_strings = 1;
log->wrap = DEFAULT_WRAPLEN;
Expand Down Expand Up @@ -248,6 +261,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;

prefix = setup_git_directory_gently(&nongit);
git_config(git_default_config, NULL);
shortlog_init(&log);
init_revisions(&rev, prefix);
parse_options_start(&ctx, argc, argv, PARSE_OPT_KEEP_DASHDASH |
Expand Down Expand Up @@ -320,6 +334,5 @@ void shortlog_output(struct shortlog *log)

log->list.strdup_strings = 1;
string_list_clear(&log->list, 1);
log->mailmap.strdup_strings = 1;
string_list_clear(&log->mailmap, 1);
clear_mailmap(&log->mailmap);
}
1 change: 1 addition & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@ extern int user_ident_explicitly_given;

extern const char *git_commit_encoding;
extern const char *git_log_output_encoding;
extern const char *git_mailmap_file;

/* IO helper functions */
extern void maybe_flush_or_die(FILE *, const char *);
Expand Down
Loading

0 comments on commit 160d2bc

Please sign in to comment.