[PATCH 0/5] Allow git log to use mailmap file

DORMANTno replies

Revision v1 of 2 in this series.

7 messages, 1 author, 2016-06-15 · open the first message on its own page

[PATCH 0/5] Allow git log to use mailmap file

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

Implement the feature suggested here [1] by Rich Mindwinter
and Junio C Hamano (and following his advices)

This is a pre-version so there are a bunch of things still missing,
among them:
 - There is no tests
 - Grep search for mailmap author/committer is not available
 - There is no documentation of the new option

[1]: http://thread.gmane.org/gmane.comp.version-control.git/211270

Antoine Pelisse (5):
  Use split_ident_line to parse author and committer
  mailmap: Remove buffer length limit in map_user
  mailmap: Add mailmap structure to rev_info and pp
  pretty: Use mailmap to display username and email
  log: Add --use-mailmap option

 builtin/blame.c | 59 +++++++++++++++++-------------------------------
 builtin/log.c   |  9 +++++++-
 commit.h        |  1 +
 log-tree.c      |  1 +
 mailmap.c       | 16 ++++++-------
 pretty.c        | 70 ++++++++++++++++++++++++++++++++++++---------------------
 revision.h      |  1 +
 7 files changed, 84 insertions(+), 73 deletions(-)

--
1.8.1.rc1.5.g7e0651a

[PATCH 2/5] mailmap: Remove buffer length limit in map_user

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

Remove the hard limit set by mail buffer in map_user and
use the strbuf API to replace it.

Signed-off-by: Antoine Pelisse <redacted>
---
 mailmap.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/mailmap.c b/mailmap.c
index ea4b471..e636278 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -193,7 +193,8 @@ int map_user(struct string_list *map,
 	char *end_of_email;
 	struct string_list_item *item;
 	struct mailmap_entry *me;
-	char buf[1024], *mailbuf;
+	struct strbuf buf = STRBUF_INIT;
+	char *mailbuf;
 	int i;
 
 	/* figure out space requirement for email */
@@ -204,15 +205,13 @@ int map_user(struct string_list *map,
 		if (!end_of_email)
 			return 0;
 	}
-	if (end_of_email - email + 1 < sizeof(buf))
-		mailbuf = buf;
-	else
-		mailbuf = xmalloc(end_of_email - email + 1);
 
 	/* downcase the email address */
+	strbuf_grow(&buf, end_of_email - email);
 	for (i = 0; i < end_of_email - email; i++)
-		mailbuf[i] = tolower(email[i]);
-	mailbuf[i] = 0;
+		strbuf_addch(&buf, tolower(email[i]));
+	strbuf_addch(&buf, 0);
+	mailbuf = strbuf_detach(&buf, 0);
 
 	debug_mm("map_user: map '%s' <%s>\n", name, mailbuf);
 	item = string_list_lookup(map, mailbuf);
@@ -226,8 +225,7 @@ int map_user(struct string_list *map,
 				item = subitem;
 		}
 	}
-	if (mailbuf != buf)
-		free(mailbuf);
+	free(mailbuf);
 	if (item != NULL) {
 		struct mailmap_info *mi = (struct mailmap_info *)item->util;
 		if (mi->name == NULL && (mi->email == NULL || maxlen_email == 0)) {
-- 
1.8.1.rc1.5.g7e0651a

[PATCH 3/5] mailmap: Add mailmap structure to rev_info and pp

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

the mailmap string_list structure filled with mailmap
information is passed along from rev_info to pretty_print_context
to provide mailmap information to pretty print each commits
with the correct username and email.

Signed-off-by: Antoine Pelisse <redacted>
---
 commit.h   | 1 +
 log-tree.c | 1 +
 revision.h | 1 +
 3 files changed, 3 insertions(+)
diff --git a/commit.h b/commit.h
index b6ad8f3..7f8f987 100644
--- a/commit.h
+++ b/commit.h
@@ -89,6 +89,7 @@ struct pretty_print_context {
 	char *notes_message;
 	struct reflog_walk_info *reflog_info;
 	const char *output_encoding;
+	struct string_list *mailmap;
 };
 
 struct userformat_want {
diff --git a/log-tree.c b/log-tree.c
index 4f86def..92254fd 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -671,6 +671,7 @@ void show_log(struct rev_info *opt)
 	ctx.preserve_subject = opt->preserve_subject;
 	ctx.reflog_info = opt->reflog_info;
 	ctx.fmt = opt->commit_format;
+	ctx.mailmap = opt->mailmap;
 	pretty_print_commit(&ctx, commit, &msgbuf);
 
 	if (opt->add_signoff)
diff --git a/revision.h b/revision.h
index 059bfff..83a79f5 100644
--- a/revision.h
+++ b/revision.h
@@ -143,6 +143,7 @@ struct rev_info {
 	const char	*subject_prefix;
 	int		no_inline;
 	int		show_log_size;
+	struct string_list *mailmap;
 
 	/* Filter by commit log message */
 	struct grep_opt	grep_filter;
-- 
1.8.1.rc1.5.g7e0651a

[PATCH 1/5] Use split_ident_line to parse author and committer

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

Currently blame.c::get_acline and pretty.c::pp_user_info()
are parsing author name, email, time and tz themselves.

Use ident.c::split_ident_line for better code reuse.

Signed-off-by: Antoine Pelisse <redacted>
---
 builtin/blame.c | 59 ++++++++++++++++++++-------------------------------------
 pretty.c        | 32 +++++++++++++++++--------------
 2 files changed, 39 insertions(+), 52 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index cfae569..dd4aff9 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1343,8 +1343,9 @@ static void get_ac_line(const char *inbuf, const char *what,
 			int mail_len, char *mail,
 			unsigned long *time, const char **tz)
 {
-	int len, tzlen, maillen;
-	char *tmp, *endp, *timepos, *mailpos;
+	struct ident_split ident;
+	int len, tzlen, maillen, namelen;
+	char *tmp, *endp, *mailpos;
 
 	tmp = strstr(inbuf, what);
 	if (!tmp)
@@ -1355,7 +1356,10 @@ static void get_ac_line(const char *inbuf, const char *what,
 		len = strlen(tmp);
 	else
 		len = endp - tmp;
-	if (person_len <= len) {
+	if (person_len <= len)
+		goto error_out;
+
+	if (split_ident_line(&ident, tmp, len)) {
 	error_out:
 		/* Ugh */
 		*tz = "(unknown)";
@@ -1364,47 +1368,26 @@ static void get_ac_line(const char *inbuf, const char *what,
 		*time = 0;
 		return;
 	}
-	memcpy(person, tmp, len);
 
-	tmp = person;
-	tmp += len;
-	*tmp = 0;
-	while (person < tmp && *tmp != ' ')
-		tmp--;
-	if (tmp <= person)
-		goto error_out;
-	*tz = tmp+1;
-	tzlen = (person+len)-(tmp+1);
+	namelen = ident.name_end - ident.name_begin;
+	memcpy(person, ident.name_begin, namelen);
+	person[namelen] = 0;
 
-	*tmp = 0;
-	while (person < tmp && *tmp != ' ')
-		tmp--;
-	if (tmp <= person)
-		goto error_out;
-	*time = strtoul(tmp, NULL, 10);
-	timepos = tmp;
+	maillen = ident.mail_end - ident.mail_begin + 2;
+	memcpy(mail, ident.mail_begin - 1, maillen);
+	mail[maillen] = 0;
 
-	*tmp = 0;
-	while (person < tmp && !(*tmp == ' ' && tmp[1] == '<'))
-		tmp--;
-	if (tmp <= person)
-		return;
-	mailpos = tmp + 1;
-	*tmp = 0;
-	maillen = timepos - tmp;
-	memcpy(mail, mailpos, maillen);
+	*time = strtoul(ident.date_begin, NULL, 10);
 
-	if (!mailmap.nr)
-		return;
+	tzlen = ident.tz_end - ident.tz_begin;
 
-	/*
-	 * mailmap expansion may make the name longer.
-	 * make room by pushing stuff down.
-	 */
-	tmp = person + person_len - (tzlen + 1);
-	memmove(tmp, *tz, tzlen);
+	/* Place tz at the end of person */
+	*tz = tmp = person + person_len - (tzlen + 1);
+	memcpy(tmp, ident.tz_begin, tzlen);
 	tmp[tzlen] = 0;
-	*tz = tmp;
+
+	if (!mailmap.nr)
+		return;
 
 	/*
 	 * Now, convert both name and e-mail using mailmap
diff --git a/pretty.c b/pretty.c
index 5bdc2e7..6730add 100644
--- a/pretty.c
+++ b/pretty.c
@@ -387,29 +387,33 @@ void pp_user_info(const struct pretty_print_context *pp,
 		  const char *what, struct strbuf *sb,
 		  const char *line, const char *encoding)
 {
+	struct ident_split ident;
+	int linelen, namelen;
+	char *line_end, *date;
 	int max_length = 78; /* per rfc2822 */
-	char *date;
-	int namelen;
 	unsigned long time;
 	int tz;
 
 	if (pp->fmt == CMIT_FMT_ONELINE)
 		return;
-	date = strchr(line, '>');
-	if (!date)
+
+	line_end = strchr(line, '\n');
+	if (!line_end)
+		return;
+
+	linelen = ++line_end - line;
+	if (split_ident_line(&ident, line, linelen))
 		return;
-	namelen = ++date - line;
-	time = strtoul(date, &date, 10);
+
+	namelen = ident.mail_end - ident.name_begin + 1;
+	time = strtoul(ident.date_begin, &date, 10);
 	tz = strtol(date, NULL, 10);
 
 	if (pp->fmt == CMIT_FMT_EMAIL) {
-		char *name_tail = strchr(line, '<');
 		int display_name_length;
-		if (!name_tail)
-			return;
-		while (line < name_tail && isspace(name_tail[-1]))
-			name_tail--;
-		display_name_length = name_tail - line;
+
+		display_name_length = ident.name_end - ident.name_begin;
+
 		strbuf_addstr(sb, "From: ");
 		if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {
 			add_rfc2047(sb, line, display_name_length,
@@ -427,10 +431,10 @@ void pp_user_info(const struct pretty_print_context *pp,
 		}
 		if (namelen - display_name_length + last_line_length(sb) > max_length) {
 			strbuf_addch(sb, '\n');
-			if (!isspace(name_tail[0]))
+			if (!isspace(ident.name_end[0]))
 				strbuf_addch(sb, ' ');
 		}
-		strbuf_add(sb, name_tail, namelen - display_name_length);
+		strbuf_add(sb, ident.name_end, namelen - display_name_length);
 		strbuf_addch(sb, '\n');
 	} else {
 		strbuf_addf(sb, "%s: %.*s%.*s\n", what,
-- 
1.8.1.rc1.5.g7e0651a

[PATCH 4/5] pretty: Use mailmap to display username and email

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

Use the mailmap information to display the correct
username and email address in all log commands.

Signed-off-by: Antoine Pelisse <redacted>
---
 pretty.c | 46 +++++++++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 15 deletions(-)
diff --git a/pretty.c b/pretty.c
index 6730add..e232aaa 100644
--- a/pretty.c
+++ b/pretty.c
@@ -387,6 +387,8 @@ void pp_user_info(const struct pretty_print_context *pp,
 		  const char *what, struct strbuf *sb,
 		  const char *line, const char *encoding)
 {
+	char person_name[1024];
+	char person_mail[1024];
 	struct ident_split ident;
 	int linelen, namelen;
 	char *line_end, *date;
@@ -405,41 +407,55 @@ void pp_user_info(const struct pretty_print_context *pp,
 	if (split_ident_line(&ident, line, linelen))
 		return;
 
-	namelen = ident.mail_end - ident.name_begin + 1;
+	memcpy(person_mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
+	person_mail[ident.mail_end - ident.mail_begin] = 0;
+
+	memcpy(person_name, ident.name_begin, ident.name_end - ident.name_begin);
+	person_name[ident.name_end - ident.name_begin] = 0;
+
+	if (pp->mailmap)
+		map_user(pp->mailmap, person_mail, sizeof(person_mail),
+			 person_name, sizeof(person_name));
+
+	namelen = strlen(person_name) + strlen(person_mail);
 	time = strtoul(ident.date_begin, &date, 10);
 	tz = strtol(date, NULL, 10);
 
 	if (pp->fmt == CMIT_FMT_EMAIL) {
 		int display_name_length;
 
-		display_name_length = ident.name_end - ident.name_begin;
+		display_name_length = strlen(person_name);
 
 		strbuf_addstr(sb, "From: ");
-		if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {
-			add_rfc2047(sb, line, display_name_length,
+		if (needs_rfc2047_encoding(person_name, display_name_length, RFC2047_ADDRESS)) {
+			add_rfc2047(sb, person_name, display_name_length,
 						encoding, RFC2047_ADDRESS);
 			max_length = 76; /* per rfc2047 */
-		} else if (needs_rfc822_quoting(line, display_name_length)) {
+		} else if (needs_rfc822_quoting(person_name,
+						display_name_length)) {
 			struct strbuf quoted = STRBUF_INIT;
-			add_rfc822_quoted(&quoted, line, display_name_length);
+			add_rfc822_quoted(&quoted, person_name,
+					  display_name_length);
 			strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
 							-6, 1, max_length);
 			strbuf_release(&quoted);
 		} else {
-			strbuf_add_wrapped_bytes(sb, line, display_name_length,
-							-6, 1, max_length);
+			strbuf_add_wrapped_bytes(sb, person_name,
+						 display_name_length,
+						 -6, 1, max_length);
 		}
-		if (namelen - display_name_length + last_line_length(sb) > max_length) {
+		if (namelen - display_name_length + last_line_length(sb) > max_length)
 			strbuf_addch(sb, '\n');
-			if (!isspace(ident.name_end[0]))
-				strbuf_addch(sb, ' ');
-		}
-		strbuf_add(sb, ident.name_end, namelen - display_name_length);
+
+		strbuf_addch(sb, ' ');
+		strbuf_addch(sb, '<');
+		strbuf_add(sb, person_mail, strlen(person_mail));
+		strbuf_addch(sb, '>');
 		strbuf_addch(sb, '\n');
 	} else {
-		strbuf_addf(sb, "%s: %.*s%.*s\n", what,
+		strbuf_addf(sb, "%s: %.*s%s <%s>\n", what,
 			      (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,
-			      "    ", namelen, line);
+			    "    ", person_name, person_mail);
 	}
 	switch (pp->fmt) {
 	case CMIT_FMT_MEDIUM:
-- 
1.8.1.rc1.5.g7e0651a

[PATCH 5/5] log: Add --use-mailmap option

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

Add the --use-mailmap option to log commands. It allows
to display names from mailmap file when displaying logs,
whatever the format used.

Signed-off-by: Antoine Pelisse <redacted>
---
 builtin/log.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/builtin/log.c b/builtin/log.c
index e7b7db1..d2bd8ce 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -22,6 +22,7 @@
 #include "branch.h"
 #include "streaming.h"
 #include "version.h"
+#include "mailmap.h"
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -94,11 +95,12 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 			 struct rev_info *rev, struct setup_revision_opt *opt)
 {
 	struct userformat_want w;
-	int quiet = 0, source = 0;
+	int quiet = 0, source = 0, mailmap = 0;
 
 	const struct option builtin_log_options[] = {
 		OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
 		OPT_BOOLEAN(0, "source", &source, N_("show source")),
+		OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
 		{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
 		  PARSE_OPT_OPTARG, decorate_callback},
 		OPT_END()
@@ -136,6 +138,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 	if (source)
 		rev->show_source = 1;
 
+	if (mailmap) {
+		rev->mailmap = xcalloc(1, sizeof(struct string_list));
+		read_mailmap(rev->mailmap, NULL);
+	}
+
 	if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
 		/*
 		 * "log --pretty=raw" is special; ignore UI oriented
-- 
1.8.1.rc1.5.g7e0651a

Re: [PATCH 5/5] log: Add --use-mailmap option

From: Antoine Pelisse <hidden>
Date: 2016-06-15 22:55:30

On Tue, Dec 11, 2012 at 11:21 PM, Antoine Pelisse [off-list ref] wrote:
Add the --use-mailmap option to log commands. It allows
to display names from mailmap file when displaying logs,
whatever the format used.
The question is which log commands actually ?
Shouldn't we put the option in revision.c::handle_revision_opt instead ?
My opinion is that it belongs to 'Commit Formatting'.
It would also make sense to be able to use '--use-mailmap' when running
format-patch for example.

Also, I've noticed that my series break some tests (linked with
format-patch BTW).
I fixed that and re-ran all tests successfully. I will resubmit it later.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help