diff --git a/builtin-pickaxe.c b/builtin-pickaxe.c index 82868328ac..32dc3932ed 100644 --- a/builtin-pickaxe.c +++ b/builtin-pickaxe.c @@ -211,7 +211,6 @@ static struct origin *find_origin(struct scoreboard *sb, { struct origin *porigin = NULL; struct diff_options diff_opts; - int i; const char *paths[2]; /* See if the origin->path is different between parent @@ -260,10 +259,17 @@ static struct origin *find_origin(struct scoreboard *sb, } } diff_flush(&diff_opts); - if (porigin) - return porigin; + return porigin; +} - /* Otherwise we would look for a rename */ +static struct origin *find_rename(struct scoreboard *sb, + struct commit *parent, + struct origin *origin) +{ + struct origin *porigin = NULL; + struct diff_options diff_opts; + int i; + const char *paths[2]; diff_setup(&diff_opts); diff_opts.recursive = 1; @@ -875,34 +881,46 @@ static int find_copy_in_parent(struct scoreboard *sb, static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) { - int i; + int i, pass; struct commit *commit = origin->commit; struct commit_list *parent; struct origin *parent_origin[MAXPARENT], *porigin; memset(parent_origin, 0, sizeof(parent_origin)); - for (i = 0, parent = commit->parents; - i < MAXPARENT && parent; - parent = parent->next, i++) { - struct commit *p = parent->item; - if (parse_commit(p)) - continue; - porigin = find_origin(sb, parent->item, origin); - if (!porigin) - continue; - if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) { - struct blame_entry *e; - for (e = sb->ent; e; e = e->next) - if (e->suspect == origin) { - origin_incref(porigin); - origin_decref(e->suspect); - e->suspect = porigin; - } - origin_decref(porigin); - goto finish; + /* 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++) { + struct origin *(*find)(struct scoreboard *, + 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; + + if (parent_origin[i]) + continue; + if (parse_commit(p)) + continue; + porigin = find(sb, parent->item, origin); + if (!porigin) + continue; + if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) { + struct blame_entry *e; + for (e = sb->ent; e; e = e->next) + if (e->suspect == origin) { + origin_incref(porigin); + origin_decref(e->suspect); + e->suspect = porigin; + } + origin_decref(porigin); + goto finish; + } + parent_origin[i] = porigin; } - parent_origin[i] = porigin; } for (i = 0, parent = commit->parents;