]> git.ipfire.org Git - thirdparty/git.git/commitdiff
merge-tree: add a new --quiet flag
authorElijah Newren <newren@gmail.com>
Fri, 16 May 2025 20:04:18 +0000 (20:04 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 16 May 2025 22:09:14 +0000 (15:09 -0700)
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 --quiet 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 early when a conflict is detected
    * avoid writing (most) merged blobs/trees to the object store

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-merge-tree.adoc
builtin/merge-tree.c
t/t4301-merge-tree-write-tree.sh

index cf0578f9b5e86df78dcbce243788a2889ca03d89..f824eea61f1e067c8ce7b49bde32c8922850a352 100644 (file)
@@ -65,6 +65,12 @@ OPTIONS
        default is to include these messages if there are merge
        conflicts, and to omit them otherwise.
 
+--quiet::
+       Disable all output from the program.  Useful when you are only
+       interested in the exit status.  Allows merge-tree to exit
+       early when it finds a conflict, 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
index 4aafa73c61559ec44c2a5d73df43b2123df3026b..7f41665dfd7e67b13040380438560ba3ae896dff 100644 (file)
@@ -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 quiet = 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, "quiet",
+                          &quiet,
+                          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,14 @@ int cmd_merge_tree(int argc,
        argc = parse_options(argc, argv, prefix, mt_options,
                             merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
 
+       if (quiet && o.show_messages == -1)
+               o.show_messages = 0;
+       o.merge_options.mergeability_only = quiet;
+       die_for_incompatible_opt2(quiet, "--quiet", o.show_messages, "--messages");
+       die_for_incompatible_opt2(quiet, "--quiet", o.name_only, "--name-only");
+       die_for_incompatible_opt2(quiet, "--quiet", o.use_stdin, "--stdin");
+       die_for_incompatible_opt2(quiet, "--quiet", !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++)
index f9c5883a7f7cd6f9570c5e4ebf6a95ca4ac14cb1..6e117ee93c8b5b8dc5788e623b00b70f56d5b8ea 100755 (executable)
@@ -54,6 +54,25 @@ test_expect_success setup '
        git commit -m first-commit
 '
 
+test_expect_success '--quiet 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 --quiet 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  '--quiet 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 --quiet 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 &&