|
|
@ -153,6 +153,10 @@ struct blame_entry { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
char guilty; |
|
|
|
char guilty; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* true if the entry has been scanned for copies in the current parent |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
char scanned; |
|
|
|
|
|
|
|
|
|
|
|
/* the line number of the first line of this group in the |
|
|
|
/* the line number of the first line of this group in the |
|
|
|
* suspect's file; internally all line numbers are 0 based. |
|
|
|
* suspect's file; internally all line numbers are 0 based. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -1008,7 +1012,8 @@ static int find_move_in_parent(struct scoreboard *sb, |
|
|
|
while (made_progress) { |
|
|
|
while (made_progress) { |
|
|
|
made_progress = 0; |
|
|
|
made_progress = 0; |
|
|
|
for (e = sb->ent; e; e = e->next) { |
|
|
|
for (e = sb->ent; e; e = e->next) { |
|
|
|
if (e->guilty || !same_suspect(e->suspect, target)) |
|
|
|
if (e->guilty || !same_suspect(e->suspect, target) || |
|
|
|
|
|
|
|
ent_score(sb, e) < blame_move_score) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
find_copy_in_blob(sb, e, parent, split, &file_p); |
|
|
|
find_copy_in_blob(sb, e, parent, split, &file_p); |
|
|
|
if (split[1].suspect && |
|
|
|
if (split[1].suspect && |
|
|
@ -1033,6 +1038,7 @@ struct blame_list { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static struct blame_list *setup_blame_list(struct scoreboard *sb, |
|
|
|
static struct blame_list *setup_blame_list(struct scoreboard *sb, |
|
|
|
struct origin *target, |
|
|
|
struct origin *target, |
|
|
|
|
|
|
|
int min_score, |
|
|
|
int *num_ents_p) |
|
|
|
int *num_ents_p) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct blame_entry *e; |
|
|
|
struct blame_entry *e; |
|
|
@ -1040,18 +1046,32 @@ static struct blame_list *setup_blame_list(struct scoreboard *sb, |
|
|
|
struct blame_list *blame_list = NULL; |
|
|
|
struct blame_list *blame_list = NULL; |
|
|
|
|
|
|
|
|
|
|
|
for (e = sb->ent, num_ents = 0; e; e = e->next) |
|
|
|
for (e = sb->ent, num_ents = 0; e; e = e->next) |
|
|
|
if (!e->guilty && same_suspect(e->suspect, target)) |
|
|
|
if (!e->scanned && !e->guilty && |
|
|
|
|
|
|
|
same_suspect(e->suspect, target) && |
|
|
|
|
|
|
|
min_score < ent_score(sb, e)) |
|
|
|
num_ents++; |
|
|
|
num_ents++; |
|
|
|
if (num_ents) { |
|
|
|
if (num_ents) { |
|
|
|
blame_list = xcalloc(num_ents, sizeof(struct blame_list)); |
|
|
|
blame_list = xcalloc(num_ents, sizeof(struct blame_list)); |
|
|
|
for (e = sb->ent, i = 0; e; e = e->next) |
|
|
|
for (e = sb->ent, i = 0; e; e = e->next) |
|
|
|
if (!e->guilty && same_suspect(e->suspect, target)) |
|
|
|
if (!e->scanned && !e->guilty && |
|
|
|
|
|
|
|
same_suspect(e->suspect, target) && |
|
|
|
|
|
|
|
min_score < ent_score(sb, e)) |
|
|
|
blame_list[i++].ent = e; |
|
|
|
blame_list[i++].ent = e; |
|
|
|
} |
|
|
|
} |
|
|
|
*num_ents_p = num_ents; |
|
|
|
*num_ents_p = num_ents; |
|
|
|
return blame_list; |
|
|
|
return blame_list; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Reset the scanned status on all entries. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static void reset_scanned_flag(struct scoreboard *sb) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct blame_entry *e; |
|
|
|
|
|
|
|
for (e = sb->ent; e; e = e->next) |
|
|
|
|
|
|
|
e->scanned = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* For lines target is suspected for, see if we can find code movement |
|
|
|
* For lines target is suspected for, see if we can find code movement |
|
|
|
* across file boundary from the parent commit. porigin is the path |
|
|
|
* across file boundary from the parent commit. porigin is the path |
|
|
@ -1070,7 +1090,7 @@ static int find_copy_in_parent(struct scoreboard *sb, |
|
|
|
struct blame_list *blame_list; |
|
|
|
struct blame_list *blame_list; |
|
|
|
int num_ents; |
|
|
|
int num_ents; |
|
|
|
|
|
|
|
|
|
|
|
blame_list = setup_blame_list(sb, target, &num_ents); |
|
|
|
blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents); |
|
|
|
if (!blame_list) |
|
|
|
if (!blame_list) |
|
|
|
return 1; /* nothing remains for this target */ |
|
|
|
return 1; /* nothing remains for this target */ |
|
|
|
|
|
|
|
|
|
|
@ -1144,18 +1164,21 @@ static int find_copy_in_parent(struct scoreboard *sb, |
|
|
|
split_blame(sb, split, blame_list[j].ent); |
|
|
|
split_blame(sb, split, blame_list[j].ent); |
|
|
|
made_progress = 1; |
|
|
|
made_progress = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
blame_list[j].ent->scanned = 1; |
|
|
|
decref_split(split); |
|
|
|
decref_split(split); |
|
|
|
} |
|
|
|
} |
|
|
|
free(blame_list); |
|
|
|
free(blame_list); |
|
|
|
|
|
|
|
|
|
|
|
if (!made_progress) |
|
|
|
if (!made_progress) |
|
|
|
break; |
|
|
|
break; |
|
|
|
blame_list = setup_blame_list(sb, target, &num_ents); |
|
|
|
blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents); |
|
|
|
if (!blame_list) { |
|
|
|
if (!blame_list) { |
|
|
|
retval = 1; |
|
|
|
retval = 1; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
reset_scanned_flag(sb); |
|
|
|
diff_flush(&diff_opts); |
|
|
|
diff_flush(&diff_opts); |
|
|
|
diff_tree_release_paths(&diff_opts); |
|
|
|
diff_tree_release_paths(&diff_opts); |
|
|
|
return retval; |
|
|
|
return retval; |
|
|
|