[PATCH v2] merge-tree: accept 3 trees as arguments
- From
Johannes Schindelin via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Jan 28, 2024, 20:34 UTC
- Message-ID
- <pull.1647.v2.git.1706474063109.gitgitgadget@gmail.com>
- In-Reply-To
- <pull.1647.git.1706277694231.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
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 <johannes.schindelin@gmx.de>
---
merge-tree: accept 3 trees as arguments
I was asked to implement this at $dayjob and it seems like a feature
that might be useful to other users, too.
Changes since v1:
* Fixed a typo in the manual page, simplified the part after the
semicolon.
* Simplified the test case.Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1647%2Fdscho%2Fallow-merge-tree-to-accept-3-trees-v2 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1647/dscho/allow-merge-tree-to-accept-3-trees-v2 Pull-Request: https://github.com/gitgitgadget/git/pull/1647
Range-diff vs v1:
1: 29234754c06 ! 1: 233a25e9071 merge-tree: accept 3 trees as arguments
@@ Documentation/git-merge-tree.txt: OPTIONS
currently not supported. This option is incompatible with `--stdin`.
++
+As the merge-base is provided directly, <branch1> and <branch2> do not need
-+o specify commits; it is sufficient if they specify trees.
++to specify commits; trees are enough.
[[OUTPUT]]
OUTPUT
@@ t/t4301-merge-tree-write-tree.sh: test_expect_success 'check the input format wh
'
+test_expect_success '--merge-base with tree OIDs' '
-+ git merge-tree --merge-base=side1^ side1 side3 >tree &&
-+ tree=$(cat tree) &&
-+ git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >tree2 &&
-+ tree2=$(cat tree2) &&
-+ test $tree = $tree2
++ 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_doneDocumentation/git-merge-tree.txt | 5 +++- builtin/merge-tree.c | 42 +++++++++++++++++++------------- t/t4301-merge-tree-write-tree.sh | 6 +++++ 3 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index b50acace3bc..dd388fa21d5 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -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 diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 3bdec53fbe5..cbd8e15af6d 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -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 diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 12ac4368736..c5628c4e613 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -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 base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
-- gitgitgadget