Skip to content

Commit

Permalink
merge-tree: accept 3 trees as arguments
Browse files Browse the repository at this point in the history
When specifying a merge base explicitly, there is actually no good
reason why the inputs need to be commits: that's only needed if the
merge base has to be deduced from the commit graph.

This commit is best viewed with `--color-moved
--color-moved-ws=allow-indentation-change`.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Jan 29, 2024
1 parent e02ecfc commit 233a25e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 18 deletions.
5 changes: 4 additions & 1 deletion Documentation/git-merge-tree.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,13 @@ OPTIONS
share no common history. This flag can be given to override that
check and make the merge proceed anyway.

--merge-base=<commit>::
--merge-base=<tree-ish>::
Instead of finding the merge-bases for <branch1> and <branch2>,
specify a merge-base for the merge, and specifying multiple bases is
currently not supported. This option is incompatible with `--stdin`.
+
As the merge-base is provided directly, <branch1> and <branch2> do not need
to specify commits; trees are enough.

[[OUTPUT]]
OUTPUT
Expand Down
42 changes: 25 additions & 17 deletions builtin/merge-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,35 +429,43 @@ static int real_merge(struct merge_tree_options *o,
struct merge_options opt;

copy_merge_options(&opt, &o->merge_options);
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"));

opt.show_rename_progress = 0;

opt.branch1 = branch1;
opt.branch2 = branch2;

if (merge_base) {
struct commit *base_commit;
struct tree *base_tree, *parent1_tree, *parent2_tree;

base_commit = lookup_commit_reference_by_name(merge_base);
if (!base_commit)
die(_("could not lookup commit '%s'"), merge_base);
/*
* We actually only need the trees because we already
* have a merge base.
*/
struct object_id base_oid, head_oid, merge_oid;

if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
die(_("could not parse as tree '%s'"), merge_base);
base_tree = parse_tree_indirect(&base_oid);
if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
die(_("could not parse as tree '%s'"), branch1);
parent1_tree = parse_tree_indirect(&head_oid);
if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
die(_("could not parse as tree '%s'"), branch2);
parent2_tree = parse_tree_indirect(&merge_oid);

opt.ancestor = merge_base;
base_tree = repo_get_commit_tree(the_repository, base_commit);
parent1_tree = repo_get_commit_tree(the_repository, parent1);
parent2_tree = repo_get_commit_tree(the_repository, parent2);
merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
} else {
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"));

/*
* Get the merge bases, in reverse order; see comment above
* merge_incore_recursive in merge-ort.h
Expand Down
6 changes: 6 additions & 0 deletions t/t4301-merge-tree-write-tree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -945,4 +945,10 @@ test_expect_success 'check the input format when --stdin is passed' '
test_cmp expect actual
'

test_expect_success '--merge-base with tree OIDs' '
git merge-tree --merge-base=side1^ side1 side3 >with-commits &&
git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees &&
test_cmp with-commits with-trees
'

test_done

0 comments on commit 233a25e

Please sign in to comment.