Signed-off-by: Jeff Smith <[email protected]>
---
builtin/blame.c | 149 +++++++++++++++++++++++++++++++++++---------------------
1 file changed, 93 insertions(+), 56 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index c873cc2..dc7600c 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -62,11 +62,6 @@ static struct string_list mailmap = STRING_LIST_INIT_NODUP;
#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
@@ -91,7 +86,7 @@ struct progress_info {
};
static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
- xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
+ xdl_emit_hunk_consume_func_t hunk_func, void *cb_data,
int xdl_opts)
{
xpparam_t xpp = {0};
xdemitconf_t xecfg = {0};
@@ -108,13 +103,13 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
* diff machinery
*/
static void fill_origin_blob(struct diff_options *opt,
- struct origin *o, mmfile_t *file)
+ struct 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))
;
@@ -265,9 +260,36 @@ struct scoreboard {
/* look-up a line in the final buffer */
int num_lines;
int *lineno;
+
+ /*
+ * blame for a blame_entry with score lower than these thresholds
+ * is not passed to the parent using move/copy logic.
+ */
+ unsigned blame_move_score;
+ unsigned blame_copy_score;
+
+ /* stats */
+ int num_read_blob;
+ int num_get_patch;
+ int num_commits;
+
+ /* options */
+ int show_root;
+ int reverse;
+ int xdl_opts;
+ int no_whole_file_rename;
+
+ /* callbacks */
+ void(*sanity_check)(struct scoreboard *);
+ void(*found_guilty_entry)(struct blame_entry *, void *);
+
+ void *found_guilty_entry_data;
};
-static void sanity_check_refcnt(struct scoreboard *);
+static void blame_sort_final(struct scoreboard *sb)
+{
+ sb->ent = blame_sort(sb->ent, compare_blame_final);
+}
/*
* If two blame entries that are next to each other came from
@@ -290,8 +312,8 @@ static void coalesce(struct scoreboard *sb)
}
}
- if (DEBUG) /* sanity */
- sanity_check_refcnt(sb);
+ if (sb->sanity_check) /* sanity */
+ sb->sanity_check(sb);
}
/*
@@ -787,11 +809,11 @@ static void pass_blame_to_parent(struct scoreboard *sb,
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))
+ if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts))
die("unable to generate diff (%s -> %s)",
oid_to_hex(&parent->commit->object.oid),
oid_to_hex(&target->commit->object.oid));
@@ -940,7 +962,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
* file_p partially may match that image.
*/
memset(split, 0, sizeof(struct blame_entry [3]));
- if (diff_hunks(file_p, &file_o, handle_split_cb, &d))
+ if (diff_hunks(file_p, &file_o, handle_split_cb, &d, sb->xdl_opts))
die("unable to generate diff (%s)",
oid_to_hex(&parent->commit->object.oid));
/* remainder, if any, all match the preimage */
@@ -993,7 +1015,7 @@ static void find_move_in_parent(struct scoreboard *sb,
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;
@@ -1009,7 +1031,7 @@ static void find_move_in_parent(struct scoreboard *sb,
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->blame_move_score < ent_score(sb, &split[1])) {
split_blame(blamed, &unblamedtail, split, e);
} else {
e->next = leftover;
@@ -1018,7 +1040,7 @@ static void find_move_in_parent(struct scoreboard *sb,
decref_split(split);
}
*unblamedtail = NULL;
- toosmall = filter_small(sb, toosmall, &unblamed,
blame_move_score);
+ toosmall = filter_small(sb, toosmall, &unblamed,
sb->blame_move_score);
} while (unblamed);
target->suspects = reverse_blame(leftover, NULL);
}
@@ -1122,7 +1144,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
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;
@@ -1139,7 +1161,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
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->blame_copy_score < ent_score(sb, &split[1])) {
split_blame(blamed, &unblamedtail, split,
blame_list[j].ent);
} else {
@@ -1150,7 +1172,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
}
free(blame_list);
*unblamedtail = NULL;
- toosmall = filter_small(sb, toosmall, &unblamed,
blame_copy_score);
+ toosmall = filter_small(sb, toosmall, &unblamed,
sb->blame_copy_score);
} while (unblamed);
target->suspects = reverse_blame(leftover, NULL);
diff_flush(&diff_opts);
@@ -1186,7 +1208,8 @@ static void pass_whole_blame(struct scoreboard *sb,
* "parent" (and "porigin"), but what we mean is to find scapegoat to
* exonerate ourselves.
*/
-static struct commit_list *first_scapegoat(struct rev_info *revs, struct
commit *commit)
+static struct commit_list *first_scapegoat(struct rev_info *revs, struct
commit *commit,
+ int reverse)
{
if (!reverse) {
if (revs->first_parent_only &&
@@ -1200,9 +1223,9 @@ static struct commit_list *first_scapegoat(struct
rev_info *revs, struct commit
return lookup_decoration(&revs->children, &commit->object);
}
-static int num_scapegoats(struct rev_info *revs, struct commit *commit)
+static int num_scapegoats(struct rev_info *revs, struct commit *commit, int
reverse)
{
- struct commit_list *l = first_scapegoat(revs, commit);
+ struct commit_list *l = first_scapegoat(revs, commit, reverse);
return commit_list_count(l);
}
@@ -1240,7 +1263,7 @@ static void pass_blame(struct scoreboard *sb, struct
origin *origin, int opt)
struct blame_entry *toosmall = NULL;
struct blame_entry *blames, **blametail = &blames;
- num_sg = num_scapegoats(revs, commit);
+ num_sg = num_scapegoats(revs, commit, sb->reverse);
if (!num_sg)
goto finish;
else if (num_sg < ARRAY_SIZE(sg_buf))
@@ -1252,12 +1275,12 @@ static void pass_blame(struct scoreboard *sb, struct
origin *origin, int opt)
* 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 - no_whole_file_rename; pass++) {
+ for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) {
struct origin *(*find)(struct scoreboard *,
struct commit *, struct origin *);
find = pass ? find_rename : find_origin;
- for (i = 0, sg = first_scapegoat(revs, commit);
+ for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
i < num_sg && sg;
sg = sg->next, i++) {
struct commit *p = sg->item;
@@ -1288,8 +1311,8 @@ static void pass_blame(struct scoreboard *sb, struct
origin *origin, int opt)
}
}
- num_commits++;
- for (i = 0, sg = first_scapegoat(revs, commit);
+ sb->num_commits++;
+ for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
@@ -1308,9 +1331,9 @@ static void pass_blame(struct scoreboard *sb, struct
origin *origin, int opt)
* 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->blame_move_score);
if (origin->suspects) {
- for (i = 0, sg = first_scapegoat(revs, commit);
+ for (i = 0, sg = first_scapegoat(revs, commit,
sb->reverse);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
@@ -1327,17 +1350,17 @@ static void pass_blame(struct scoreboard *sb, struct
origin *origin, int opt)
* 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->blame_copy_score > sb->blame_move_score)
+ filter_small(sb, &toosmall, &origin->suspects,
sb->blame_copy_score);
+ else if (sb->blame_copy_score < sb->blame_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->blame_copy_score);
}
if (!origin->suspects)
goto finish;
- for (i = 0, sg = first_scapegoat(revs, commit);
+ for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
i < num_sg && sg;
sg = sg->next, i++) {
struct origin *porigin = sg_origin[i];
@@ -1566,9 +1589,10 @@ static int emit_one_suspect_detail(struct origin
*suspect, int repeat)
* The blame_entry is found to be guilty for the range.
* Show it in incremental output.
*/
-static void found_guilty_entry(struct blame_entry *ent,
- struct progress_info *pi)
+static void found_guilty_entry(struct blame_entry *ent, void *data)
{
+ struct progress_info *pi = (struct progress_info *)data;
+
if (incremental) {
struct origin *suspect = ent->suspect;
@@ -1591,11 +1615,6 @@ static void assign_blame(struct scoreboard *sb, int opt)
{
struct rev_info *revs = sb->revs;
struct commit *commit = prio_queue_get(&sb->commits);
- struct progress_info pi = { NULL, 0 };
-
- if (show_progress)
- pi.progress = start_progress_delay(_("Blaming lines"),
- sb->num_lines, 50, 1);
while (commit) {
struct blame_entry *ent;
@@ -1618,7 +1637,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
*/
origin_incref(suspect);
parse_commit(commit);
- if (reverse ||
+ if (sb->reverse ||
(!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age)))
pass_blame(sb, suspect, opt);
@@ -1628,7 +1647,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
mark_parents_uninteresting(commit);
}
/* treat root commit as boundary */
- if (!commit->parents && !show_root)
+ if (!commit->parents && !sb->show_root)
commit->object.flags |= UNINTERESTING;
/* Take responsibility for the remaining entries */
@@ -1637,7 +1656,8 @@ static void assign_blame(struct scoreboard *sb, int opt)
suspect->guilty = 1;
for (;;) {
struct blame_entry *next = ent->next;
- found_guilty_entry(ent, &pi);
+ if (sb->found_guilty_entry)
+ sb->found_guilty_entry(ent,
sb->found_guilty_entry_data);
if (next) {
ent = next;
continue;
@@ -1650,11 +1670,9 @@ static void assign_blame(struct scoreboard *sb, int opt)
}
origin_decref(suspect);
- if (DEBUG) /* sanity */
- sanity_check_refcnt(sb);
+ if (sb->sanity_check) /* sanity */
+ sb->sanity_check(sb);
}
-
- stop_progress(&pi.progress);
}
static const char *format_time(unsigned long time, const char *tz_str,
@@ -2187,6 +2205,7 @@ int cmd_blame(int argc, const char **argv, const char
*prefix)
char *final_commit_name = NULL;
enum object_type type;
struct commit *final_commit = NULL;
+ struct progress_info pi = { NULL, 0 };
struct string_list range_list = STRING_LIST_INIT_NODUP;
int output_option = 0, opt = 0;
@@ -2476,7 +2495,7 @@ int cmd_blame(int argc, const char **argv, const char
*prefix)
oid_to_hex(&o->blob_oid),
path);
}
- num_read_blob++;
+ sb.num_read_blob++;
lno = prepare_lines(&sb);
if (lno && !range_list.nr)
@@ -2529,10 +2548,28 @@ int cmd_blame(int argc, const char **argv, const char
*prefix)
sb.ent = NULL;
sb.path = path;
+ sb.blame_move_score = blame_move_score;
+ sb.blame_copy_score = blame_copy_score;
+
+ sb.sanity_check = DEBUG ? &sanity_check_refcnt : NULL;
+
+ sb.show_root = show_root;
+ sb.reverse = reverse;
+ sb.xdl_opts = xdl_opts;
+ sb.no_whole_file_rename = no_whole_file_rename;
+
read_mailmap(&mailmap, NULL);
+ sb.found_guilty_entry = &found_guilty_entry;
+ sb.found_guilty_entry_data = π
+ if (show_progress)
+ pi.progress = start_progress_delay(_("Blaming lines"),
+ sb.num_lines, 50, 1);
+
assign_blame(&sb, opt);
+ stop_progress(&pi.progress);
+
if (!incremental)
setup_pager();
@@ -2541,7 +2578,7 @@ int cmd_blame(int argc, const char **argv, const char
*prefix)
if (incremental)
return 0;
- sb.ent = blame_sort(sb.ent, compare_blame_final);
+ blame_sort_final(&sb);
coalesce(&sb);
@@ -2557,9 +2594,9 @@ int cmd_blame(int argc, const char **argv, const char
*prefix)
}
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;
}
--
2.9.3