@ -1191,18 +1191,45 @@ static void pass_whole_blame(struct scoreboard *sb,
@@ -1191,18 +1191,45 @@ static void pass_whole_blame(struct scoreboard *sb,
}
}
#define MAXPARENT 16
/*
* We pass blame from the current commit to its parents. We keep saying
* "parent" (and "porigin"), but what we mean is to find scapegoat to
* exonerate ourselves.
*/
static struct commit_list *first_scapegoat(struct commit *commit)
{
return commit->parents;
}
static int num_scapegoats(struct commit *commit)
{
int cnt;
struct commit_list *l = first_scapegoat(commit);
for (cnt = 0; l; l = l->next)
cnt++;
return cnt;
}
#define MAXSG 16
static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
{
int i, pass;
int i, pass, num_sg;
struct commit *commit = origin->commit;
struct commit_list *parent;
struct origin *parent_origin[MAXPARENT], *porigin;
memset(parent_origin, 0, sizeof(parent_origin));
struct commit_list *sg;
struct origin *sg_buf[MAXSG];
struct origin *porigin, **sg_origin = sg_buf;
num_sg = num_scapegoats(commit);
if (!num_sg)
goto finish;
else if (num_sg < ARRAY_SIZE(sg_buf))
memset(sg_buf, 0, sizeof(sg_buf));
else
sg_origin = xcalloc(num_sg, sizeof(*sg_origin));
/* The first pass looks for unrenamed path to optimize for
/*
* The first pass looks for unrenamed path to optimize for
* common cases, then we look for renames in the second pass.
*/
for (pass = 0; pass < 2; pass++) {
@ -1210,13 +1237,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
@@ -1210,13 +1237,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
struct commit *, struct origin *);
find = pass ? find_rename : find_origin;
for (i = 0, parent = commit->parents;
i < MAXPARENT && parent;
parent = parent->next, i++) {
struct commit *p = parent->item;
for (i = 0, sg = first_scapegoat(commit);
i < num_sg && sg;
sg = sg->next, i++) {
struct commit *p = sg->item;
int j, same;
if (parent_origin[i])
if (sg_origin[i])
continue;
if (parse_commit(p))
continue;
@ -1229,24 +1256,24 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
@@ -1229,24 +1256,24 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
goto finish;
}
for (j = same = 0; j < i; j++)
if (parent_origin[j] &&
!hashcmp(parent_origin[j]->blob_sha1,
if (sg_origin[j] &&
!hashcmp(sg_origin[j]->blob_sha1,
porigin->blob_sha1)) {
same = 1;
break;
}
if (!same)
parent_origin[i] = porigin;
sg_origin[i] = porigin;
else
origin_decref(porigin);
}
}
num_commits++;
for (i = 0, parent = commit->parents;
i < MAXPARENT && parent;
parent = parent->next, i++) {
struct origin *porigin = parent_origin[i];
for (i = 0, sg = first_scapegoat(commit);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
if (!porigin)
continue;
if (pass_blame_to_parent(sb, origin, porigin))
@ -1257,10 +1284,10 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
@@ -1257,10 +1284,10 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
* Optionally find moves in parents' files.
*/
if (opt & PICKAXE_BLAME_MOVE)
for (i = 0, parent = commit->parents;
i < MAXPARENT && parent;
parent = parent->next, i++) {
struct origin *porigin = parent_origin[i];
for (i = 0, sg = first_scapegoat(commit);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
if (!porigin)
continue;
if (find_move_in_parent(sb, origin, porigin))
@ -1271,23 +1298,25 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
@@ -1271,23 +1298,25 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
* Optionally find copies from parents' files.
*/
if (opt & PICKAXE_BLAME_COPY)
for (i = 0, parent = commit->parents;
i < MAXPARENT && parent;
parent = parent->next, i++) {
struct origin *porigin = parent_origin[i];
if (find_copy_in_parent(sb, origin, parent->item,
for (i = 0, sg = first_scapegoat(commit);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
if (find_copy_in_parent(sb, origin, sg->item,
porigin, opt))
goto finish;
}
finish:
for (i = 0; i < MAXPARENT; i++) {
if (parent_origin[i]) {
drop_origin_blob(parent_origin[i]);
origin_decref(parent_origin[i]);
for (i = 0; i < num_sg; i++) {
if (sg_origin[i]) {
drop_origin_blob(sg_origin[i]);
origin_decref(sg_origin[i]);
}
}
drop_origin_blob(origin);
if (sg_buf != sg_origin)
free(sg_origin);
}
/*