diff options
Diffstat (limited to 'match-trees.c')
-rw-r--r-- | match-trees.c | 136 |
1 files changed, 72 insertions, 64 deletions
diff --git a/match-trees.c b/match-trees.c index 1ce0954a3e..37653308d3 100644 --- a/match-trees.c +++ b/match-trees.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree.h" #include "tree-walk.h" +#include "object-store.h" static int score_missing(unsigned mode, const char *path) { @@ -48,17 +49,17 @@ static int score_matches(unsigned mode1, unsigned mode2, const char *path) } static void *fill_tree_desc_strict(struct tree_desc *desc, - const unsigned char *hash) + const struct object_id *hash) { void *buffer; enum object_type type; unsigned long size; - buffer = read_sha1_file(hash, &type, &size); + buffer = read_object_file(hash, &type, &size); if (!buffer) - die("unable to read tree (%s)", sha1_to_hex(hash)); + die("unable to read tree (%s)", oid_to_hex(hash)); if (type != OBJ_TREE) - die("%s is not a tree", sha1_to_hex(hash)); + die("%s is not a tree", oid_to_hex(hash)); init_tree_desc(desc, buffer, size); return buffer; } @@ -73,7 +74,7 @@ static int base_name_entries_compare(const struct name_entry *a, /* * Inspect two trees, and give a score that tells how similar they are. */ -static int score_trees(const unsigned char *hash1, const unsigned char *hash2) +static int score_trees(const struct object_id *hash1, const struct object_id *hash2) { struct tree_desc one; struct tree_desc two; @@ -82,34 +83,43 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2) int score = 0; for (;;) { - struct name_entry e1, e2; - int got_entry_from_one = tree_entry(&one, &e1); - int got_entry_from_two = tree_entry(&two, &e2); int cmp; - if (got_entry_from_one && got_entry_from_two) - cmp = base_name_entries_compare(&e1, &e2); - else if (got_entry_from_one) + if (one.size && two.size) + cmp = base_name_entries_compare(&one.entry, &two.entry); + else if (one.size) /* two lacks this entry */ cmp = -1; - else if (got_entry_from_two) + else if (two.size) /* two has more entries */ cmp = 1; else break; - if (cmp < 0) + if (cmp < 0) { /* path1 does not appear in two */ - score += score_missing(e1.mode, e1.path); - else if (cmp > 0) + score += score_missing(one.entry.mode, one.entry.path); + update_tree_entry(&one); + } else if (cmp > 0) { /* path2 does not appear in one */ - score += score_missing(e2.mode, e2.path); - else if (hashcmp(e1.sha1, e2.sha1)) - /* they are different */ - score += score_differs(e1.mode, e2.mode, e1.path); - else - /* same subtree or blob */ - score += score_matches(e1.mode, e2.mode, e1.path); + score += score_missing(two.entry.mode, two.entry.path); + update_tree_entry(&two); + } else { + /* path appears in both */ + if (oidcmp(one.entry.oid, two.entry.oid)) { + /* they are different */ + score += score_differs(one.entry.mode, + two.entry.mode, + one.entry.path); + } else { + /* same subtree or blob */ + score += score_matches(one.entry.mode, + two.entry.mode, + one.entry.path); + } + update_tree_entry(&one); + update_tree_entry(&two); + } } free(one_buf); free(two_buf); @@ -119,8 +129,8 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2) /* * Match one itself and its subtrees with two and pick the best match. */ -static void match_trees(const unsigned char *hash1, - const unsigned char *hash2, +static void match_trees(const struct object_id *hash1, + const struct object_id *hash2, int *best_score, char **best_match, const char *base, @@ -131,7 +141,7 @@ static void match_trees(const unsigned char *hash1, while (one.size) { const char *path; - const unsigned char *elem; + const struct object_id *elem; unsigned mode; int score; @@ -158,22 +168,20 @@ static void match_trees(const unsigned char *hash1, } /* - * A tree "hash1" has a subdirectory at "prefix". Come up with a - * tree object by replacing it with another tree "hash2". + * A tree "oid1" has a subdirectory at "prefix". Come up with a tree object by + * replacing it with another tree "oid2". */ -static int splice_tree(const unsigned char *hash1, - const char *prefix, - const unsigned char *hash2, - unsigned char *result) +static int splice_tree(const struct object_id *oid1, const char *prefix, + const struct object_id *oid2, struct object_id *result) { char *subpath; int toplen; char *buf; unsigned long sz; struct tree_desc desc; - unsigned char *rewrite_here; - const unsigned char *rewrite_with; - unsigned char subtree[20]; + struct object_id *rewrite_here; + const struct object_id *rewrite_with; + struct object_id subtree; enum object_type type; int status; @@ -182,41 +190,41 @@ static int splice_tree(const unsigned char *hash1, if (*subpath) subpath++; - buf = read_sha1_file(hash1, &type, &sz); + buf = read_object_file(oid1, &type, &sz); if (!buf) - die("cannot read tree %s", sha1_to_hex(hash1)); + die("cannot read tree %s", oid_to_hex(oid1)); init_tree_desc(&desc, buf, sz); rewrite_here = NULL; while (desc.size) { const char *name; unsigned mode; - const unsigned char *sha1; + const struct object_id *oid; - sha1 = tree_entry_extract(&desc, &name, &mode); + oid = tree_entry_extract(&desc, &name, &mode); if (strlen(name) == toplen && !memcmp(name, prefix, toplen)) { if (!S_ISDIR(mode)) - die("entry %s in tree %s is not a tree", - name, sha1_to_hex(hash1)); - rewrite_here = (unsigned char *) sha1; + die("entry %s in tree %s is not a tree", name, + oid_to_hex(oid1)); + rewrite_here = (struct object_id *)oid; break; } update_tree_entry(&desc); } if (!rewrite_here) - die("entry %.*s not found in tree %s", - toplen, prefix, sha1_to_hex(hash1)); + die("entry %.*s not found in tree %s", toplen, prefix, + oid_to_hex(oid1)); if (*subpath) { - status = splice_tree(rewrite_here, subpath, hash2, subtree); + status = splice_tree(rewrite_here, subpath, oid2, &subtree); if (status) return status; - rewrite_with = subtree; + rewrite_with = &subtree; + } else { + rewrite_with = oid2; } - else - rewrite_with = hash2; - hashcpy(rewrite_here, rewrite_with); - status = write_sha1_file(buf, sz, tree_type, result); + oidcpy(rewrite_here, rewrite_with); + status = write_object_file(buf, sz, tree_type, result); free(buf); return status; } @@ -229,9 +237,9 @@ static int splice_tree(const unsigned char *hash1, * other hand, it could cover tree one and we might need to pick a * subtree of it. */ -void shift_tree(const unsigned char *hash1, - const unsigned char *hash2, - unsigned char *shifted, +void shift_tree(const struct object_id *hash1, + const struct object_id *hash2, + struct object_id *shifted, int depth_limit) { char *add_prefix; @@ -262,7 +270,7 @@ void shift_tree(const unsigned char *hash1, match_trees(hash2, hash1, &del_score, &del_prefix, "", depth_limit); /* Assume we do not have to do any shifting */ - hashcpy(shifted, hash2); + oidcpy(shifted, hash2); if (add_score < del_score) { /* We need to pick a subtree of two */ @@ -273,7 +281,7 @@ void shift_tree(const unsigned char *hash1, if (get_tree_entry(hash2, del_prefix, shifted, &mode)) die("cannot find path %s in tree %s", - del_prefix, sha1_to_hex(hash2)); + del_prefix, oid_to_hex(hash2)); return; } @@ -288,22 +296,22 @@ void shift_tree(const unsigned char *hash1, * Unfortunately we cannot fundamentally tell which one to * be prefixed, as recursive merge can work in either direction. */ -void shift_tree_by(const unsigned char *hash1, - const unsigned char *hash2, - unsigned char *shifted, +void shift_tree_by(const struct object_id *hash1, + const struct object_id *hash2, + struct object_id *shifted, const char *shift_prefix) { - unsigned char sub1[20], sub2[20]; + struct object_id sub1, sub2; unsigned mode1, mode2; unsigned candidate = 0; /* Can hash2 be a tree at shift_prefix in tree hash1? */ - if (!get_tree_entry(hash1, shift_prefix, sub1, &mode1) && + if (!get_tree_entry(hash1, shift_prefix, &sub1, &mode1) && S_ISDIR(mode1)) candidate |= 1; /* Can hash1 be a tree at shift_prefix in tree hash2? */ - if (!get_tree_entry(hash2, shift_prefix, sub2, &mode2) && + if (!get_tree_entry(hash2, shift_prefix, &sub2, &mode2) && S_ISDIR(mode2)) candidate |= 2; @@ -313,19 +321,19 @@ void shift_tree_by(const unsigned char *hash1, int score; candidate = 0; - score = score_trees(sub1, hash2); + score = score_trees(&sub1, hash2); if (score > best_score) { candidate = 1; best_score = score; } - score = score_trees(sub2, hash1); + score = score_trees(&sub2, hash1); if (score > best_score) candidate = 2; } if (!candidate) { /* Neither is plausible -- do not shift */ - hashcpy(shifted, hash2); + oidcpy(shifted, hash2); return; } @@ -340,5 +348,5 @@ void shift_tree_by(const unsigned char *hash1, * shift tree2 up by removing shift_prefix from it * to match tree1. */ - hashcpy(shifted, sub2); + oidcpy(shifted, &sub2); } |