*/
struct origin {
int refcnt;
+ struct origin *previous;
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
static void origin_decref(struct origin *o)
{
if (o && --o->refcnt <= 0) {
+ if (o->previous)
+ origin_decref(o->previous);
free(o->file.ptr);
free(o);
}
struct origin *porigin = sg_origin[i];
if (!porigin)
continue;
+ if (!origin->previous) {
+ origin_incref(porigin);
+ origin->previous = porigin;
+ }
if (pass_blame_to_parent(sb, origin, porigin))
goto finish;
}
* 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)
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;
}
*tmp = 0;
while (*tmp != ' ')
tmp--;
- *mail = tmp + 1;
+ mailpos = tmp + 1;
*tmp = 0;
maillen = timepos - tmp;
+ memcpy(mail, mailpos, maillen);
if (!mailmap.nr)
return;
* 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,
{
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];
/*
}
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) {
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;
write_name_quoted(path, stdout, '\n');
}
+/*
+ * Porcelain/Incremental format wants to show a lot of details per
+ * commit. Instead of repeating this every line, emit it only once,
+ * the first time each commit appears in the output.
+ */
+static int emit_one_suspect_detail(struct origin *suspect)
+{
+ struct commit_info ci;
+
+ if (suspect->commit->object.flags & METAINFO_SHOWN)
+ return 0;
+
+ suspect->commit->object.flags |= METAINFO_SHOWN;
+ get_commit_info(suspect->commit, &ci, 1);
+ printf("author %s\n", ci.author);
+ printf("author-mail %s\n", ci.author_mail);
+ printf("author-time %lu\n", ci.author_time);
+ printf("author-tz %s\n", ci.author_tz);
+ printf("committer %s\n", ci.committer);
+ printf("committer-mail %s\n", ci.committer_mail);
+ printf("committer-time %lu\n", ci.committer_time);
+ printf("committer-tz %s\n", ci.committer_tz);
+ printf("summary %s\n", ci.summary);
+ if (suspect->commit->object.flags & UNINTERESTING)
+ printf("boundary\n");
+ if (suspect->previous) {
+ struct origin *prev = suspect->previous;
+ printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
+ write_name_quoted(prev->path, stdout, '\n');
+ }
+ return 1;
+}
+
/*
* The blame_entry is found to be guilty for the range. Mark it
* as such, and show it in incremental output.
printf("%s %d %d %d\n",
sha1_to_hex(suspect->commit->object.sha1),
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
- if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
- struct commit_info ci;
- suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
- printf("author %s\n", ci.author);
- printf("author-mail %s\n", ci.author_mail);
- printf("author-time %lu\n", ci.author_time);
- printf("author-tz %s\n", ci.author_tz);
- printf("committer %s\n", ci.committer);
- printf("committer-mail %s\n", ci.committer_mail);
- printf("committer-time %lu\n", ci.committer_time);
- printf("committer-tz %s\n", ci.committer_tz);
- printf("summary %s\n", ci.summary);
- if (suspect->commit->object.flags & UNINTERESTING)
- printf("boundary\n");
- }
+ emit_one_suspect_detail(suspect);
write_filename_info(suspect->path);
maybe_flush_or_die(stdout, "stdout");
}
ent->s_lno + 1,
ent->lno + 1,
ent->num_lines);
- if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
- struct commit_info ci;
- suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
- printf("author %s\n", ci.author);
- printf("author-mail %s\n", ci.author_mail);
- printf("author-time %lu\n", ci.author_time);
- printf("author-tz %s\n", ci.author_tz);
- printf("committer %s\n", ci.committer);
- printf("committer-mail %s\n", ci.committer_mail);
- printf("committer-time %lu\n", ci.committer_time);
- printf("committer-tz %s\n", ci.committer_tz);
- write_filename_info(suspect->path);
- printf("summary %s\n", ci.summary);
- if (suspect->commit->object.flags & UNINTERESTING)
- printf("boundary\n");
- }
- else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
+ if (emit_one_suspect_detail(suspect) ||
+ (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
write_filename_info(suspect->path);
cp = nth_line(sb, ent->lno);
baa = 1;
}
}
- for (ent = sb->ent; ent; ent = ent->next) {
- /* Mark the ones that haven't been checked */
- if (0 < ent->suspect->refcnt)
- ent->suspect->refcnt = -ent->suspect->refcnt;
- }
- for (ent = sb->ent; ent; ent = ent->next) {
- /*
- * ... then pick each and see if they have the the
- * correct refcnt.
- */
- int found;
- struct blame_entry *e;
- struct origin *suspect = ent->suspect;
-
- if (0 < suspect->refcnt)
- continue;
- suspect->refcnt = -suspect->refcnt; /* Unmark */
- for (found = 0, e = sb->ent; e; e = e->next) {
- if (e->suspect != suspect)
- continue;
- found++;
- }
- if (suspect->refcnt != found) {
- fprintf(stderr, "%s in %s has refcnt %d, not %d\n",
- ent->suspect->path,
- sha1_to_hex(ent->suspect->commit->object.sha1),
- ent->suspect->refcnt, found);
- baa = 2;
- }
- }
if (baa) {
int opt = 0160;
find_alignment(sb, &opt);
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
- read_mailmap(&mailmap, ".mailmap", NULL);
+ read_mailmap(&mailmap, NULL);
if (!incremental)
setup_pager();