Skip to content

Commit

Permalink
git-blame --incremental
Browse files Browse the repository at this point in the history
This adds --incremental option to help GUI porcelains to show
the result from git-blame incrementally.  The output gives the
origin information in the same format as the porcelain format.
The first line has commit object name, the line number of the
first line in the group in the original file, the line number of
that file in the final image, and number of lines in the group.
Then subsequent lines show the metainformation for the commit
when the commit is shown for the first time, except the filename
information is always shown (we cannot even make it conditional
to -C option as blame always follows the renaming of the file
wholesale).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Linus Torvalds authored and Junio C Hamano committed Jan 28, 2007
1 parent 0175476 commit 717d146
Showing 1 changed file with 107 additions and 66 deletions.
173 changes: 107 additions & 66 deletions builtin-blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "diff.h"
#include "diffcore.h"
#include "revision.h"
#include "quote.h"
#include "xdiff-interface.h"

static char blame_usage[] =
Expand All @@ -27,6 +28,7 @@ static char blame_usage[] =
" -p, --porcelain Show in a format designed for machine consumption\n"
" -L n,m Process only line range n,m, counting from 1\n"
" -M, -C Find line movements within and across files\n"
" --incremental Show blame entries as we find them, incrementally\n"
" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";

static int longest_file;
Expand All @@ -36,6 +38,7 @@ static int max_digits;
static int max_score_digits;
static int show_root;
static int blank_boundary;
static int incremental;

#ifndef DEBUG
#define DEBUG 0
Expand Down Expand Up @@ -1069,72 +1072,6 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
origin_decref(parent_origin[i]);
}

static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
{
while (1) {
struct blame_entry *ent;
struct commit *commit;
struct origin *suspect = NULL;

/* find one suspect to break down */
for (ent = sb->ent; !suspect && ent; ent = ent->next)
if (!ent->guilty)
suspect = ent->suspect;
if (!suspect)
return; /* all done */

origin_incref(suspect);
commit = suspect->commit;
if (!commit->object.parsed)
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
else {
commit->object.flags |= UNINTERESTING;
if (commit->object.parsed)
mark_parents_uninteresting(commit);
}
/* treat root commit as boundary */
if (!commit->parents && !show_root)
commit->object.flags |= UNINTERESTING;

/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
if (!cmp_suspect(ent->suspect, suspect))
ent->guilty = 1;
origin_decref(suspect);

if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
}
}

static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;

if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
return time_buf;
}

tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);

strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
return time_buf;
}

struct commit_info
{
char *author;
Expand Down Expand Up @@ -1245,6 +1182,105 @@ static void get_commit_info(struct commit *commit,
summary_buf[len] = 0;
}

static void found_guilty_entry(struct blame_entry *ent)
{
if (ent->guilty)
return;
ent->guilty = 1;
if (incremental) {
struct origin *suspect = ent->suspect;

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");
}
printf("filename ");
write_name_quoted(NULL, 0, suspect->path, 1, stdout);
putchar('\n');
}
}

static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
{
while (1) {
struct blame_entry *ent;
struct commit *commit;
struct origin *suspect = NULL;

/* find one suspect to break down */
for (ent = sb->ent; !suspect && ent; ent = ent->next)
if (!ent->guilty)
suspect = ent->suspect;
if (!suspect)
return; /* all done */

origin_incref(suspect);
commit = suspect->commit;
if (!commit->object.parsed)
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
else {
commit->object.flags |= UNINTERESTING;
if (commit->object.parsed)
mark_parents_uninteresting(commit);
}
/* treat root commit as boundary */
if (!commit->parents && !show_root)
commit->object.flags |= UNINTERESTING;

/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
if (!cmp_suspect(ent->suspect, suspect))
found_guilty_entry(ent);
origin_decref(suspect);

if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
}
}

static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;

if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
return time_buf;
}

tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);

strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
return time_buf;
}

#define OUTPUT_ANNOTATE_COMPAT 001
#define OUTPUT_LONG_OBJECT_NAME 002
#define OUTPUT_RAW_TIMESTAMP 004
Expand Down Expand Up @@ -1717,6 +1753,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
die("More than one '-L n,m' option given");
bottomtop = arg;
}
else if (!strcmp("--incremental", arg))
incremental = 1;
else if (!strcmp("--score-debug", arg))
output_option |= OUTPUT_SHOW_SCORE;
else if (!strcmp("-f", arg) ||
Expand Down Expand Up @@ -1907,6 +1945,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)

assign_blame(&sb, &revs, opt);

if (incremental)
return 0;

coalesce(&sb);

if (!(output_option & OUTPUT_PORCELAIN))
Expand Down

0 comments on commit 717d146

Please sign in to comment.