From: Phillip Wood Date: Fri, 16 May 2025 13:18:19 GMT Subject: Re: [PATCH v3 2/2] merge-tree: add a new --dry-run flag Message-ID: <23e4267a-34fb-414d-bae3-7f607d3bdbec@gmail.com> In-Reply-To: Hi Elijah On 14/05/2025 01:24, Elijah Newren via GitGitGadget wrote: > From: Elijah Newren > > +--dry-run:: > + 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. I don't want to bike-shed but to me this feels more like "git diff --quiet" than "git push --dry-run" or "git send-email --dry-run" which still print diagnostic messages. Best Wishes Phillip > --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..273ec171e988 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 dry_run = 0; > > const char * const merge_tree_usage[] = { > N_("git merge-tree [--write-tree] [] "), > @@ -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, "dry-run", > + &dry_run, > + 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 (dry_run && o.show_messages == -1) > + o.show_messages = 0; > + o.merge_options.mergeability_only = dry_run; > + die_for_incompatible_opt2(dry_run, "--dry-run", > + o.show_messages, "--messages"); > + die_for_incompatible_opt2(dry_run, "--dry-run", > + o.name_only, "--name-only"); > + die_for_incompatible_opt2(dry_run, "--dry-run", > + o.use_stdin, "--stdin"); > + die_for_incompatible_opt2(dry_run, "--dry-run", > + !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..566a2b4ec737 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 '--dry-run 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 --dry-run 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 '--dry-run 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 --dry-run 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 &&