Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2022-06-18 03:20:47 +0300
committerJunio C Hamano <gitster@pobox.com>2022-06-23 02:10:05 +0300
commit1f0c3a29da3515d88537902cd267cc726020eea5 (patch)
treeb6cefb71697248ef7d7886fdec8022414320deae /builtin/merge-tree.c
parent6ec755a0e152dfb0ed6bffa70b511c45a1f29ebd (diff)
merge-tree: implement real merges
This adds the ability to perform real merges rather than just trivial merges (meaning handling three way content merges, recursive ancestor consolidation, renames, proper directory/file conflict handling, and so forth). However, unlike `git merge`, the working tree and index are left alone and no branch is updated. The only output is: - the toplevel resulting tree printed on stdout - exit status of 0 (clean), 1 (conflicts present), anything else (merge could not be performed; unknown if clean or conflicted) This output is meant to be used by some higher level script, perhaps in a sequence of steps like this: NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) test $? -eq 0 || die "There were conflicts..." NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2) git update-ref $BRANCH1 $NEWCOMMIT Note that higher level scripts may also want to access the conflict/warning messages normally output during a merge, or have quick access to a list of files with conflicts. That is not available in this preliminary implementation, but subsequent commits will add that ability (meaning that NEWTREE would be a lot more than a tree in the case of conflicts). This also marks the traditional trivial merge of merge-tree as deprecated. The trivial merge not only had limited applicability, the output format was also difficult to work with (and its format undocumented), and will generally be less performant than real merges. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/merge-tree.c')
-rw-r--r--builtin/merge-tree.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 0f9d928e86..2332525d8b 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -2,6 +2,9 @@
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
+#include "help.h"
+#include "commit-reach.h"
+#include "merge-ort.h"
#include "object-store.h"
#include "parse-options.h"
#include "repository.h"
@@ -398,7 +401,43 @@ struct merge_tree_options {
static int real_merge(struct merge_tree_options *o,
const char *branch1, const char *branch2)
{
- die(_("real merges are not yet implemented"));
+ struct commit *parent1, *parent2;
+ struct commit_list *merge_bases = NULL;
+ struct merge_options opt;
+ struct merge_result result = { 0 };
+
+ parent1 = get_merge_parent(branch1);
+ if (!parent1)
+ help_unknown_ref(branch1, "merge-tree",
+ _("not something we can merge"));
+
+ parent2 = get_merge_parent(branch2);
+ if (!parent2)
+ help_unknown_ref(branch2, "merge-tree",
+ _("not something we can merge"));
+
+ init_merge_options(&opt, the_repository);
+
+ opt.show_rename_progress = 0;
+
+ opt.branch1 = branch1;
+ opt.branch2 = branch2;
+
+ /*
+ * Get the merge bases, in reverse order; see comment above
+ * merge_incore_recursive in merge-ort.h
+ */
+ merge_bases = get_merge_bases(parent1, parent2);
+ if (!merge_bases)
+ die(_("refusing to merge unrelated histories"));
+ merge_bases = reverse_commit_list(merge_bases);
+
+ merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ if (result.clean < 0)
+ die(_("failure to merge"));
+ puts(oid_to_hex(&result.tree->object.oid));
+ merge_finalize(&opt, &result);
+ return !result.clean; /* result.clean < 0 handled above */
}
int cmd_merge_tree(int argc, const char **argv, const char *prefix)