summaryrefslogtreecommitdiff
path: root/merge-ort.c
diff options
context:
space:
mode:
authorLibravatar Elijah Newren <newren@gmail.com>2020-12-16 22:28:02 +0000
committerLibravatar Junio C Hamano <gitster@pobox.com>2020-12-16 21:56:39 -0800
commit8119214f4e7036cef01a8e13f161ec510b3ff710 (patch)
treeaf9ef47412aaf52ae1dd84c9d13ea17cb5481a7e /merge-ort.c
parentmerge-ort: make clear_internal_opts() aware of partial clearing (diff)
downloadtgif-8119214f4e7036cef01a8e13f161ec510b3ff710.tar.xz
merge-ort: implement merge_incore_recursive()
Implement merge_incore_recursive(), mostly through the use of a new helper function, merge_ort_internal(), which itself is based off merge_recursive_internal() from merge-recursive.c. This drops the number of failures in the testsuite when run under GIT_TEST_MERGE_ALGORITHM=ort from around 1500 to 647. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'merge-ort.c')
-rw-r--r--merge-ort.c90
1 files changed, 88 insertions, 2 deletions
diff --git a/merge-ort.c b/merge-ort.c
index bd237f3472..31103d2140 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1356,7 +1356,6 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)
c->maybe_tree = t;
}
-MAYBE_UNUSED
static struct commit *make_virtual_commit(struct repository *repo,
struct tree *tree,
const char *comment)
@@ -1466,6 +1465,89 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt,
}
}
+/*
+ * Originally from merge_recursive_internal(); somewhat adapted, though.
+ */
+static void merge_ort_internal(struct merge_options *opt,
+ struct commit_list *merge_bases,
+ struct commit *h1,
+ struct commit *h2,
+ struct merge_result *result)
+{
+ struct commit_list *iter;
+ struct commit *merged_merge_bases;
+ const char *ancestor_name;
+ struct strbuf merge_base_abbrev = STRBUF_INIT;
+
+ if (!merge_bases) {
+ merge_bases = get_merge_bases(h1, h2);
+ /* See merge-ort.h:merge_incore_recursive() declaration NOTE */
+ merge_bases = reverse_commit_list(merge_bases);
+ }
+
+ merged_merge_bases = pop_commit(&merge_bases);
+ if (merged_merge_bases == NULL) {
+ /* if there is no common ancestor, use an empty tree */
+ struct tree *tree;
+
+ tree = lookup_tree(opt->repo, opt->repo->hash_algo->empty_tree);
+ merged_merge_bases = make_virtual_commit(opt->repo, tree,
+ "ancestor");
+ ancestor_name = "empty tree";
+ } else if (merge_bases) {
+ ancestor_name = "merged common ancestors";
+ } else {
+ strbuf_add_unique_abbrev(&merge_base_abbrev,
+ &merged_merge_bases->object.oid,
+ DEFAULT_ABBREV);
+ ancestor_name = merge_base_abbrev.buf;
+ }
+
+ for (iter = merge_bases; iter; iter = iter->next) {
+ const char *saved_b1, *saved_b2;
+ struct commit *prev = merged_merge_bases;
+
+ opt->priv->call_depth++;
+ /*
+ * When the merge fails, the result contains files
+ * with conflict markers. The cleanness flag is
+ * ignored (unless indicating an error), it was never
+ * actually used, as result of merge_trees has always
+ * overwritten it: the committed "conflicts" were
+ * already resolved.
+ */
+ saved_b1 = opt->branch1;
+ saved_b2 = opt->branch2;
+ opt->branch1 = "Temporary merge branch 1";
+ opt->branch2 = "Temporary merge branch 2";
+ merge_ort_internal(opt, NULL, prev, iter->item, result);
+ if (result->clean < 0)
+ return;
+ opt->branch1 = saved_b1;
+ opt->branch2 = saved_b2;
+ opt->priv->call_depth--;
+
+ merged_merge_bases = make_virtual_commit(opt->repo,
+ result->tree,
+ "merged tree");
+ commit_list_insert(prev, &merged_merge_bases->parents);
+ commit_list_insert(iter->item,
+ &merged_merge_bases->parents->next);
+
+ clear_or_reinit_internal_opts(opt->priv, 1);
+ }
+
+ opt->ancestor = ancestor_name;
+ merge_ort_nonrecursive_internal(opt,
+ repo_get_commit_tree(opt->repo,
+ merged_merge_bases),
+ repo_get_commit_tree(opt->repo, h1),
+ repo_get_commit_tree(opt->repo, h2),
+ result);
+ strbuf_release(&merge_base_abbrev);
+ opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */
+}
+
void merge_incore_nonrecursive(struct merge_options *opt,
struct tree *merge_base,
struct tree *side1,
@@ -1483,5 +1565,9 @@ void merge_incore_recursive(struct merge_options *opt,
struct commit *side2,
struct merge_result *result)
{
- die("Not yet implemented");
+ /* We set the ancestor label based on the merge_bases */
+ assert(opt->ancestor == NULL);
+
+ merge_start(opt, result);
+ merge_ort_internal(opt, merge_bases, side1, side2, result);
}