merge-tree.c: allow specifying the merge-base when --stdin is passed

The previous commit added a `--merge-base` option in order to allow using a specified merge-base for the merge. Extend the input accepted by `--stdin` to also allow a specified merge-base with each merge requested. For example: printf "<b3> -- <b1> <b2>" | git merge-tree --stdin does a merge of b1 and b2, and uses b3 as the merge-base. Signed-off-by: Kyle Zhao <kylezhao@tencent.com> Signed-off-by: Taylor Blau <me@ttaylorr.com>

Kyle Zhao committed Nov 11, 2022 at 23:45 UTC 501e3bab99da75eada3e2d6ef5257a3c44dd1ae4
3 files changed +67 -3
Documentation/git-merge-tree.txt
+13 -1
@@ -66,7 +66,8 @@ OPTIONS
66
67 --merge-base=<commit>::
68 Instead of finding the merge-bases for <branch1> and <branch2>,
69 - specify a merge-base for the merge.
69 + specify a merge-base for the merge. This option is incompatible
70 + with `--stdin`.
71
72 [[OUTPUT]]
73 OUTPUT
@@ -220,6 +221,17 @@ with linkgit:git-merge[1]:
221 * any messages that would have been printed to stdout (the
222 <<IM,Informational messages>>)
223
224 +INPUT FORMAT
225 +------------
226 +'git merge-tree --stdin' input format is fully text based. Each line
227 +has this format:
228 +
229 + [<base-commit> -- ]<branch1> <branch2>
230 +
231 +If one line is separated by `--`, the string before the separator is
232 +used for specifying a merge-base for the merge and the string after
233 +the separator describes the branches to be merged.
234 +
235 MISTAKES TO AVOID
236 -----------------
237
builtin/merge-tree.c
+19 -2
@@ -557,12 +557,29 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
557 while (strbuf_getline_lf(&buf, stdin) != EOF) {
558 struct strbuf **split;
559 int result;
560 + const char *input_merge_base = NULL;
561
562 split = strbuf_split(&buf, ' ');
562 - if (!split[0] || !split[1] || split[2])
563 + if (!split[0] || !split[1])
564 die(_("malformed input line: '%s'."), buf.buf);
565 strbuf_rtrim(split[0]);
565 - result = real_merge(&o, merge_base, split[0]->buf, split[1]->buf, prefix);
566 + strbuf_rtrim(split[1]);
567 +
568 + /* parse the merge-base */
569 + if (!strcmp(split[1]->buf, "--")) {
570 + input_merge_base = split[0]->buf;
571 + }
572 +
573 + if (input_merge_base && split[2] && split[3] && !split[4]) {
574 + strbuf_rtrim(split[2]);
575 + strbuf_rtrim(split[3]);
576 + result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
577 + } else if (!input_merge_base && !split[2]) {
578 + result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
579 + } else {
580 + die(_("malformed input line: '%s'."), buf.buf);
581 + }
582 +
583 if (result < 0)
584 die(_("merging cannot continue; got unclean result of %d"), result);
585 strbuf_list_free(split);
t/t4301-merge-tree-write-tree.sh
+35
@@ -860,6 +860,13 @@ test_expect_success '--stdin with both a successful and a conflicted merge' '
860 test_cmp expect actual
861 '
862
863 +
864 +test_expect_success '--merge-base is incompatible with --stdin' '
865 + test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
866 +
867 + grep "^fatal: --merge-base is incompatible with --stdin" expect
868 +'
869 +
870 # specify merge-base as parent of branch2
871 # git merge-tree --write-tree --merge-base=c2 c1 c3
872 # Commit c1: add file1
@@ -887,4 +894,32 @@ test_expect_success 'specify merge-base as parent of branch2' '
894 test_cmp expect actual
895 '
896
897 +# Since the earlier tests have verified that individual merge-tree calls
898 +# are doing the right thing, this test case is only used to verify that
899 +# we can also trigger merges via --stdin, and that when we do we get
900 +# the same answer as running a bunch of separate merges.
901 +
902 +test_expect_success 'check the input format when --stdin is passed' '
903 + test_when_finished "rm -rf repo" &&
904 + git init repo &&
905 + test_commit -C repo c1 &&
906 + test_commit -C repo c2 &&
907 + test_commit -C repo c3 &&
908 + printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
909 +
910 + printf "1\0" >expect &&
911 + git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
912 + printf "\0" >>expect &&
913 +
914 + printf "1\0" >>expect &&
915 + git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
916 + printf "\0" >>expect &&
917 +
918 + printf "1\0" >>expect &&
919 + git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
920 + printf "\0" >>expect &&
921 +
922 + test_cmp expect actual
923 +'
924 +
925 test_done