diff options
author | Junio C Hamano <gitster@pobox.com> | 2018-08-17 13:09:55 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2018-08-17 13:09:55 -0700 |
commit | 60858f343aa909305c28790c7684bf88905695a2 (patch) | |
tree | a49486fea05a68d019262140c24e63483a1affcc | |
parent | Merge branch 'ab/test-must-be-empty' (diff) | |
parent | score_trees(): fix iteration over trees with missing entries (diff) | |
download | tgif-60858f343aa909305c28790c7684bf88905695a2.tar.xz |
Merge branch 'jk/merge-subtree-heuristics'
The automatic tree-matching in "git merge -s subtree" was broken 5
years ago and nobody has noticed since then, which is now fixed.
* jk/merge-subtree-heuristics:
score_trees(): fix iteration over trees with missing entries
-rw-r--r-- | match-trees.c | 43 | ||||
-rwxr-xr-x | t/t6029-merge-subtree.sh | 28 |
2 files changed, 54 insertions, 17 deletions
diff --git a/match-trees.c b/match-trees.c index 4cdeff53e1..37653308d3 100644 --- a/match-trees.c +++ b/match-trees.c @@ -83,34 +83,43 @@ 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); + } else if (cmp > 0) { /* path2 does not appear in one */ - score += score_missing(e2.mode, e2.path); - else if (oidcmp(e1.oid, e2.oid)) - /* 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); diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh index 7d5bc78472..793f0c8bf3 100755 --- a/t/t6029-merge-subtree.sh +++ b/t/t6029-merge-subtree.sh @@ -29,6 +29,34 @@ test_expect_success 'subtree available and works like recursive' ' ' +test_expect_success 'setup branch sub' ' + git checkout --orphan sub && + git rm -rf . && + test_commit foo +' + +test_expect_success 'setup branch main' ' + git checkout -b main master && + git merge -s ours --no-commit --allow-unrelated-histories sub && + git read-tree --prefix=dir/ -u sub && + git commit -m "initial merge of sub into main" && + test_path_is_file dir/foo.t && + test_path_is_file hello +' + +test_expect_success 'update branch sub' ' + git checkout sub && + test_commit bar +' + +test_expect_success 'update branch main' ' + git checkout main && + git merge -s subtree sub -m "second merge of sub into main" && + test_path_is_file dir/bar.t && + test_path_is_file dir/foo.t && + test_path_is_file hello +' + test_expect_success 'setup' ' mkdir git-gui && cd git-gui && |