mailmap: support reading mailmap from blobs

In a bare repository, there isn't a simple way to respect an in-tree mailmap without extracting it to a temporary file. This patch provides a config variable, similar to mailmap.file, which reads the mailmap from a blob in the repository. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 12, 2012 at 06:04 UTC 086109006f695166daf2934417a20681b0c94ab8
5 files changed +129 -2
Documentation/config.txt
+6
@@ -1517,6 +1517,12 @@ mailmap.file::
1517 subdirectory, or somewhere outside of the repository itself.
1518 See linkgit:git-shortlog[1] and linkgit:git-blame[1].
1519
1520 +mailmap.blob::
1521 + Like `mailmap.file`, but consider the value as a reference to a
1522 + blob in the repository (e.g., `HEAD:.mailmap`). If both
1523 + `mailmap.file` and `mailmap.blob` are given, both are parsed,
1524 + with entries from `mailmap.file` taking precedence.
1525 +
1526 man.viewer::
1527 Specify the programs that may be used to display help in the
1528 'man' format. See linkgit:git-help[1].
cache.h
+1
@@ -1155,6 +1155,7 @@ extern int author_ident_sufficiently_given(void);
1155 extern const char *git_commit_encoding;
1156 extern const char *git_log_output_encoding;
1157 extern const char *git_mailmap_file;
1158 +extern const char *git_mailmap_blob;
1159
1160 /* IO helper functions */
1161 extern void maybe_flush_or_die(FILE *, const char *);
config.c
+2
@@ -839,6 +839,8 @@ static int git_default_mailmap_config(const char *var, const char *value)
839 {
840 if (!strcmp(var, "mailmap.file"))
841 return git_config_string(&git_mailmap_file, var, value);
842 + if (!strcmp(var, "mailmap.blob"))
843 + return git_config_string(&git_mailmap_blob, var, value);
844
845 /* Add other config variables here and to Documentation/config.txt. */
846 return 0;
mailmap.c
+47 -2
@@ -10,6 +10,7 @@ static inline void debug_mm(const char *format, ...) {}
10 #endif
11
12 const char *git_mailmap_file;
13 +const char *git_mailmap_blob;
14
15 struct mailmap_info {
16 char *name;
@@ -177,12 +178,56 @@ static int read_mailmap_file(struct string_list *map, const char *filename,
178 return 0;
179 }
180
181 +static void read_mailmap_buf(struct string_list *map,
182 + const char *buf, unsigned long len,
183 + char **repo_abbrev)
184 +{
185 + while (len) {
186 + const char *end = strchrnul(buf, '\n');
187 + unsigned long linelen = end - buf + 1;
188 + char *line = xmemdupz(buf, linelen);
189 +
190 + read_mailmap_line(map, line, repo_abbrev);
191 +
192 + free(line);
193 + buf += linelen;
194 + len -= linelen;
195 + }
196 +}
197 +
198 +static int read_mailmap_blob(struct string_list *map,
199 + const char *name,
200 + char **repo_abbrev)
201 +{
202 + unsigned char sha1[20];
203 + char *buf;
204 + unsigned long size;
205 + enum object_type type;
206 +
207 + if (!name)
208 + return 1;
209 + if (get_sha1(name, sha1) < 0)
210 + return 1;
211 +
212 + buf = read_sha1_file(sha1, &type, &size);
213 + if (!buf)
214 + return 1;
215 + if (type != OBJ_BLOB)
216 + return 1;
217 +
218 + read_mailmap_buf(map, buf, size, repo_abbrev);
219 +
220 + free(buf);
221 + return 0;
222 +}
223 +
224 int read_mailmap(struct string_list *map, char **repo_abbrev)
225 {
226 map->strdup_strings = 1;
183 - /* each failure returns 1, so >1 means both calls failed */
227 + /* each failure returns 1, so >2 means all calls failed */
228 return read_mailmap_file(map, ".mailmap", repo_abbrev) +
185 - read_mailmap_file(map, git_mailmap_file, repo_abbrev) > 1;
229 + read_mailmap_blob(map, git_mailmap_blob, repo_abbrev) +
230 + read_mailmap_file(map, git_mailmap_file, repo_abbrev) > 2;
231 }
232
233 void clear_mailmap(struct string_list *map)
t/t4203-mailmap.sh
+73
@@ -149,6 +149,79 @@ test_expect_success 'No mailmap files, but configured' '
149 test_cmp expect actual
150 '
151
152 +test_expect_success 'setup mailmap blob tests' '
153 + git checkout -b map &&
154 + test_when_finished "git checkout master" &&
155 + cat >just-bugs <<-\EOF &&
156 + Blob Guy <bugs@company.xx>
157 + EOF
158 + cat >both <<-\EOF &&
159 + Blob Guy <author@example.com>
160 + Blob Guy <bugs@company.xx>
161 + EOF
162 + git add just-bugs both &&
163 + git commit -m "my mailmaps" &&
164 + echo "Repo Guy <author@example.com>" >.mailmap &&
165 + echo "Internal Guy <author@example.com>" >internal.map
166 +'
167 +
168 +test_expect_success 'mailmap.blob set' '
169 + cat >expect <<-\EOF &&
170 + Blob Guy (1):
171 + second
172 +
173 + Repo Guy (1):
174 + initial
175 +
176 + EOF
177 + git -c mailmap.blob=map:just-bugs shortlog HEAD >actual &&
178 + test_cmp expect actual
179 +'
180 +
181 +test_expect_success 'mailmap.blob overrides .mailmap' '
182 + cat >expect <<-\EOF &&
183 + Blob Guy (2):
184 + initial
185 + second
186 +
187 + EOF
188 + git -c mailmap.blob=map:both shortlog HEAD >actual &&
189 + test_cmp expect actual
190 +'
191 +
192 +test_expect_success 'mailmap.file overrides mailmap.blob' '
193 + cat >expect <<-\EOF &&
194 + Blob Guy (1):
195 + second
196 +
197 + Internal Guy (1):
198 + initial
199 +
200 + EOF
201 + git \
202 + -c mailmap.blob=map:both \
203 + -c mailmap.file=internal.map \
204 + shortlog HEAD >actual &&
205 + test_cmp expect actual
206 +'
207 +
208 +test_expect_success 'mailmap.blob can be missing' '
209 + cat >expect <<-\EOF &&
210 + Repo Guy (1):
211 + initial
212 +
213 + nick1 (1):
214 + second
215 +
216 + EOF
217 + git -c mailmap.blob=map:nonexistent shortlog HEAD >actual &&
218 + test_cmp expect actual
219 +'
220 +
221 +test_expect_success 'cleanup after mailmap.blob tests' '
222 + rm -f .mailmap
223 +'
224 +
225 # Extended mailmap configurations should give us the following output for shortlog
226 cat >expect <<\EOF
227 A U Thor <author@example.com> (1):