diff mbox series

[v2,12/13] merge-tree: add a --allow-unrelated-histories flag

Message ID 25677d5038cab591774eaa1349365871b23aa2fc.1643479633.git.gitgitgadget@gmail.com (mailing list archive)
State Superseded
Headers show
Series In-core git merge-tree ("Server side merges") | expand

Commit Message

Elijah Newren Jan. 29, 2022, 6:07 p.m. UTC
From: Elijah Newren <newren@gmail.com>

Folks may want to merge histories that have no common ancestry; provide
a flag with the same name as used by `git merge` to allow this.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 Documentation/git-merge-tree.txt |  5 +++++
 builtin/merge-tree.c             |  7 ++++++-
 t/t4301-merge-tree-write-tree.sh | 24 +++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 2 deletions(-)

Comments

Junio C Hamano Feb. 2, 2022, 9:32 p.m. UTC | #1
"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> @@ -430,7 +431,7 @@ static int real_merge(struct merge_tree_options *o,
>  	 * merge_incore_recursive in merge-ort.h
>  	 */
>  	common = get_merge_bases(parent1, parent2);
> -	if (!common)
> +	if (!common && !o->allow_unrelated_histories)
>  		die(_("refusing to merge unrelated histories"));
>  	for (j = common; j; j = j->next)
>  		commit_list_insert(j->item, &merge_bases);

Curious.  This step _adds_ an "--allow" option from the command
line, but we actually did not have to die() when seeing that there
is no common ancestor before this step.  The end result is OK either
way.

> @@ -494,6 +495,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
>  			   &o.exclude_modes_oids_stages,
>  			   N_("list conflicted files without modes/oids/stages"),
>  			   PARSE_OPT_NONEG),
> +		OPT_BOOL_F(0, "allow-unrelated-histories",
> +			   &o.allow_unrelated_histories,
> +			   N_("allow merging unrelated histories"),
> +			   PARSE_OPT_NONEG),
>  		OPT_END()
>  	};
diff mbox series

Patch

diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 55bb7bc61c1..d35710c81d5 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -49,6 +49,11 @@  OPTIONS
 	default is to include these messages if there are merge
 	conflicts, and to omit them otherwise.
 
+--allow-unrelated-histories::
+	merge-tree will by default error out if the two branches specified
+	share no common history.  This flag can be given to override that
+	check and make the merge proceed anyway.
+
 OUTPUT
 ------
 
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index dc52cd02dce..cca5075d521 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -393,6 +393,7 @@  static int trivial_merge(const char *base,
 
 struct merge_tree_options {
 	int mode;
+	int allow_unrelated_histories;
 	int show_messages;
 	int exclude_modes_oids_stages;
 };
@@ -430,7 +431,7 @@  static int real_merge(struct merge_tree_options *o,
 	 * merge_incore_recursive in merge-ort.h
 	 */
 	common = get_merge_bases(parent1, parent2);
-	if (!common)
+	if (!common && !o->allow_unrelated_histories)
 		die(_("refusing to merge unrelated histories"));
 	for (j = common; j; j = j->next)
 		commit_list_insert(j->item, &merge_bases);
@@ -494,6 +495,10 @@  int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 			   &o.exclude_modes_oids_stages,
 			   N_("list conflicted files without modes/oids/stages"),
 			   PARSE_OPT_NONEG),
+		OPT_BOOL_F(0, "allow-unrelated-histories",
+			   &o.allow_unrelated_histories,
+			   N_("allow merging unrelated histories"),
+			   PARSE_OPT_NONEG),
 		OPT_END()
 	};
 
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index 1572f460da0..996bdfaab7d 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -38,7 +38,13 @@  test_expect_success setup '
 	>whatever/empty &&
 	git add numbers greeting whatever/empty &&
 	test_tick &&
-	git commit -m other-modifications
+	git commit -m other-modifications &&
+
+	git switch --orphan unrelated &&
+	>something-else &&
+	git add something-else &&
+	test_tick &&
+	git commit -m first-commit
 '
 
 test_expect_success 'Content merge and a few conflicts' '
@@ -139,4 +145,20 @@  test_expect_success 'Check conflicted oids and modes without messages' '
 	test_cmp conflicted-file-info actual
 '
 
+test_expect_success 'error out by default for unrelated histories' '
+	test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
+
+	grep "refusing to merge unrelated histories" error
+'
+
+test_expect_success 'can override merge of unrelated histories' '
+	git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
+	TREE=$(cat tree) &&
+
+	git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect &&
+	git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual &&
+
+	test_cmp expect actual
+'
+
 test_done