git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>, Elijah Newren <newren@gmail.com>
Subject: [PATCH 2/2] merge-tree: add a new --mergeability-only flag
Date: Sat, 10 May 2025 22:02:41 +0000	[thread overview]
Message-ID: <0b32c80d2867492b7b63f346bdf1e9401d4644ae.1746914561.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1920.git.1746914561.gitgitgadget@gmail.com>

From: Elijah Newren <newren@gmail.com>

Git Forges may be interested in whether two branches can be merged while
not being interested in what the resulting merge tree is nor which files
conflicted.  For such cases, add a new --mergeability-only flag which
will make use of the new mergeability_only flag added to merge-ort in
the previous commit.  This option allows the merge machinery to, in the
outer layer of the merge:
      * exit upon first conflict
      * avoid writing merged blobs/trees to the object store

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 Documentation/git-merge-tree.adoc |  6 +++++
 builtin/merge-tree.c              | 22 ++++++++++++++++++
 t/t4301-merge-tree-write-tree.sh  | 38 +++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/Documentation/git-merge-tree.adoc b/Documentation/git-merge-tree.adoc
index cf0578f9b5e8..7dcc17806191 100644
--- a/Documentation/git-merge-tree.adoc
+++ b/Documentation/git-merge-tree.adoc
@@ -65,6 +65,12 @@ OPTIONS
 	default is to include these messages if there are merge
 	conflicts, and to omit them otherwise.
 
+--mergeability-only::
+	Disable all output from the program.  Useful when you are only
+	interested in the exit status.  Allows merge-tree to exit
+	early on the first conflict it finds, and allows it to avoid
+	writing most objects created by merges.
+
 --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
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 4aafa73c6155..48179d83596c 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -490,6 +490,9 @@ static int real_merge(struct merge_tree_options *o,
 	if (result.clean < 0)
 		die(_("failure to merge"));
 
+	if (o->merge_options.mergeability_only)
+		goto cleanup;
+
 	if (show_messages == -1)
 		show_messages = !result.clean;
 
@@ -522,6 +525,8 @@ static int real_merge(struct merge_tree_options *o,
 	}
 	if (o->use_stdin)
 		putchar(line_termination);
+
+cleanup:
 	merge_finalize(&opt, &result);
 	clear_merge_options(&opt);
 	return !result.clean; /* result.clean < 0 handled above */
@@ -538,6 +543,7 @@ int cmd_merge_tree(int argc,
 	int original_argc;
 	const char *merge_base = NULL;
 	int ret;
+	int mergeability_only = 0;
 
 	const char * const merge_tree_usage[] = {
 		N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -552,6 +558,10 @@ int cmd_merge_tree(int argc,
 			    N_("do a trivial merge only"), MODE_TRIVIAL),
 		OPT_BOOL(0, "messages", &o.show_messages,
 			 N_("also show informational/conflict messages")),
+		OPT_BOOL_F(0, "mergeability-only",
+			   &mergeability_only,
+			   N_("suppress all output; only exit status wanted"),
+			   PARSE_OPT_NONEG),
 		OPT_SET_INT('z', NULL, &line_termination,
 			    N_("separate paths with the NUL character"), '\0'),
 		OPT_BOOL_F(0, "name-only",
@@ -583,6 +593,18 @@ int cmd_merge_tree(int argc,
 	argc = parse_options(argc, argv, prefix, mt_options,
 			     merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
 
+	if (mergeability_only && o.show_messages == -1)
+		o.show_messages = 0;
+	o.merge_options.mergeability_only = mergeability_only;
+	die_for_incompatible_opt2(mergeability_only, "--mergeability-only",
+				  o.show_messages, "--messages");
+	die_for_incompatible_opt2(mergeability_only, "--mergeability-only",
+				  o.name_only, "--name-only");
+	die_for_incompatible_opt2(mergeability_only, "--mergeability-only",
+				  o.use_stdin, "--stdin");
+	die_for_incompatible_opt2(mergeability_only, "--mergeability-only",
+				  !line_termination, "-z");
+
 	if (xopts.nr && o.mode == MODE_TRIVIAL)
 		die(_("--trivial-merge is incompatible with all other options"));
 	for (size_t x = 0; x < xopts.nr; x++)
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index f9c5883a7f7c..3170830dd79d 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -54,6 +54,25 @@ test_expect_success setup '
 	git commit -m first-commit
 '
 
+test_expect_success '--mergeability-only on clean merge' '
+	# Get rid of loose objects to start with
+	git gc &&
+	echo "0 objects, 0 kilobytes" >expect &&
+	git count-objects >actual &&
+	test_cmp expect actual &&
+
+	# Ensure merge is successful (exit code of 0)
+	git merge-tree --write-tree --mergeability-only side1 side3 >output &&
+
+	# Ensure there is no output
+	test_must_be_empty output &&
+
+	# Ensure no loose objects written (all new objects written would have
+	# been in "outer layer" of the merge)
+	git count-objects >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'Clean merge' '
 	TREE_OID=$(git merge-tree --write-tree side1 side3) &&
 	q_to_tab <<-EOF >expect &&
@@ -72,6 +91,25 @@ test_expect_success 'Failed merge without rename detection' '
 	grep "CONFLICT (modify/delete): numbers deleted" out
 '
 
+test_expect_success  '--mergeability-only on conflicted merge' '
+	# Get rid of loose objects to start with
+	git gc &&
+	echo "0 objects, 0 kilobytes" >expect &&
+	git count-objects >actual &&
+	test_cmp expect actual &&
+
+	# Ensure merge has conflict
+	test_expect_code 1 git merge-tree --write-tree --mergeability-only side1 side2 >output &&
+
+	# Ensure there is no output
+	test_must_be_empty output &&
+
+	# Ensure no loose objects written (all new objects written would have
+	# been in "outer layer" of the merge)
+	git count-objects >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'Content merge and a few conflicts' '
 	git checkout side1^0 &&
 	test_must_fail git merge side2 &&
-- 
gitgitgadget

  parent reply	other threads:[~2025-05-10 22:02 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-10 22:02 [PATCH 0/2] merge-tree: add new --mergeability-only option Elijah Newren via GitGitGadget
2025-05-10 22:02 ` [PATCH 1/2] merge-ort: add a new mergeability_only option Elijah Newren via GitGitGadget
2025-05-10 22:02 ` Elijah Newren via GitGitGadget [this message]
2025-05-12 17:04 ` [PATCH 0/2] merge-tree: add new --mergeability-only option Junio C Hamano
2025-05-12 17:41   ` Elijah Newren
2025-05-12 18:27     ` Junio C Hamano
2025-05-12 18:37       ` Elijah Newren
2025-05-12 23:42 ` [PATCH v2 0/2] merge-tree: add new --dry-run option Elijah Newren via GitGitGadget
2025-05-12 23:42   ` [PATCH v2 1/2] merge-ort: add a new mergeability_only option Elijah Newren via GitGitGadget
2025-05-12 23:42   ` [PATCH v2 2/2] merge-tree: add a new --dry-run flag Elijah Newren via GitGitGadget
2025-05-13  7:15     ` Kristoffer Haugsbakk
2025-05-13 15:28       ` Elijah Newren
2025-05-13 13:24     ` Junio C Hamano
2025-05-13 15:30       ` Elijah Newren
2025-05-14 14:08         ` Junio C Hamano
2025-05-14  0:24   ` [PATCH v3 0/2] merge-tree: add new --dry-run option Elijah Newren via GitGitGadget
2025-05-14  0:24     ` [PATCH v3 1/2] merge-ort: add a new mergeability_only option Elijah Newren via GitGitGadget
2025-05-14  0:24     ` [PATCH v3 2/2] merge-tree: add a new --dry-run flag Elijah Newren via GitGitGadget
2025-05-15 13:07       ` Junio C Hamano
2025-05-16 13:18       ` Phillip Wood
2025-05-16 16:03         ` Elijah Newren
2025-05-14 15:34     ` [PATCH v3 0/2] merge-tree: add new --dry-run option Kristoffer Haugsbakk
2025-05-16 20:04     ` [PATCH v4 0/2] merge-tree: add new --quiet option Elijah Newren via GitGitGadget
2025-05-16 20:04       ` [PATCH v4 1/2] merge-ort: add a new mergeability_only option Elijah Newren via GitGitGadget
2025-05-16 20:04       ` [PATCH v4 2/2] merge-tree: add a new --quiet flag Elijah Newren via GitGitGadget
2025-05-17 19:52         ` Kristoffer Haugsbakk
2025-05-17 19:57           ` Kristoffer Haugsbakk
2025-05-19  9:05       ` [PATCH v4 0/2] merge-tree: add new --quiet option Phillip Wood
2025-05-19 15:59         ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0b32c80d2867492b7b63f346bdf1e9401d4644ae.1746914561.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=newren@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).