git-pickaxe: split find_origin() into find_rename() and find_origin().
authorJunio C Hamano <junkio@cox.net>
Tue, 31 Oct 2006 01:17:41 +0000 (17:17 -0800)
committerJunio C Hamano <junkio@cox.net>
Tue, 31 Oct 2006 01:17:41 +0000 (17:17 -0800)
When a merge adds a new file from the second parent, the
earlier code tried to find renames in the first parent before
noticing that the vertion from the second parent was added
without modification.

Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-pickaxe.c

index 82868328ac1fb6b951e2124db7a8563365fe34e3..32dc3932edfa6c007d75b5369917e1fd744ca317 100644 (file)
@@ -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;