On Tue, Jul 31, 2018 at 08:53:23AM -0700, Junio C Hamano wrote:
George Shammas [off-list ref] writes:
quoted
Bisecting around, this might be the commit that introduced the breakage.
https://github.com/git/git/commit/d8febde
Interesting. I've never used the "-s subtree" strategy without
"-Xsubtree=..." to explicitly tell where the thing should go for a
long time, so I am not surprised if I did not notice if an update to
the heuristics made long time ago had affected tree matching.
d8febde3 ("match-trees: simplify score_trees() using tree_entry()",
2013-03-24) does touch the area that may affect the subtree matching
behaviour.
Because it is an update to heuristics, and as such, we need to be
careful when saying it is or is not "broken". Some heuristics may
work better with your particular case, and may do worse with other
cases.
But from the log message description, it looks like it was meant to
be a no-op simplification rewrite that should not affect the outcome,
so it is a bit surprising.
Yeah, this is definitely not "well, the heuristic changed a bit". It's
just broken. This fixes it, but we should probably add a test.
diff --git a/match-trees.c b/match-trees.c
index 4cdeff53e1..730fff4cfb 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -83,34 +83,40 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
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);
+ continue;
+ } else if (cmp > 0) {
/* path2 does not appear in one */
- score += score_missing(e2.mode, e2.path);
- else if (oidcmp(e1.oid, e2.oid))
+ score += score_missing(two.entry.mode, two.entry.path);
+ update_tree_entry(&two);
+ continue;
+ } if (oidcmp(one.entry.oid, two.entry.oid)) {
/* they are different */
- score += score_differs(e1.mode, e2.mode, e1.path);
- else
+ score += score_differs(one.entry.mode, two.entry.mode,
+ one.entry.path);
+ } else {
/* same subtree or blob */
- score += score_matches(e1.mode, e2.mode, e1.path);
+ 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);