@@ -1,9 +1,13 @@
#include "git-compat-util.h"
#include "gettext.h"
#include "hash.h"
+#include "hex.h"
+#include "lockfile.h"
#include "merge-ort.h"
#include "merge-ort-wrappers.h"
#include "read-cache-ll.h"
+#include "repository.h"
+#include "tag.h"
#include "tree.h"
#include "commit.h"
@@ -64,3 +68,63 @@ int merge_ort_recursive(struct merge_options *opt,
return tmp.clean;
}
+
+static struct commit *get_ref(struct repository *repo,
+ const struct object_id *oid,
+ const char *name)
+{
+ struct object *object;
+
+ object = deref_tag(repo, parse_object(repo, oid),
+ name, strlen(name));
+ if (!object)
+ return NULL;
+ if (object->type == OBJ_TREE)
+ return make_virtual_commit(repo, (struct tree*)object, name);
+ if (object->type != OBJ_COMMIT)
+ return NULL;
+ if (repo_parse_commit(repo, (struct commit *)object))
+ return NULL;
+ return (struct commit *)object;
+}
+
+int merge_ort_generic(struct merge_options *opt,
+ const struct object_id *head,
+ const struct object_id *merge,
+ int num_merge_bases,
+ const struct object_id *merge_bases,
+ struct commit **result)
+{
+ int clean;
+ struct lock_file lock = LOCK_INIT;
+ struct commit *head_commit = get_ref(opt->repo, head, opt->branch1);
+ struct commit *next_commit = get_ref(opt->repo, merge, opt->branch2);
+ struct commit_list *ca = NULL;
+
+ if (merge_bases) {
+ int i;
+ for (i = 0; i < num_merge_bases; ++i) {
+ struct commit *base;
+ if (!(base = get_ref(opt->repo, &merge_bases[i],
+ oid_to_hex(&merge_bases[i]))))
+ return error(_("Could not parse object '%s'"),
+ oid_to_hex(&merge_bases[i]));
+ commit_list_insert(base, &ca);
+ }
+ }
+
+ repo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);
+ clean = merge_ort_recursive(opt, head_commit, next_commit, ca,
+ result);
+ free_commit_list(ca);
+ if (clean < 0) {
+ rollback_lock_file(&lock);
+ return clean;
+ }
+
+ if (write_locked_index(opt->repo->index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ return error(_("Unable to write index."));
+
+ return clean ? 0 : 1;
+}
@@ -22,4 +22,16 @@ int merge_ort_recursive(struct merge_options *opt,
const struct commit_list *ancestors,
struct commit **result);
+/*
+ * rename-detecting three-way merge. num_merge_bases must be at least 1.
+ * Recursive ancestor consolidation will be performed if num_merge_bases > 1.
+ * Wrapper mimicking the old merge_recursive_generic() function.
+ */
+int merge_ort_generic(struct merge_options *opt,
+ const struct object_id *head,
+ const struct object_id *merge,
+ int num_merge_bases,
+ const struct object_id *merge_bases,
+ struct commit **result);
+
#endif
@@ -4878,9 +4878,9 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)
c->maybe_tree = t;
}
-static struct commit *make_virtual_commit(struct repository *repo,
- struct tree *tree,
- const char *comment)
+struct commit *make_virtual_commit(struct repository *repo,
+ struct tree *tree,
+ const char *comment)
{
struct commit *commit = alloc_commit_node(repo);
@@ -5186,6 +5186,8 @@ static void merge_ort_internal(struct merge_options *opt,
ancestor_name = "empty tree";
} else if (merge_bases) {
ancestor_name = "merged common ancestors";
+ } else if (opt->ancestor) {
+ ancestor_name = opt->ancestor;
} else {
strbuf_add_unique_abbrev(&merge_base_abbrev,
&merged_merge_bases->object.oid,
@@ -5275,8 +5277,13 @@ void merge_incore_recursive(struct merge_options *opt,
{
trace2_region_enter("merge", "incore_recursive", opt->repo);
- /* We set the ancestor label based on the merge_bases */
- assert(opt->ancestor == NULL);
+ /*
+ * We set the ancestor label based on the merge_bases...but we
+ * allow one exception through so that builtin/am can override
+ * with its constructed fake ancestor.
+ */
+ assert(opt->ancestor == NULL ||
+ (merge_bases && !merge_bases->next));
trace2_region_enter("merge", "merge_start", opt->repo);
merge_start(opt, result);
@@ -44,6 +44,11 @@ struct merge_result {
unsigned _properly_initialized;
};
+/* Mostly internal function also used by merge-ort-wrappers.c */
+struct commit *make_virtual_commit(struct repository *repo,
+ struct tree *tree,
+ const char *comment);
+
/*
* rename-detecting three-way merge with recursive ancestor consolidation.
* working tree and index are untouched.