int *lineno;
};
+static int cmp_suspect(struct origin *a, struct origin *b)
+{
+ int cmp = hashcmp(a->commit->object.sha1, b->commit->object.sha1);
+ if (cmp)
+ return cmp;
+ return strcmp(a->path, b->path);
+}
+
static void coalesce(struct scoreboard *sb)
{
struct blame_entry *ent, *next;
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
- if (ent->suspect == next->suspect &&
+ if (!cmp_suspect(ent->suspect, next->suspect) &&
ent->guilty == next->guilty &&
ent->s_lno + ent->num_lines == next->s_lno) {
ent->num_lines += next->num_lines;
if (ent->next)
ent->next->prev = ent;
free(next);
+ ent->score = 0;
next = ent; /* again */
}
}
int last_in_target = -1;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || e->suspect != target)
+ if (e->guilty || cmp_suspect(e->suspect, target))
continue;
if (last_in_target < e->s_lno + e->num_lines)
last_in_target = e->s_lno + e->num_lines;
struct blame_entry *e;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || e->suspect != target)
+ if (e->guilty || cmp_suspect(e->suspect, target))
continue;
if (same <= e->s_lno)
continue;
struct origin *parent)
{
int last_in_target;
- struct blame_entry *ent, split[3];
+ struct blame_entry *e, split[3];
mmfile_t file_p;
char type[10];
char *blob_p;
return 0;
}
- for (ent = sb->ent; ent; ent = ent->next) {
- if (ent->suspect != target || ent->guilty)
+ for (e = sb->ent; e; e = e->next) {
+ if (e->guilty || cmp_suspect(e->suspect, target))
continue;
- find_copy_in_blob(sb, ent, parent, split, &file_p);
+ find_copy_in_blob(sb, e, parent, split, &file_p);
if (split[1].suspect &&
blame_move_score < ent_score(sb, &split[1]))
- split_blame(sb, split, ent);
+ split_blame(sb, split, e);
}
free(blob_p);
return 0;
{
struct diff_options diff_opts;
const char *paths[1];
- struct blame_entry *ent;
+ struct blame_entry *e;
int i;
if (find_last_in_target(sb, target) < 0)
"", &diff_opts);
diffcore_std(&diff_opts);
- for (ent = sb->ent; ent; ent = ent->next) {
+ for (e = sb->ent; e; e = e->next) {
struct blame_entry split[3];
- if (ent->suspect != target || ent->guilty)
+ if (e->guilty || cmp_suspect(e->suspect, target))
continue;
memset(split, 0, sizeof(split));
free(blob);
continue;
}
- find_copy_in_blob(sb, ent, norigin, this, &file_p);
+ find_copy_in_blob(sb, e, norigin, this, &file_p);
copy_split_if_better(sb, split, this);
}
if (split[1].suspect &&
blame_copy_score < ent_score(sb, &split[1]))
- split_blame(sb, split, ent);
+ split_blame(sb, split, e);
}
diff_flush(&diff_opts);
for (e = sb->ent; e; e = e->next)
if (e->suspect == origin)
e->suspect = porigin;
- /* now everything blamed for origin is blamed for
- * porigin, we do not need to keep it anymore.
- * Do not free porigin (or the ones we got from
- * earlier round); they may still be used elsewhere.
- */
- free_origin(origin);
return;
}
parent_origin[i] = porigin;
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
- if (ent->suspect == suspect)
+ if (!cmp_suspect(ent->suspect, suspect))
ent->guilty = 1;
+
+ coalesce(sb);
}
}