#define DEBUG 0
#endif
-/* stats */
-static int num_read_blob;
-static int num_get_patch;
-static int num_commits;
-
#define PICKAXE_BLAME_MOVE 01
#define PICKAXE_BLAME_COPY 02
#define PICKAXE_BLAME_COPY_HARDER 04
#define PICKAXE_BLAME_COPY_HARDEST 010
-/*
- * blame for a blame_entry with score lower than these thresholds
- * is not passed to the parent using move/copy logic.
- */
static unsigned blame_move_score;
static unsigned blame_copy_score;
#define BLAME_DEFAULT_MOVE_SCORE 20
/*
* One blob in a commit that is being suspected
*/
-struct origin {
+struct blame_origin {
int refcnt;
/* Record preceding blame record for this blob */
- struct origin *previous;
+ struct blame_origin *previous;
/* origins are put in a list linked via `next' hanging off the
* corresponding commit's util field in order to make finding
* them fast. The presence in this chain does not count
* us get tripped up by this case, it certainly does not seem
* worth optimizing for.
*/
- struct origin *next;
+ struct blame_origin *next;
struct commit *commit;
/* `suspects' contains blame entries that may be attributed to
* this origin's commit or to parent commits. When a commit
* diff machinery
*/
static void fill_origin_blob(struct diff_options *opt,
- struct origin *o, mmfile_t *file)
+ struct blame_origin *o, mmfile_t *file, int *num_read_blob)
{
if (!o->file.ptr) {
enum object_type type;
unsigned long file_size;
- num_read_blob++;
+ (*num_read_blob)++;
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
;
* Origin is refcounted and usually we keep the blob contents to be
* reused.
*/
-static inline struct origin *origin_incref(struct origin *o)
+static inline struct blame_origin *blame_origin_incref(struct blame_origin *o)
{
if (o)
o->refcnt++;
return o;
}
-static void origin_decref(struct origin *o)
+static void blame_origin_decref(struct blame_origin *o)
{
if (o && --o->refcnt <= 0) {
- struct origin *p, *l = NULL;
+ struct blame_origin *p, *l = NULL;
if (o->previous)
- origin_decref(o->previous);
+ blame_origin_decref(o->previous);
free(o->file.ptr);
/* Should be present exactly once in commit chain */
for (p = o->commit->util; p; l = p, p = p->next) {
return;
}
}
- die("internal error in blame::origin_decref");
+ die("internal error in blame_origin_decref");
}
}
-static void drop_origin_blob(struct origin *o)
+static void drop_origin_blob(struct blame_origin *o)
{
if (o->file.ptr) {
free(o->file.ptr);
int num_lines;
/* the commit that introduced this group into the final image */
- struct origin *suspect;
+ struct blame_origin *suspect;
/* the line number of the first line of this group in the
* suspect's file; internally all line numbers are 0 based.
/*
* The current state of the blame assignment.
*/
-struct scoreboard {
+struct blame_scoreboard {
/* the final commit (i.e. where we started digging from) */
struct commit *final;
/* Priority queue for commits with unassigned blame records */
/* look-up a line in the final buffer */
int num_lines;
int *lineno;
+
+ /* stats */
+ int num_read_blob;
+ int num_get_patch;
+ int num_commits;
+
+ /*
+ * blame for a blame_entry with score lower than these thresholds
+ * is not passed to the parent using move/copy logic.
+ */
+ unsigned move_score;
+ unsigned copy_score;
+
+ /* use this file's contents as the final image */
+ const char *contents_from;
};
-static void sanity_check_refcnt(struct scoreboard *);
+static void sanity_check_refcnt(struct blame_scoreboard *);
/*
* If two blame entries that are next to each other came from
* contiguous lines in the same origin (i.e. <commit, path> pair),
* merge them together.
*/
-static void coalesce(struct scoreboard *sb)
+static void blame_coalesce(struct blame_scoreboard *sb)
{
struct blame_entry *ent, *next;
ent->s_lno + ent->num_lines == next->s_lno) {
ent->num_lines += next->num_lines;
ent->next = next->next;
- origin_decref(next->suspect);
+ blame_origin_decref(next->suspect);
free(next);
ent->score = 0;
next = ent; /* again */
* the commit priority queue of the score board.
*/
-static void queue_blames(struct scoreboard *sb, struct origin *porigin,
+static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porigin,
struct blame_entry *sorted)
{
if (porigin->suspects)
porigin->suspects = blame_merge(porigin->suspects, sorted);
else {
- struct origin *o;
+ struct blame_origin *o;
for (o = porigin->commit->util; o; o = o->next) {
if (o->suspects) {
porigin->suspects = sorted;
* get_origin() to obtain shared, refcounted copy instead of calling
* this function directly.
*/
-static struct origin *make_origin(struct commit *commit, const char *path)
+static struct blame_origin *make_origin(struct commit *commit, const char *path)
{
- struct origin *o;
+ struct blame_origin *o;
FLEX_ALLOC_STR(o, path, path);
o->commit = commit;
o->refcnt = 1;
* Locate an existing origin or create a new one.
* This moves the origin to front position in the commit util list.
*/
-static struct origin *get_origin(struct commit *commit, const char *path)
+static struct blame_origin *get_origin(struct commit *commit, const char *path)
{
- struct origin *o, *l;
+ struct blame_origin *o, *l;
for (o = commit->util, l = NULL; o; l = o, o = o->next) {
if (!strcmp(o->path, path)) {
o->next = commit->util;
commit->util = o;
}
- return origin_incref(o);
+ return blame_origin_incref(o);
}
}
return make_origin(commit, path);
*
* This also fills origin->mode for corresponding tree path.
*/
-static int fill_blob_sha1_and_mode(struct origin *origin)
+static int fill_blob_sha1_and_mode(struct blame_origin *origin)
{
if (!is_null_oid(&origin->blob_oid))
return 0;
* We have an origin -- check if the same path exists in the
* parent and return an origin structure to represent it.
*/
-static struct origin *find_origin(struct commit *parent,
- struct origin *origin)
+static struct blame_origin *find_origin(struct commit *parent,
+ struct blame_origin *origin)
{
- struct origin *porigin;
+ struct blame_origin *porigin;
struct diff_options diff_opts;
const char *paths[2];
* The same path between origin and its parent
* without renaming -- the most common case.
*/
- return origin_incref (porigin);
+ return blame_origin_incref (porigin);
}
/* See if the origin->path is different between parent
* We have an origin -- find the path that corresponds to it in its
* parent and return an origin structure to represent it.
*/
-static struct origin *find_rename(struct commit *parent,
- struct origin *origin)
+static struct blame_origin *find_rename(struct commit *parent,
+ struct blame_origin *origin)
{
- struct origin *porigin = NULL;
+ struct blame_origin *porigin = NULL;
struct diff_options diff_opts;
int i;
{
struct blame_entry *e = xmalloc(sizeof(*e));
memcpy(e, src, sizeof(*e));
- origin_incref(e->suspect);
+ blame_origin_incref(e->suspect);
e->next = **queue;
**queue = e;
static void dup_entry(struct blame_entry ***queue,
struct blame_entry *dst, struct blame_entry *src)
{
- origin_incref(src->suspect);
- origin_decref(dst->suspect);
+ blame_origin_incref(src->suspect);
+ blame_origin_decref(dst->suspect);
memcpy(dst, src, sizeof(*src));
dst->next = **queue;
**queue = dst;
*queue = &dst->next;
}
-static const char *nth_line(struct scoreboard *sb, long lno)
+static const char *blame_nth_line(struct blame_scoreboard *sb, long lno)
{
return sb->final_buf + sb->lineno[lno];
}
static const char *nth_line_cb(void *data, long lno)
{
- return nth_line((struct scoreboard *)data, lno);
+ return blame_nth_line((struct blame_scoreboard *)data, lno);
}
/*
static void split_overlap(struct blame_entry *split,
struct blame_entry *e,
int tlno, int plno, int same,
- struct origin *parent)
+ struct blame_origin *parent)
{
int chunk_end_lno;
memset(split, 0, sizeof(struct blame_entry [3]));
if (e->s_lno < tlno) {
/* there is a pre-chunk part not blamed on parent */
- split[0].suspect = origin_incref(e->suspect);
+ split[0].suspect = blame_origin_incref(e->suspect);
split[0].lno = e->lno;
split[0].s_lno = e->s_lno;
split[0].num_lines = tlno - e->s_lno;
if (same < e->s_lno + e->num_lines) {
/* there is a post-chunk part not blamed on parent */
- split[2].suspect = origin_incref(e->suspect);
+ split[2].suspect = blame_origin_incref(e->suspect);
split[2].lno = e->lno + (same - e->s_lno);
split[2].s_lno = e->s_lno + (same - e->s_lno);
split[2].num_lines = e->s_lno + e->num_lines - same;
*/
if (split[1].num_lines < 1)
return;
- split[1].suspect = origin_incref(parent);
+ split[1].suspect = blame_origin_incref(parent);
}
/*
int i;
for (i = 0; i < 3; i++)
- origin_decref(split[i].suspect);
+ blame_origin_decref(split[i].suspect);
}
/*
*/
static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
int tlno, int offset, int same,
- struct origin *parent)
+ struct blame_origin *parent)
{
struct blame_entry *e = **srcq;
struct blame_entry *samep = NULL, *diffp = NULL;
n->next = diffp;
diffp = n;
} else
- origin_decref(e->suspect);
+ blame_origin_decref(e->suspect);
/* Pass blame for everything before the differing
* chunk to the parent */
- e->suspect = origin_incref(parent);
+ e->suspect = blame_origin_incref(parent);
e->s_lno += offset;
e->next = samep;
samep = e;
*/
int len = same - e->s_lno;
struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
- n->suspect = origin_incref(e->suspect);
+ n->suspect = blame_origin_incref(e->suspect);
n->lno = e->lno + len;
n->s_lno = e->s_lno + len;
n->num_lines = e->num_lines - len;
}
struct blame_chunk_cb_data {
- struct origin *parent;
+ struct blame_origin *parent;
long offset;
struct blame_entry **dstq;
struct blame_entry **srcq;
* for the lines it is suspected to its parent. Run diff to find
* which lines came from parent and pass blame for them.
*/
-static void pass_blame_to_parent(struct scoreboard *sb,
- struct origin *target,
- struct origin *parent)
+static void pass_blame_to_parent(struct blame_scoreboard *sb,
+ struct blame_origin *target,
+ struct blame_origin *parent)
{
mmfile_t file_p, file_o;
struct blame_chunk_cb_data d;
d.offset = 0;
d.dstq = &newdest; d.srcq = &target->suspects;
- fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
- fill_origin_blob(&sb->revs->diffopt, target, &file_o);
- num_get_patch++;
+ fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
+ fill_origin_blob(&sb->revs->diffopt, target, &file_o, &sb->num_read_blob);
+ sb->num_get_patch++;
if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d))
die("unable to generate diff (%s -> %s)",
*
* Compute how trivial the lines in the blame_entry are.
*/
-static unsigned ent_score(struct scoreboard *sb, struct blame_entry *e)
+static unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
{
unsigned score;
const char *cp, *ep;
return e->score;
score = 1;
- cp = nth_line(sb, e->lno);
- ep = nth_line(sb, e->lno + e->num_lines);
+ cp = blame_nth_line(sb, e->lno);
+ ep = blame_nth_line(sb, e->lno + e->num_lines);
while (cp < ep) {
unsigned ch = *((unsigned char *)cp);
if (isalnum(ch))
* so far, by comparing this and best_so_far and copying this into
* bst_so_far as needed.
*/
-static void copy_split_if_better(struct scoreboard *sb,
+static void copy_split_if_better(struct blame_scoreboard *sb,
struct blame_entry *best_so_far,
struct blame_entry *this)
{
if (!this[1].suspect)
return;
if (best_so_far[1].suspect) {
- if (ent_score(sb, &this[1]) < ent_score(sb, &best_so_far[1]))
+ if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1]))
return;
}
for (i = 0; i < 3; i++)
- origin_incref(this[i].suspect);
+ blame_origin_incref(this[i].suspect);
decref_split(best_so_far);
memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
}
*
* All line numbers are 0-based.
*/
-static void handle_split(struct scoreboard *sb,
+static void handle_split(struct blame_scoreboard *sb,
struct blame_entry *ent,
int tlno, int plno, int same,
- struct origin *parent,
+ struct blame_origin *parent,
struct blame_entry *split)
{
if (ent->num_lines <= tlno)
}
struct handle_split_cb_data {
- struct scoreboard *sb;
+ struct blame_scoreboard *sb;
struct blame_entry *ent;
- struct origin *parent;
+ struct blame_origin *parent;
struct blame_entry *split;
long plno;
long tlno;
* we can pass blames to it. file_p has the blob contents for
* the parent.
*/
-static void find_copy_in_blob(struct scoreboard *sb,
+static void find_copy_in_blob(struct blame_scoreboard *sb,
struct blame_entry *ent,
- struct origin *parent,
+ struct blame_origin *parent,
struct blame_entry *split,
mmfile_t *file_p)
{
/*
* Prepare mmfile that contains only the lines in ent.
*/
- cp = nth_line(sb, ent->lno);
+ cp = blame_nth_line(sb, ent->lno);
file_o.ptr = (char *) cp;
- file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp;
+ file_o.size = blame_nth_line(sb, ent->lno + ent->num_lines) - cp;
/*
* file_o is a part of final image we are annotating.
* Returns a pointer to the link pointing to the old head of the small list.
*/
-static struct blame_entry **filter_small(struct scoreboard *sb,
+static struct blame_entry **filter_small(struct blame_scoreboard *sb,
struct blame_entry **small,
struct blame_entry **source,
unsigned score_min)
struct blame_entry *p = *source;
struct blame_entry *oldsmall = *small;
while (p) {
- if (ent_score(sb, p) <= score_min) {
+ if (blame_entry_score(sb, p) <= score_min) {
*small = p;
small = &p->next;
p = *small;
* See if lines currently target is suspected for can be attributed to
* parent.
*/
-static void find_move_in_parent(struct scoreboard *sb,
+static void find_move_in_parent(struct blame_scoreboard *sb,
struct blame_entry ***blamed,
struct blame_entry **toosmall,
- struct origin *target,
- struct origin *parent)
+ struct blame_origin *target,
+ struct blame_origin *parent)
{
struct blame_entry *e, split[3];
struct blame_entry *unblamed = target->suspects;
if (!unblamed)
return; /* nothing remains for this target */
- fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
+ fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
if (!file_p.ptr)
return;
next = e->next;
find_copy_in_blob(sb, e, parent, split, &file_p);
if (split[1].suspect &&
- blame_move_score < ent_score(sb, &split[1])) {
+ sb->move_score < blame_entry_score(sb, &split[1])) {
split_blame(blamed, &unblamedtail, split, e);
} else {
e->next = leftover;
decref_split(split);
}
*unblamedtail = NULL;
- toosmall = filter_small(sb, toosmall, &unblamed, blame_move_score);
+ toosmall = filter_small(sb, toosmall, &unblamed, sb->move_score);
} while (unblamed);
target->suspects = reverse_blame(leftover, NULL);
}
* across file boundary from the parent commit. porigin is the path
* in the parent we already tried.
*/
-static void find_copy_in_parent(struct scoreboard *sb,
+static void find_copy_in_parent(struct blame_scoreboard *sb,
struct blame_entry ***blamed,
struct blame_entry **toosmall,
- struct origin *target,
+ struct blame_origin *target,
struct commit *parent,
- struct origin *porigin,
+ struct blame_origin *porigin,
int opt)
{
struct diff_options diff_opts;
for (i = 0; i < diff_queued_diff.nr; i++) {
struct diff_filepair *p = diff_queued_diff.queue[i];
- struct origin *norigin;
+ struct blame_origin *norigin;
mmfile_t file_p;
struct blame_entry this[3];
norigin = get_origin(parent, p->one->path);
oidcpy(&norigin->blob_oid, &p->one->oid);
norigin->mode = p->one->mode;
- fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
+ fill_origin_blob(&sb->revs->diffopt, norigin, &file_p, &sb->num_read_blob);
if (!file_p.ptr)
continue;
this);
decref_split(this);
}
- origin_decref(norigin);
+ blame_origin_decref(norigin);
}
for (j = 0; j < num_ents; j++) {
struct blame_entry *split = blame_list[j].split;
if (split[1].suspect &&
- blame_copy_score < ent_score(sb, &split[1])) {
+ sb->copy_score < blame_entry_score(sb, &split[1])) {
split_blame(blamed, &unblamedtail, split,
blame_list[j].ent);
} else {
}
free(blame_list);
*unblamedtail = NULL;
- toosmall = filter_small(sb, toosmall, &unblamed, blame_copy_score);
+ toosmall = filter_small(sb, toosmall, &unblamed, sb->copy_score);
} while (unblamed);
target->suspects = reverse_blame(leftover, NULL);
diff_flush(&diff_opts);
* The blobs of origin and porigin exactly match, so everything
* origin is suspected for can be blamed on the parent.
*/
-static void pass_whole_blame(struct scoreboard *sb,
- struct origin *origin, struct origin *porigin)
+static void pass_whole_blame(struct blame_scoreboard *sb,
+ struct blame_origin *origin, struct blame_origin *porigin)
{
struct blame_entry *e, *suspects;
suspects = origin->suspects;
origin->suspects = NULL;
for (e = suspects; e; e = e->next) {
- origin_incref(porigin);
- origin_decref(e->suspect);
+ blame_origin_incref(porigin);
+ blame_origin_decref(e->suspect);
e->suspect = porigin;
}
queue_blames(sb, porigin, suspects);
/* Distribute collected unsorted blames to the respected sorted lists
* in the various origins.
*/
-static void distribute_blame(struct scoreboard *sb, struct blame_entry *blamed)
+static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
{
blamed = blame_sort(blamed, compare_blame_suspect);
while (blamed)
{
- struct origin *porigin = blamed->suspect;
+ struct blame_origin *porigin = blamed->suspect;
struct blame_entry *suspects = NULL;
do {
struct blame_entry *next = blamed->next;
#define MAXSG 16
-static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
+static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, int opt)
{
struct rev_info *revs = sb->revs;
int i, pass, num_sg;
struct commit *commit = origin->commit;
struct commit_list *sg;
- struct origin *sg_buf[MAXSG];
- struct origin *porigin, **sg_origin = sg_buf;
+ struct blame_origin *sg_buf[MAXSG];
+ struct blame_origin *porigin, **sg_origin = sg_buf;
struct blame_entry *toosmall = NULL;
struct blame_entry *blames, **blametail = &blames;
* common cases, then we look for renames in the second pass.
*/
for (pass = 0; pass < 2 - no_whole_file_rename; pass++) {
- struct origin *(*find)(struct commit *, struct origin *);
+ struct blame_origin *(*find)(struct commit *, struct blame_origin *);
find = pass ? find_rename : find_origin;
for (i = 0, sg = first_scapegoat(revs, commit);
continue;
if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) {
pass_whole_blame(sb, origin, porigin);
- origin_decref(porigin);
+ blame_origin_decref(porigin);
goto finish;
}
for (j = same = 0; j < i; j++)
if (!same)
sg_origin[i] = porigin;
else
- origin_decref(porigin);
+ blame_origin_decref(porigin);
}
}
- num_commits++;
+ sb->num_commits++;
for (i = 0, sg = first_scapegoat(revs, commit);
i < num_sg && sg;
sg = sg->next, i++) {
- struct origin *porigin = sg_origin[i];
+ struct blame_origin *porigin = sg_origin[i];
if (!porigin)
continue;
if (!origin->previous) {
- origin_incref(porigin);
+ blame_origin_incref(porigin);
origin->previous = porigin;
}
pass_blame_to_parent(sb, origin, porigin);
* Optionally find moves in parents' files.
*/
if (opt & PICKAXE_BLAME_MOVE) {
- filter_small(sb, &toosmall, &origin->suspects, blame_move_score);
+ filter_small(sb, &toosmall, &origin->suspects, sb->move_score);
if (origin->suspects) {
for (i = 0, sg = first_scapegoat(revs, commit);
i < num_sg && sg;
sg = sg->next, i++) {
- struct origin *porigin = sg_origin[i];
+ struct blame_origin *porigin = sg_origin[i];
if (!porigin)
continue;
find_move_in_parent(sb, &blametail, &toosmall, origin, porigin);
* Optionally find copies from parents' files.
*/
if (opt & PICKAXE_BLAME_COPY) {
- if (blame_copy_score > blame_move_score)
- filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
- else if (blame_copy_score < blame_move_score) {
+ if (sb->copy_score > sb->move_score)
+ filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
+ else if (sb->copy_score < sb->move_score) {
origin->suspects = blame_merge(origin->suspects, toosmall);
toosmall = NULL;
- filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
+ filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
}
if (!origin->suspects)
goto finish;
for (i = 0, sg = first_scapegoat(revs, commit);
i < num_sg && sg;
sg = sg->next, i++) {
- struct origin *porigin = sg_origin[i];
+ struct blame_origin *porigin = sg_origin[i];
find_copy_in_parent(sb, &blametail, &toosmall,
origin, sg->item, porigin, opt);
if (!origin->suspects)
for (i = 0; i < num_sg; i++) {
if (sg_origin[i]) {
drop_origin_blob(sg_origin[i]);
- origin_decref(sg_origin[i]);
+ blame_origin_decref(sg_origin[i]);
}
}
drop_origin_blob(origin);
* To allow LF and other nonportable characters in pathnames,
* they are c-style quoted as needed.
*/
-static void write_filename_info(struct origin *suspect)
+static void write_filename_info(struct blame_origin *suspect)
{
if (suspect->previous) {
- struct origin *prev = suspect->previous;
+ struct blame_origin *prev = suspect->previous;
printf("previous %s ", oid_to_hex(&prev->commit->object.oid));
write_name_quoted(prev->path, stdout, '\n');
}
* the first time each commit appears in the output (unless the
* user has specifically asked for us to repeat).
*/
-static int emit_one_suspect_detail(struct origin *suspect, int repeat)
+static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat)
{
struct commit_info ci;
struct progress_info *pi)
{
if (incremental) {
- struct origin *suspect = ent->suspect;
+ struct blame_origin *suspect = ent->suspect;
printf("%s %d %d %d\n",
oid_to_hex(&suspect->commit->object.oid),
* The main loop -- while we have blobs with lines whose true origin
* is still unknown, pick one blob, and allow its lines to pass blames
* to its parents. */
-static void assign_blame(struct scoreboard *sb, int opt)
+static void assign_blame(struct blame_scoreboard *sb, int opt)
{
struct rev_info *revs = sb->revs;
struct commit *commit = prio_queue_get(&sb->commits);
while (commit) {
struct blame_entry *ent;
- struct origin *suspect = commit->util;
+ struct blame_origin *suspect = commit->util;
/* find one suspect to break down */
while (suspect && !suspect->suspects)
* We will use this suspect later in the loop,
* so hold onto it in the meantime.
*/
- origin_incref(suspect);
+ blame_origin_incref(suspect);
parse_commit(commit);
if (reverse ||
(!(commit->object.flags & UNINTERESTING) &&
break;
}
}
- origin_decref(suspect);
+ blame_origin_decref(suspect);
if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
#define OUTPUT_SHOW_EMAIL 0400
#define OUTPUT_LINE_PORCELAIN 01000
-static void emit_porcelain_details(struct origin *suspect, int repeat)
+static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
{
if (emit_one_suspect_detail(suspect, repeat) ||
(suspect->commit->object.flags & MORE_THAN_ONE_PATH))
write_filename_info(suspect);
}
-static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
+static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
int opt)
{
int repeat = opt & OUTPUT_LINE_PORCELAIN;
int cnt;
const char *cp;
- struct origin *suspect = ent->suspect;
+ struct blame_origin *suspect = ent->suspect;
char hex[GIT_MAX_HEXSZ + 1];
oid_to_hex_r(hex, &suspect->commit->object.oid);
ent->num_lines);
emit_porcelain_details(suspect, repeat);
- cp = nth_line(sb, ent->lno);
+ cp = blame_nth_line(sb, ent->lno);
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
if (cnt) {
putchar('\n');
}
-static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
+static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
{
int cnt;
const char *cp;
- struct origin *suspect = ent->suspect;
+ struct blame_origin *suspect = ent->suspect;
struct commit_info ci;
char hex[GIT_MAX_HEXSZ + 1];
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
get_commit_info(suspect->commit, &ci, 1);
oid_to_hex_r(hex, &suspect->commit->object.oid);
- cp = nth_line(sb, ent->lno);
+ cp = blame_nth_line(sb, ent->lno);
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
commit_info_destroy(&ci);
}
-static void output(struct scoreboard *sb, int option)
+static void output(struct blame_scoreboard *sb, int option)
{
struct blame_entry *ent;
if (option & OUTPUT_PORCELAIN) {
for (ent = sb->ent; ent; ent = ent->next) {
int count = 0;
- struct origin *suspect;
+ struct blame_origin *suspect;
struct commit *commit = ent->suspect->commit;
if (commit->object.flags & MORE_THAN_ONE_PATH)
continue;
* To allow quick access to the contents of nth line in the
* final image, prepare an index in the scoreboard.
*/
-static int prepare_lines(struct scoreboard *sb)
+static int prepare_lines(struct blame_scoreboard *sb)
{
const char *buf = sb->final_buf;
unsigned long len = sb->final_buf_size;
return 0;
}
-static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
+static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
{
const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
auto_abbrev);
* How many columns do we need to show line numbers, authors,
* and filenames?
*/
-static void find_alignment(struct scoreboard *sb, int *option)
+static void find_alignment(struct blame_scoreboard *sb, int *option)
{
int longest_src_lines = 0;
int longest_dst_lines = 0;
int auto_abbrev = DEFAULT_ABBREV;
for (e = sb->ent; e; e = e->next) {
- struct origin *suspect = e->suspect;
+ struct blame_origin *suspect = e->suspect;
int num;
if (compute_auto_abbrev)
num = e->lno + e->num_lines;
if (longest_dst_lines < num)
longest_dst_lines = num;
- if (largest_score < ent_score(sb, e))
- largest_score = ent_score(sb, e);
+ if (largest_score < blame_entry_score(sb, e))
+ largest_score = blame_entry_score(sb, e);
}
max_orig_digits = decimal_width(longest_src_lines);
max_digits = decimal_width(longest_dst_lines);
* For debugging -- origin is refcounted, and this asserts that
* we do not underflow.
*/
-static void sanity_check_refcnt(struct scoreboard *sb)
+static void sanity_check_refcnt(struct blame_scoreboard *sb)
{
int baa = 0;
struct blame_entry *ent;
const char *contents_from)
{
struct commit *commit;
- struct origin *origin;
+ struct blame_origin *origin;
struct commit_list **parent_tail, *parent;
struct object_id head_oid;
struct strbuf buf = STRBUF_INIT;
return found;
}
-static char *prepare_final(struct scoreboard *sb)
+static char *prepare_final(struct blame_scoreboard *sb)
{
const char *name;
sb->final = find_single_final(sb->revs, &name);
return xstrdup_or_null(name);
}
-static const char *dwim_reverse_initial(struct scoreboard *sb)
+static const char *dwim_reverse_initial(struct blame_scoreboard *sb)
{
/*
* DWIM "git blame --reverse ONE -- PATH" as
return sb->revs->pending.objects[0].name;
}
-static char *prepare_initial(struct scoreboard *sb)
+static char *prepare_initial(struct blame_scoreboard *sb)
{
int i;
const char *final_commit_name = NULL;
{
struct rev_info revs;
const char *path;
- struct scoreboard sb;
- struct origin *o;
+ struct blame_scoreboard sb;
+ struct blame_origin *o;
struct blame_entry *ent = NULL;
long dashdash_pos, lno;
char *final_commit_name = NULL;
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
PICKAXE_BLAME_COPY_HARDER);
- if (!blame_move_score)
- blame_move_score = BLAME_DEFAULT_MOVE_SCORE;
- if (!blame_copy_score)
- blame_copy_score = BLAME_DEFAULT_COPY_SCORE;
-
/*
* We have collected options unknown to us in argv[1..unk]
* which are to be passed to revision machinery if we are
revs.disable_stdin = 1;
setup_revisions(argc, argv, &revs, NULL);
memset(&sb, 0, sizeof(sb));
+ sb.move_score = BLAME_DEFAULT_MOVE_SCORE;
+ sb.copy_score = BLAME_DEFAULT_COPY_SCORE;
sb.revs = &revs;
+ sb.contents_from = contents_from;
if (!reverse) {
final_commit_name = prepare_final(&sb);
sb.commits.compare = compare_commits_by_commit_date;
oid_to_hex(&o->blob_oid),
path);
}
- num_read_blob++;
+ sb.num_read_blob++;
lno = prepare_lines(&sb);
if (lno && !range_list.nr)
ent->suspect = o;
ent->s_lno = bottom;
ent->next = next;
- origin_incref(o);
+ blame_origin_incref(o);
}
o->suspects = ent;
prio_queue_put(&sb.commits, o->commit);
- origin_decref(o);
+ blame_origin_decref(o);
range_set_release(&ranges);
string_list_clear(&range_list, 0);
sb.ent = NULL;
sb.path = path;
+ if (blame_move_score)
+ sb.move_score = blame_move_score;
+ if (blame_copy_score)
+ sb.copy_score = blame_copy_score;
+
read_mailmap(&mailmap, NULL);
assign_blame(&sb, opt);
sb.ent = blame_sort(sb.ent, compare_blame_final);
- coalesce(&sb);
+ blame_coalesce(&sb);
if (!(output_option & OUTPUT_PORCELAIN))
find_alignment(&sb, &output_option);
}
if (show_stats) {
- printf("num read blob: %d\n", num_read_blob);
- printf("num get patch: %d\n", num_get_patch);
- printf("num commits: %d\n", num_commits);
+ printf("num read blob: %d\n", sb.num_read_blob);
+ printf("num get patch: %d\n", sb.num_get_patch);
+ printf("num commits: %d\n", sb.num_commits);
}
return 0;
}