{"thread":{"id":"62959","subject":"[PATCH 0/5] merge-tree --stdin: flush stdout","startedAt":"2025-02-16T16:37:13Z","lastAt":"2025-02-19T16:03:03Z","messageCount":25,"participants":["Phillip Wood via GitGitGadget","Elijah Newren","Phillip Wood","Junio C Hamano","Patrick Steinhardt"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"512484","messageId":"pull.1862.git.1739723829.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":null,"subject":"[PATCH 0/5] merge-tree --stdin: flush stdout","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:04Z","receivedAt":"2025-02-16T16:37:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"I tried to squash some fixup commits with \"git merge-tree --stdin\" and found\nthat my script deadlocked because the output of \"git merge-tree\" is not\nflushed after each merge. The first patch fixes that and the rest are\ncleanups I noticed while reading the code and documentation. This series is\nbased on maint.\n\nPhillip Wood (5):\n  merge-tree --stdin: flush stdout to avoid deadlock\n  merge-tree: remove redundant code\n  merge-tree: only use basic merge config\n  merge-tree: improve docs for --stdin\n  merge-tree: fix link formatting in html docs\n\n Documentation/git-merge-tree.txt | 11 ++++++++---\n builtin/merge-tree.c             | 11 +++++------\n 2 files changed, 13 insertions(+), 9 deletions(-)\n\n\nbase-commit: f93ff170b93a1782659637824b25923245ac9dd1\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1862%2Fphillipwood%2Fmerge-tree-flush-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1862/phillipwood/merge-tree-flush-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1862\n-- \ngitgitgadget\n"},{"id":"512485","messageId":"16fec87766f97d46a337f5c514f1aec0668546ec.1739723830.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH 2/5] merge-tree: remove redundant code","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:06Z","receivedAt":"2025-02-16T16:37:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nreal_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\nis less than zero. Therefore the check for \"result < 0\" is redundant and\nthe result variable is not needed.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 57f4340faba..3c73482f2b0 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -601,7 +601,6 @@ int cmd_merge_tree(int argc,\n \t\tline_termination = '\\0';\n \t\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\t\tstruct strbuf **split;\n-\t\t\tint result;\n \t\t\tconst char *input_merge_base = NULL;\n \n \t\t\tsplit = strbuf_split(&buf, ' ');\n@@ -618,16 +617,14 @@ int cmd_merge_tree(int argc,\n \t\t\tif (input_merge_base && split[2] && split[3] && !split[4]) {\n \t\t\t\tstrbuf_rtrim(split[2]);\n \t\t\t\tstrbuf_rtrim(split[3]);\n-\t\t\t\tresult = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n+\t\t\t\treal_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n \t\t\t} else if (!input_merge_base && !split[2]) {\n-\t\t\t\tresult = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n+\t\t\t\treal_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n \t\t\t} else {\n \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n \t\t\t}\n \t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \n-\t\t\tif (result < 0)\n-\t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n \t\t\tstrbuf_list_free(split);\n \t\t}\n \t\tstrbuf_release(&buf);\n-- \ngitgitgadget\n\n"},{"id":"512486","messageId":"3b3179785098580f3336bb24bdbaf0aa1366bfcd.1739723830.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:05Z","receivedAt":"2025-02-16T16:37:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIf a process tries to read the output from \"git merge-tree --stdin\"\nbefore it closes merge-tree's stdin then it deadlocks. This happens\nbecause merge-tree does not flush its output before trying to read\nanother line of input and means that it is not possible to cherry-pick a\nsequence of commits using \"git merge-tree --stdin\". Fix this by calling\nmaybe_flush_or_die() before trying to read the next line of\ninput. Flushing the output after each merge does not seem to affect the\nperformance, any difference is lost in the noise even after increasing\nthe number of runs.\n\n$ git rev-list --merges --parents -n100 origin/master |\n\tsed 's/^[^ ]* //' >/tmp/merges\n$ hyperfine -L flush 0,1 --warmup 1 --runs 30 \\\n\t'GIT_FLUSH={flush} ./git merge-tree --stdin </tmp/merges'\nBenchmark 1: GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges\n  Time (mean ± σ):     546.6 ms ±  11.7 ms    [User: 503.2 ms, System: 40.9 ms]\n  Range (min … max):   535.9 ms … 567.7 ms    30 runs\n\nBenchmark 2: GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges\n  Time (mean ± σ):     546.9 ms ±  12.0 ms    [User: 505.9 ms, System: 38.9 ms]\n  Range (min … max):   529.8 ms … 570.0 ms    30 runs\n\nSummary\n  'GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges' ran\n    1.00 ± 0.03 times faster than 'GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges'\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 9a6c8b4e4cf..57f4340faba 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -18,6 +18,7 @@\n #include \"tree.h\"\n #include \"config.h\"\n #include \"strvec.h\"\n+#include \"write-or-die.h\"\n \n static int line_termination = '\\n';\n \n@@ -623,6 +624,7 @@ int cmd_merge_tree(int argc,\n \t\t\t} else {\n \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n \t\t\t}\n+\t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \n \t\t\tif (result < 0)\n \t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n-- \ngitgitgadget\n\n"},{"id":"512489","messageId":"bf1dc603a153ed9e8a3e7b708ec99877048ab3e3.1739723830.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH 3/5] merge-tree: only use basic merge config","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:07Z","receivedAt":"2025-02-16T16:37:15Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nCommit 9c93ba4d0ae (merge-recursive: honor diff.algorithm, 2024-07-13)\nreplaced init_merge_options() with init_basic_merge_config() for use in\nplumbing commands and init_ui_merge_config() for use in porcelain\ncommands. As \"git merge-tree\" is a plumbing command it should call\ninit_basic_merge_config() rather than init_ui_merge_config(). The merge\nort machinery ignores \"diff.algorithm\" so the behavior is unchanged by\nthis commit but it future proofs us against any future changes to\ninit_ui_merge_config().\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 3c73482f2b0..3ec7127b3a6 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -576,7 +576,7 @@ int cmd_merge_tree(int argc,\n \t};\n \n \t/* Init merge options */\n-\tinit_ui_merge_options(&o.merge_options, the_repository);\n+\tinit_basic_merge_options(&o.merge_options, the_repository);\n \n \t/* Parse arguments */\n \toriginal_argc = argc - 1; /* ignoring argv[0] */\n-- \ngitgitgadget\n\n"},{"id":"512488","messageId":"4c4168506346fa3eed3d01445980044bce6c14ab.1739723830.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH 4/5] merge-tree: improve docs for --stdin","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:08Z","receivedAt":"2025-02-16T16:37:16Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAdd a section for --stdin in the list of options and document that it\nimplies -z so readers know how to parse the output. Also correct the\nmerge status documentation for --stdin as if the status is less than\nzero \"git merge-tree\" dies before printing it.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Documentation/git-merge-tree.txt | 8 ++++++--\n 1 file changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\nindex 0b6a8a19b1f..efb16b4f27d 100644\n--- a/Documentation/git-merge-tree.txt\n+++ b/Documentation/git-merge-tree.txt\n@@ -40,6 +40,11 @@ After the merge completes, a new toplevel tree object is created.  See\n OPTIONS\n -------\n \n+--stdin::\n+\tRead the commits to merge from the standard input rather than\n+\tthe command-line. See <<INPUT,INPUT FORMAT>> below for more\n+\tinformation.  Implies `-z`.\n+\n -z::\n \tDo not quote filenames in the <Conflicted file info> section,\n \tand end each filename with a NUL character rather than\n@@ -116,8 +121,6 @@ This is an integer status followed by a NUL character.  The integer status is:\n \n      0: merge had conflicts\n      1: merge was clean\n-     <0: something prevented the merge from running (e.g. access to repository\n-\t objects denied by filesystem)\n \n [[OIDTLT]]\n OID of toplevel tree\n@@ -235,6 +238,7 @@ with linkgit:git-merge[1]:\n   * any messages that would have been printed to stdout (the\n     <<IM,Informational messages>>)\n \n+[[INPUT]]\n INPUT FORMAT\n ------------\n 'git merge-tree --stdin' input format is fully text based. Each line\n-- \ngitgitgadget\n\n"},{"id":"512487","messageId":"89722894c875bc0208945c036700dba74cc0068f.1739723830.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH 5/5] merge-tree: fix link formatting in html docs","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-16T16:37:09Z","receivedAt":"2025-02-16T16:37:17Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn the html documentation the link to the \"OUTPUT\" section is surrounded\nby square brackets. Fix this by adding explicit link text to the cross\nreference.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Documentation/git-merge-tree.txt | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\nindex efb16b4f27d..cf0578f9b5e 100644\n--- a/Documentation/git-merge-tree.txt\n+++ b/Documentation/git-merge-tree.txt\n@@ -49,7 +49,8 @@ OPTIONS\n \tDo not quote filenames in the <Conflicted file info> section,\n \tand end each filename with a NUL character rather than\n \tnewline.  Also begin the messages section with a NUL character\n-\tinstead of a newline.  See <<OUTPUT>> below for more information.\n+\tinstead of a newline.  See <<OUTPUT,OUTPUT>> below for more\n+\tinformation.\n \n --name-only::\n \tIn the Conflicted file info section, instead of writing a list\n-- \ngitgitgadget\n"},{"id":"512543","messageId":"CABPp-BEPk+hozriBY687ELi7r-Y2JFy4rsxUCVejMt5wetHiqA@mail.gmail.com","threadId":"62959","inReplyTo":"3b3179785098580f3336bb24bdbaf0aa1366bfcd.1739723830.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-17T20:01:38Z","receivedAt":"2025-02-17T20:01:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> If a process tries to read the output from \"git merge-tree --stdin\"\n> before it closes merge-tree's stdin then it deadlocks. This happens\n> because merge-tree does not flush its output before trying to read\n> another line of input and means that it is not possible to cherry-pick a\n> sequence of commits using \"git merge-tree --stdin\". Fix this by calling\n> maybe_flush_or_die() before trying to read the next line of\n> input.\n\nMakes sense.\n\n> Flushing the output after each merge does not seem to affect the\n> performance, any difference is lost in the noise even after increasing\n> the number of runs.\n>\n> $ git rev-list --merges --parents -n100 origin/master |\n>         sed 's/^[^ ]* //' >/tmp/merges\n> $ hyperfine -L flush 0,1 --warmup 1 --runs 30 \\\n>         'GIT_FLUSH={flush} ./git merge-tree --stdin </tmp/merges'\n> Benchmark 1: GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges\n>   Time (mean ± σ):     546.6 ms ±  11.7 ms    [User: 503.2 ms, System: 40.9 ms]\n>   Range (min … max):   535.9 ms … 567.7 ms    30 runs\n>\n> Benchmark 2: GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges\n>   Time (mean ± σ):     546.9 ms ±  12.0 ms    [User: 505.9 ms, System: 38.9 ms]\n>   Range (min … max):   529.8 ms … 570.0 ms    30 runs\n>\n> Summary\n>   'GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges' ran\n>     1.00 ± 0.03 times faster than 'GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges'\n\nNice; thanks for checking and providing these stats.\n\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  builtin/merge-tree.c | 2 ++\n>  1 file changed, 2 insertions(+)\n>\n> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\n> index 9a6c8b4e4cf..57f4340faba 100644\n> --- a/builtin/merge-tree.c\n> +++ b/builtin/merge-tree.c\n> @@ -18,6 +18,7 @@\n>  #include \"tree.h\"\n>  #include \"config.h\"\n>  #include \"strvec.h\"\n> +#include \"write-or-die.h\"\n>\n>  static int line_termination = '\\n';\n>\n> @@ -623,6 +624,7 @@ int cmd_merge_tree(int argc,\n>                         } else {\n>                                 die(_(\"malformed input line: '%s'.\"), buf.buf);\n>                         }\n> +                       maybe_flush_or_die(stdout, \"stdout\");\n>\n>                         if (result < 0)\n>                                 die(_(\"merging cannot continue; got unclean result of %d\"), result);\n> --\n> gitgitgadget\n\nLooks good to me.\n"},{"id":"512544","messageId":"CABPp-BGTSciJMRWBGe9qOFh5wGuLppB6L+v9J5-KVdbNc6H3Hw@mail.gmail.com","threadId":"62959","inReplyTo":"16fec87766f97d46a337f5c514f1aec0668546ec.1739723830.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/5] merge-tree: remove redundant code","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-17T20:15:12Z","receivedAt":"2025-02-17T20:15:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> real_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\n> is less than zero. Therefore the check for \"result < 0\" is redundant and\n> the result variable is not needed.\n\nIndeed, the only return statement in real_merge(), occurring on the\nlast line of the function, is even:\n    return !result.clean; /* result.clean < 0 handled above */\n\nHowever, it might be worth adding to the commit message some comments\nabout o->use_stdin here.  When o->use_stdin is true, that the program\nexit status is 0 for both successful merges and conflicts but the\nconflict status for each individual commit is printed as part of the\noutput.  As such, the return status isn't used in those cases and\nreal_merge() might as well be a void function.  However, when\no->use_stdin is false, the exit status from real_merge is used, which\nis why that callsite (not visibile in this patch since it is\nunmodified) still pays attention to real_merge()'s return status.\n\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  builtin/merge-tree.c | 7 ++-----\n>  1 file changed, 2 insertions(+), 5 deletions(-)\n>\n> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\n> index 57f4340faba..3c73482f2b0 100644\n> --- a/builtin/merge-tree.c\n> +++ b/builtin/merge-tree.c\n> @@ -601,7 +601,6 @@ int cmd_merge_tree(int argc,\n>                 line_termination = '\\0';\n>                 while (strbuf_getline_lf(&buf, stdin) != EOF) {\n>                         struct strbuf **split;\n> -                       int result;\n>                         const char *input_merge_base = NULL;\n>\n>                         split = strbuf_split(&buf, ' ');\n> @@ -618,16 +617,14 @@ int cmd_merge_tree(int argc,\n>                         if (input_merge_base && split[2] && split[3] && !split[4]) {\n>                                 strbuf_rtrim(split[2]);\n>                                 strbuf_rtrim(split[3]);\n> -                               result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n> +                               real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n>                         } else if (!input_merge_base && !split[2]) {\n> -                               result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n> +                               real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n>                         } else {\n>                                 die(_(\"malformed input line: '%s'.\"), buf.buf);\n>                         }\n>                         maybe_flush_or_die(stdout, \"stdout\");\n>\n> -                       if (result < 0)\n> -                               die(_(\"merging cannot continue; got unclean result of %d\"), result);\n>                         strbuf_list_free(split);\n>                 }\n>                 strbuf_release(&buf);\n> --\n> gitgitgadget\n\nLooks good.\n"},{"id":"512545","messageId":"CABPp-BG13wHuUKLZ6xAJn7z44HbNoO=4D71cY48vmBUnpfoiTg@mail.gmail.com","threadId":"62959","inReplyTo":"4c4168506346fa3eed3d01445980044bce6c14ab.1739723830.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 4/5] merge-tree: improve docs for --stdin","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-17T20:26:51Z","receivedAt":"2025-02-17T20:27:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> Add a section for --stdin in the list of options and document that it\n> implies -z so readers know how to parse the output.\n\nMakes sense.\n\n> Also correct the\n> merge status documentation for --stdin as if the status is less than\n> zero \"git merge-tree\" dies before printing it.\n\nThis also makes sense, but...die'ing still has an exit status\nassociated with it right?\n\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  Documentation/git-merge-tree.txt | 8 ++++++--\n>  1 file changed, 6 insertions(+), 2 deletions(-)\n>\n> diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\n> index 0b6a8a19b1f..efb16b4f27d 100644\n> --- a/Documentation/git-merge-tree.txt\n> +++ b/Documentation/git-merge-tree.txt\n> @@ -40,6 +40,11 @@ After the merge completes, a new toplevel tree object is created.  See\n>  OPTIONS\n>  -------\n>\n> +--stdin::\n> +       Read the commits to merge from the standard input rather than\n> +       the command-line. See <<INPUT,INPUT FORMAT>> below for more\n> +       information.  Implies `-z`.\n> +\n>  -z::\n>         Do not quote filenames in the <Conflicted file info> section,\n>         and end each filename with a NUL character rather than\n> @@ -116,8 +121,6 @@ This is an integer status followed by a NUL character.  The integer status is:\n>\n>       0: merge had conflicts\n>       1: merge was clean\n> -     <0: something prevented the merge from running (e.g. access to repository\n> -        objects denied by filesystem)\n\nShould this line be kept but replace \"<0\" with \"128\" (the exit status of die)?\n\n>\n>  [[OIDTLT]]\n>  OID of toplevel tree\n> @@ -235,6 +238,7 @@ with linkgit:git-merge[1]:\n>    * any messages that would have been printed to stdout (the\n>      <<IM,Informational messages>>)\n>\n> +[[INPUT]]\n>  INPUT FORMAT\n>  ------------\n>  'git merge-tree --stdin' input format is fully text based. Each line\n> --\n> gitgitgadget\n"},{"id":"512546","messageId":"CABPp-BEQSsVUPUJyB+SqAsD89NFAzF_ibqOFqrs510kHX0u6xw@mail.gmail.com","threadId":"62959","inReplyTo":"89722894c875bc0208945c036700dba74cc0068f.1739723830.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 5/5] merge-tree: fix link formatting in html docs","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-17T20:30:39Z","receivedAt":"2025-02-17T20:30:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> In the html documentation the link to the \"OUTPUT\" section is surrounded\n> by square brackets. Fix this by adding explicit link text to the cross\n> reference.\n>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  Documentation/git-merge-tree.txt | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\n> index efb16b4f27d..cf0578f9b5e 100644\n> --- a/Documentation/git-merge-tree.txt\n> +++ b/Documentation/git-merge-tree.txt\n> @@ -49,7 +49,8 @@ OPTIONS\n>         Do not quote filenames in the <Conflicted file info> section,\n>         and end each filename with a NUL character rather than\n>         newline.  Also begin the messages section with a NUL character\n> -       instead of a newline.  See <<OUTPUT>> below for more information.\n> +       instead of a newline.  See <<OUTPUT,OUTPUT>> below for more\n> +       information.\n>\n>  --name-only::\n>         In the Conflicted file info section, instead of writing a list\n> --\n> gitgitgadget\n\nSeems to be the only line in git-merge-tree.txt matching <<.*>> which\nalso matches <<[,]*>>; i.e. looks like the only case that needed to be\nfixed.  Thanks for fixing it.\n"},{"id":"512584","messageId":"06582f75-c14c-482f-a9d8-b2c2e77ce2c8@gmail.com","threadId":"62959","inReplyTo":"CABPp-BGTSciJMRWBGe9qOFh5wGuLppB6L+v9J5-KVdbNc6H3Hw@mail.gmail.com","subject":"Re: [PATCH 2/5] merge-tree: remove redundant code","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-02-18T10:01:44Z","receivedAt":"2025-02-18T10:01:47Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 17/02/2025 20:15, Elijah Newren wrote:\n> On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n>>\n>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>> real_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\n>> is less than zero. Therefore the check for \"result < 0\" is redundant and\n>> the result variable is not needed.\n> \n> Indeed, the only return statement in real_merge(), occurring on the\n> last line of the function, is even:\n>      return !result.clean; /* result.clean < 0 handled above */\n> \n> However, it might be worth adding to the commit message some comments\n> about o->use_stdin here.  When o->use_stdin is true, that the program\n> exit status is 0 for both successful merges and conflicts but the\n> conflict status for each individual commit is printed as part of the\n> output.  As such, the return status isn't used in those cases and\n> real_merge() might as well be a void function.  However, when\n> o->use_stdin is false, the exit status from real_merge is used, which\n> is why that callsite (not visibile in this patch since it is\n> unmodified) still pays attention to real_merge()'s return status.\n\nThat's a good suggestion - I'll re-roll\n\nThanks\n\nPhillip\n\n>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>> ---\n>>   builtin/merge-tree.c | 7 ++-----\n>>   1 file changed, 2 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\n>> index 57f4340faba..3c73482f2b0 100644\n>> --- a/builtin/merge-tree.c\n>> +++ b/builtin/merge-tree.c\n>> @@ -601,7 +601,6 @@ int cmd_merge_tree(int argc,\n>>                  line_termination = '\\0';\n>>                  while (strbuf_getline_lf(&buf, stdin) != EOF) {\n>>                          struct strbuf **split;\n>> -                       int result;\n>>                          const char *input_merge_base = NULL;\n>>\n>>                          split = strbuf_split(&buf, ' ');\n>> @@ -618,16 +617,14 @@ int cmd_merge_tree(int argc,\n>>                          if (input_merge_base && split[2] && split[3] && !split[4]) {\n>>                                  strbuf_rtrim(split[2]);\n>>                                  strbuf_rtrim(split[3]);\n>> -                               result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n>> +                               real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n>>                          } else if (!input_merge_base && !split[2]) {\n>> -                               result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n>> +                               real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n>>                          } else {\n>>                                  die(_(\"malformed input line: '%s'.\"), buf.buf);\n>>                          }\n>>                          maybe_flush_or_die(stdout, \"stdout\");\n>>\n>> -                       if (result < 0)\n>> -                               die(_(\"merging cannot continue; got unclean result of %d\"), result);\n>>                          strbuf_list_free(split);\n>>                  }\n>>                  strbuf_release(&buf);\n>> --\n>> gitgitgadget\n> \n> Looks good.\n> \n\n"},{"id":"512585","messageId":"1b6ba7c4-56e2-4892-93d3-d57c7193432d@gmail.com","threadId":"62959","inReplyTo":"CABPp-BG13wHuUKLZ6xAJn7z44HbNoO=4D71cY48vmBUnpfoiTg@mail.gmail.com","subject":"Re: [PATCH 4/5] merge-tree: improve docs for --stdin","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-02-18T10:02:27Z","receivedAt":"2025-02-18T10:02:31Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 17/02/2025 20:26, Elijah Newren wrote:\n> On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n>>\n>> Also correct the\n>> merge status documentation for --stdin as if the status is less than\n>> zero \"git merge-tree\" dies before printing it.\n> \n> This also makes sense, but...die'ing still has an exit status\n> associated with it right?\n\nIt does, but that is documented in a separate section which says that if \nthere is an error it exits with a code that isn't 0 or 1. The section \nI've altered is documenting what \"git merge-tree --stdin\" prints to \nstdout and if result.clean is less than zero then it dies it does not \nprint anything to stdout.\n\nBest Wishes\n\nPhillip\n\n>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>> ---\n>>   Documentation/git-merge-tree.txt | 8 ++++++--\n>>   1 file changed, 6 insertions(+), 2 deletions(-)\n>>\n>> diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\n>> index 0b6a8a19b1f..efb16b4f27d 100644\n>> --- a/Documentation/git-merge-tree.txt\n>> +++ b/Documentation/git-merge-tree.txt\n>> @@ -40,6 +40,11 @@ After the merge completes, a new toplevel tree object is created.  See\n>>   OPTIONS\n>>   -------\n>>\n>> +--stdin::\n>> +       Read the commits to merge from the standard input rather than\n>> +       the command-line. See <<INPUT,INPUT FORMAT>> below for more\n>> +       information.  Implies `-z`.\n>> +\n>>   -z::\n>>          Do not quote filenames in the <Conflicted file info> section,\n>>          and end each filename with a NUL character rather than\n>> @@ -116,8 +121,6 @@ This is an integer status followed by a NUL character.  The integer status is:\n>>\n>>        0: merge had conflicts\n>>        1: merge was clean\n>> -     <0: something prevented the merge from running (e.g. access to repository\n>> -        objects denied by filesystem)\n> \n> Should this line be kept but replace \"<0\" with \"128\" (the exit status of die)?\n> \n>>\n>>   [[OIDTLT]]\n>>   OID of toplevel tree\n>> @@ -235,6 +238,7 @@ with linkgit:git-merge[1]:\n>>     * any messages that would have been printed to stdout (the\n>>       <<IM,Informational messages>>)\n>>\n>> +[[INPUT]]\n>>   INPUT FORMAT\n>>   ------------\n>>   'git merge-tree --stdin' input format is fully text based. Each line\n>> --\n>> gitgitgadget\n> \n\n"},{"id":"512608","messageId":"CABPp-BHqg45=yo4EPmYc9bFpB-wt8vaR1BCqksX1wgEQyq999w@mail.gmail.com","threadId":"62959","inReplyTo":"1b6ba7c4-56e2-4892-93d3-d57c7193432d@gmail.com","subject":"Re: [PATCH 4/5] merge-tree: improve docs for --stdin","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-18T15:56:07Z","receivedAt":"2025-02-18T15:56:19Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 18, 2025 at 2:02 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Elijah\n>\n> On 17/02/2025 20:26, Elijah Newren wrote:\n> > On Sun, Feb 16, 2025 at 8:37 AM Phillip Wood via GitGitGadget\n> > <gitgitgadget@gmail.com> wrote:\n> >>\n> >> Also correct the\n> >> merge status documentation for --stdin as if the status is less than\n> >> zero \"git merge-tree\" dies before printing it.\n> >\n> > This also makes sense, but...die'ing still has an exit status\n> > associated with it right?\n>\n> It does, but that is documented in a separate section which says that if\n> there is an error it exits with a code that isn't 0 or 1. The section\n> I've altered is documenting what \"git merge-tree --stdin\" prints to\n> stdout and if result.clean is less than zero then it dies it does not\n> print anything to stdout.\n>\n> Best Wishes\n>\n> Phillip\n\nOh, right, so your patch is good then.  Thanks for pointing out what I missed.\n"},{"id":"512611","messageId":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.git.1739723829.gitgitgadget@gmail.com","subject":"[PATCH v2 0/5] merge-tree --stdin: flush stdout","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:34Z","receivedAt":"2025-02-18T16:24:42Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Thanks to Elijah for his comments on V1. I've updated the commit message of\npatch 2 as he suggested. The rest of the patches are unchanged.\n\nV1 Cover Letter:\n\nI tried to squash some fixup commits with \"git merge-tree --stdin\" and found\nthat my script deadlocked because the output of \"git merge-tree\" is not\nflushed after each merge. The first patch fixes that and the rest are\ncleanups I noticed while reading the code and documentation. This series is\nbased on maint.\n\nPhillip Wood (5):\n  merge-tree --stdin: flush stdout to avoid deadlock\n  merge-tree: remove redundant code\n  merge-tree: only use basic merge config\n  merge-tree: improve docs for --stdin\n  merge-tree: fix link formatting in html docs\n\n Documentation/git-merge-tree.txt | 11 ++++++++---\n builtin/merge-tree.c             | 11 +++++------\n 2 files changed, 13 insertions(+), 9 deletions(-)\n\n\nbase-commit: f93ff170b93a1782659637824b25923245ac9dd1\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1862%2Fphillipwood%2Fmerge-tree-flush-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1862/phillipwood/merge-tree-flush-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1862\n\nRange-diff vs v1:\n\n 1:  3b317978509 = 1:  3b317978509 merge-tree --stdin: flush stdout to avoid deadlock\n 2:  16fec87766f ! 2:  63b09dbe1b7 merge-tree: remove redundant code\n     @@ Commit message\n      \n          real_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\n          is less than zero. Therefore the check for \"result < 0\" is redundant and\n     -    the result variable is not needed.\n     +    the result variable is not needed. The return value of real_merge() is\n     +    ignored because exit status of \"git merge-tree --stdin\" is \"0\" for both\n     +    successful and conflicted merges (the status of each merge is written to\n     +    stdout). The return type of real_merge() is not changed as it is used\n     +    for the program's exit status when \"--stdin\" is not given.\n      \n          Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n      \n 3:  bf1dc603a15 = 3:  f95a15a4203 merge-tree: only use basic merge config\n 4:  4c416850634 = 4:  1645b0e747e merge-tree: improve docs for --stdin\n 5:  89722894c87 = 5:  a0179820092 merge-tree: fix link formatting in html docs\n\n-- \ngitgitgadget\n"},{"id":"512612","messageId":"3b3179785098580f3336bb24bdbaf0aa1366bfcd.1739895879.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"[PATCH v2 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:35Z","receivedAt":"2025-02-18T16:24:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIf a process tries to read the output from \"git merge-tree --stdin\"\nbefore it closes merge-tree's stdin then it deadlocks. This happens\nbecause merge-tree does not flush its output before trying to read\nanother line of input and means that it is not possible to cherry-pick a\nsequence of commits using \"git merge-tree --stdin\". Fix this by calling\nmaybe_flush_or_die() before trying to read the next line of\ninput. Flushing the output after each merge does not seem to affect the\nperformance, any difference is lost in the noise even after increasing\nthe number of runs.\n\n$ git rev-list --merges --parents -n100 origin/master |\n\tsed 's/^[^ ]* //' >/tmp/merges\n$ hyperfine -L flush 0,1 --warmup 1 --runs 30 \\\n\t'GIT_FLUSH={flush} ./git merge-tree --stdin </tmp/merges'\nBenchmark 1: GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges\n  Time (mean ± σ):     546.6 ms ±  11.7 ms    [User: 503.2 ms, System: 40.9 ms]\n  Range (min … max):   535.9 ms … 567.7 ms    30 runs\n\nBenchmark 2: GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges\n  Time (mean ± σ):     546.9 ms ±  12.0 ms    [User: 505.9 ms, System: 38.9 ms]\n  Range (min … max):   529.8 ms … 570.0 ms    30 runs\n\nSummary\n  'GIT_FLUSH=0 ./git merge-tree --stdin </tmp/merges' ran\n    1.00 ± 0.03 times faster than 'GIT_FLUSH=1 ./git merge-tree --stdin </tmp/merges'\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 9a6c8b4e4cf..57f4340faba 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -18,6 +18,7 @@\n #include \"tree.h\"\n #include \"config.h\"\n #include \"strvec.h\"\n+#include \"write-or-die.h\"\n \n static int line_termination = '\\n';\n \n@@ -623,6 +624,7 @@ int cmd_merge_tree(int argc,\n \t\t\t} else {\n \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n \t\t\t}\n+\t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \n \t\t\tif (result < 0)\n \t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n-- \ngitgitgadget\n\n"},{"id":"512613","messageId":"63b09dbe1b7bc7c671526288e302051e5f447552.1739895879.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"[PATCH v2 2/5] merge-tree: remove redundant code","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:36Z","receivedAt":"2025-02-18T16:24:44Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nreal_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\nis less than zero. Therefore the check for \"result < 0\" is redundant and\nthe result variable is not needed. The return value of real_merge() is\nignored because exit status of \"git merge-tree --stdin\" is \"0\" for both\nsuccessful and conflicted merges (the status of each merge is written to\nstdout). The return type of real_merge() is not changed as it is used\nfor the program's exit status when \"--stdin\" is not given.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 57f4340faba..3c73482f2b0 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -601,7 +601,6 @@ int cmd_merge_tree(int argc,\n \t\tline_termination = '\\0';\n \t\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\t\tstruct strbuf **split;\n-\t\t\tint result;\n \t\t\tconst char *input_merge_base = NULL;\n \n \t\t\tsplit = strbuf_split(&buf, ' ');\n@@ -618,16 +617,14 @@ int cmd_merge_tree(int argc,\n \t\t\tif (input_merge_base && split[2] && split[3] && !split[4]) {\n \t\t\t\tstrbuf_rtrim(split[2]);\n \t\t\t\tstrbuf_rtrim(split[3]);\n-\t\t\t\tresult = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n+\t\t\t\treal_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);\n \t\t\t} else if (!input_merge_base && !split[2]) {\n-\t\t\t\tresult = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n+\t\t\t\treal_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);\n \t\t\t} else {\n \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n \t\t\t}\n \t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \n-\t\t\tif (result < 0)\n-\t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n \t\t\tstrbuf_list_free(split);\n \t\t}\n \t\tstrbuf_release(&buf);\n-- \ngitgitgadget\n\n"},{"id":"512614","messageId":"f95a15a42037ac3f523c15f460ecd325331bc5b7.1739895879.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"[PATCH v2 3/5] merge-tree: only use basic merge config","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:37Z","receivedAt":"2025-02-18T16:24:45Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nCommit 9c93ba4d0ae (merge-recursive: honor diff.algorithm, 2024-07-13)\nreplaced init_merge_options() with init_basic_merge_config() for use in\nplumbing commands and init_ui_merge_config() for use in porcelain\ncommands. As \"git merge-tree\" is a plumbing command it should call\ninit_basic_merge_config() rather than init_ui_merge_config(). The merge\nort machinery ignores \"diff.algorithm\" so the behavior is unchanged by\nthis commit but it future proofs us against any future changes to\ninit_ui_merge_config().\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/merge-tree.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 3c73482f2b0..3ec7127b3a6 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -576,7 +576,7 @@ int cmd_merge_tree(int argc,\n \t};\n \n \t/* Init merge options */\n-\tinit_ui_merge_options(&o.merge_options, the_repository);\n+\tinit_basic_merge_options(&o.merge_options, the_repository);\n \n \t/* Parse arguments */\n \toriginal_argc = argc - 1; /* ignoring argv[0] */\n-- \ngitgitgadget\n\n"},{"id":"512615","messageId":"1645b0e747e9bd65147bb0bc4123cfa32ca68818.1739895879.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"[PATCH v2 4/5] merge-tree: improve docs for --stdin","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:38Z","receivedAt":"2025-02-18T16:24:46Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAdd a section for --stdin in the list of options and document that it\nimplies -z so readers know how to parse the output. Also correct the\nmerge status documentation for --stdin as if the status is less than\nzero \"git merge-tree\" dies before printing it.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Documentation/git-merge-tree.txt | 8 ++++++--\n 1 file changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\nindex 0b6a8a19b1f..efb16b4f27d 100644\n--- a/Documentation/git-merge-tree.txt\n+++ b/Documentation/git-merge-tree.txt\n@@ -40,6 +40,11 @@ After the merge completes, a new toplevel tree object is created.  See\n OPTIONS\n -------\n \n+--stdin::\n+\tRead the commits to merge from the standard input rather than\n+\tthe command-line. See <<INPUT,INPUT FORMAT>> below for more\n+\tinformation.  Implies `-z`.\n+\n -z::\n \tDo not quote filenames in the <Conflicted file info> section,\n \tand end each filename with a NUL character rather than\n@@ -116,8 +121,6 @@ This is an integer status followed by a NUL character.  The integer status is:\n \n      0: merge had conflicts\n      1: merge was clean\n-     <0: something prevented the merge from running (e.g. access to repository\n-\t objects denied by filesystem)\n \n [[OIDTLT]]\n OID of toplevel tree\n@@ -235,6 +238,7 @@ with linkgit:git-merge[1]:\n   * any messages that would have been printed to stdout (the\n     <<IM,Informational messages>>)\n \n+[[INPUT]]\n INPUT FORMAT\n ------------\n 'git merge-tree --stdin' input format is fully text based. Each line\n-- \ngitgitgadget\n\n"},{"id":"512616","messageId":"a017982009267da5157d314a7d3061bac60ea8af.1739895879.git.gitgitgadget@gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"[PATCH v2 5/5] merge-tree: fix link formatting in html docs","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-02-18T16:24:39Z","receivedAt":"2025-02-18T16:24:46Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn the html documentation the link to the \"OUTPUT\" section is surrounded\nby square brackets. Fix this by adding explicit link text to the cross\nreference.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Documentation/git-merge-tree.txt | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt\nindex efb16b4f27d..cf0578f9b5e 100644\n--- a/Documentation/git-merge-tree.txt\n+++ b/Documentation/git-merge-tree.txt\n@@ -49,7 +49,8 @@ OPTIONS\n \tDo not quote filenames in the <Conflicted file info> section,\n \tand end each filename with a NUL character rather than\n \tnewline.  Also begin the messages section with a NUL character\n-\tinstead of a newline.  See <<OUTPUT>> below for more information.\n+\tinstead of a newline.  See <<OUTPUT,OUTPUT>> below for more\n+\tinformation.\n \n --name-only::\n \tIn the Conflicted file info section, instead of writing a list\n-- \ngitgitgadget\n"},{"id":"512617","messageId":"CABPp-BE3NtP463P4R+stzcQ_MufjobL-CX-rB=0m5gC0DzA9ww@mail.gmail.com","threadId":"62959","inReplyTo":"pull.1862.v2.git.1739895879.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/5] merge-tree --stdin: flush stdout","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-02-18T16:46:50Z","receivedAt":"2025-02-18T16:47:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 18, 2025 at 8:24 AM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> Thanks to Elijah for his comments on V1. I've updated the commit message of\n> patch 2 as he suggested. The rest of the patches are unchanged.\n>\n> V1 Cover Letter:\n>\n> I tried to squash some fixup commits with \"git merge-tree --stdin\" and found\n> that my script deadlocked because the output of \"git merge-tree\" is not\n> flushed after each merge. The first patch fixes that and the rest are\n> cleanups I noticed while reading the code and documentation. This series is\n> based on maint.\n>\n> Phillip Wood (5):\n>   merge-tree --stdin: flush stdout to avoid deadlock\n>   merge-tree: remove redundant code\n>   merge-tree: only use basic merge config\n>   merge-tree: improve docs for --stdin\n>   merge-tree: fix link formatting in html docs\n>\n>  Documentation/git-merge-tree.txt | 11 ++++++++---\n>  builtin/merge-tree.c             | 11 +++++------\n>  2 files changed, 13 insertions(+), 9 deletions(-)\n>\n>\n> base-commit: f93ff170b93a1782659637824b25923245ac9dd1\n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1862%2Fphillipwood%2Fmerge-tree-flush-v2\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1862/phillipwood/merge-tree-flush-v2\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1862\n>\n> Range-diff vs v1:\n>\n>  1:  3b317978509 = 1:  3b317978509 merge-tree --stdin: flush stdout to avoid deadlock\n>  2:  16fec87766f ! 2:  63b09dbe1b7 merge-tree: remove redundant code\n>      @@ Commit message\n>\n>           real_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\n>           is less than zero. Therefore the check for \"result < 0\" is redundant and\n>      -    the result variable is not needed.\n>      +    the result variable is not needed. The return value of real_merge() is\n>      +    ignored because exit status of \"git merge-tree --stdin\" is \"0\" for both\n>      +    successful and conflicted merges (the status of each merge is written to\n>      +    stdout). The return type of real_merge() is not changed as it is used\n>      +    for the program's exit status when \"--stdin\" is not given.\n>\n>           Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n>  3:  bf1dc603a15 = 3:  f95a15a4203 merge-tree: only use basic merge config\n>  4:  4c416850634 = 4:  1645b0e747e merge-tree: improve docs for --stdin\n>  5:  89722894c87 = 5:  a0179820092 merge-tree: fix link formatting in html docs\n\nThis round looks good to me; thanks.\n"},{"id":"512619","messageId":"a0281e37-d025-4ef4-89dc-49d5f88c0ef0@gmail.com","threadId":"62959","inReplyTo":"CABPp-BE3NtP463P4R+stzcQ_MufjobL-CX-rB=0m5gC0DzA9ww@mail.gmail.com","subject":"Re: [PATCH v2 0/5] merge-tree --stdin: flush stdout","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-02-18T16:54:26Z","receivedAt":"2025-02-18T16:54:30Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 18/02/2025 16:46, Elijah Newren wrote:\n> On Tue, Feb 18, 2025 at 8:24 AM Phillip Wood via GitGitGadget\n>> Range-diff vs v1:\n>>\n>>   1:  3b317978509 = 1:  3b317978509 merge-tree --stdin: flush stdout to avoid deadlock\n>>   2:  16fec87766f ! 2:  63b09dbe1b7 merge-tree: remove redundant code\n>>       @@ Commit message\n>>\n>>            real_merge() only ever returns \"0\" or \"1\" as it dies if the merge status\n>>            is less than zero. Therefore the check for \"result < 0\" is redundant and\n>>       -    the result variable is not needed.\n>>       +    the result variable is not needed. The return value of real_merge() is\n>>       +    ignored because exit status of \"git merge-tree --stdin\" is \"0\" for both\n>>       +    successful and conflicted merges (the status of each merge is written to\n>>       +    stdout). The return type of real_merge() is not changed as it is used\n>>       +    for the program's exit status when \"--stdin\" is not given.\n>>\n>>            Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>>   3:  bf1dc603a15 = 3:  f95a15a4203 merge-tree: only use basic merge config\n>>   4:  4c416850634 = 4:  1645b0e747e merge-tree: improve docs for --stdin\n>>   5:  89722894c87 = 5:  a0179820092 merge-tree: fix link formatting in html docs\n> \n> This round looks good to me; thanks.\n\nThat's great, thanks very much for reviewing these patches\n\nBest Wishes\n\nPhillip\n"},{"id":"512638","messageId":"xmqqtt8rjbb0.fsf@gitster.g","threadId":"62959","inReplyTo":"CABPp-BE3NtP463P4R+stzcQ_MufjobL-CX-rB=0m5gC0DzA9ww@mail.gmail.com","subject":"Re: [PATCH v2 0/5] merge-tree --stdin: flush stdout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-02-18T19:35:31Z","receivedAt":"2025-02-18T19:35:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Tue, Feb 18, 2025 at 8:24 AM Phillip Wood via GitGitGadget\n> ...\n>>  3:  bf1dc603a15 = 3:  f95a15a4203 merge-tree: only use basic merge config\n>>  4:  4c416850634 = 4:  1645b0e747e merge-tree: improve docs for --stdin\n>>  5:  89722894c87 = 5:  a0179820092 merge-tree: fix link formatting in html docs\n>\n> This round looks good to me; thanks.\n\nThanks, both.  Queued.\n"},{"id":"512654","messageId":"Z7V48_q3Uu9d0D3Q@pks.im","threadId":"62959","inReplyTo":"3b3179785098580f3336bb24bdbaf0aa1366bfcd.1739895879.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-02-19T06:23:47Z","receivedAt":"2025-02-19T06:23:57Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Feb 18, 2025 at 04:24:35PM +0000, Phillip Wood via GitGitGadget wrote:\n> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\n> index 9a6c8b4e4cf..57f4340faba 100644\n> --- a/builtin/merge-tree.c\n> +++ b/builtin/merge-tree.c\n> @@ -18,6 +18,7 @@\n>  #include \"tree.h\"\n>  #include \"config.h\"\n>  #include \"strvec.h\"\n> +#include \"write-or-die.h\"\n>  \n>  static int line_termination = '\\n';\n>  \n> @@ -623,6 +624,7 @@ int cmd_merge_tree(int argc,\n>  \t\t\t} else {\n>  \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n>  \t\t\t}\n> +\t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n>  \n>  \t\t\tif (result < 0)\n>  \t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n\nI was briefly wondering whether we should rather move this into\n`real_merge()` itself, which is responsible for writing to stdout. But\nthe only other callsite doesn't really care as it will exit immediately\nanyway. So this is probably fine.\n\nOverall the series looks good to me, thanks!\n\nPatrick\n"},{"id":"512713","messageId":"49dc31a3-bdf4-4abb-85f6-2a80dbe18cad@gmail.com","threadId":"62959","inReplyTo":"Z7V48_q3Uu9d0D3Q@pks.im","subject":"Re: [PATCH v2 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-02-19T14:55:29Z","receivedAt":"2025-02-19T14:55:34Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Patrick\n\nOn 19/02/2025 06:23, Patrick Steinhardt wrote:\n> \n> I was briefly wondering whether we should rather move this into\n> `real_merge()` itself, which is responsible for writing to stdout. But\n> the only other callsite doesn't really care as it will exit immediately\n> anyway. So this is probably fine.\n\nI did wonder about that when I was writing the patch but decided it only \nmattered when --stdin was given.\n\n> Overall the series looks good to me, thanks!\n\nThanks\n\nPhillip\n\n"},{"id":"512715","messageId":"xmqqseo9hqh8.fsf@gitster.g","threadId":"62959","inReplyTo":"Z7V48_q3Uu9d0D3Q@pks.im","subject":"Re: [PATCH v2 1/5] merge-tree --stdin: flush stdout to avoid deadlock","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-02-19T16:02:59Z","receivedAt":"2025-02-19T16:03:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Tue, Feb 18, 2025 at 04:24:35PM +0000, Phillip Wood via GitGitGadget wrote:\n>> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\n>> index 9a6c8b4e4cf..57f4340faba 100644\n>> --- a/builtin/merge-tree.c\n>> +++ b/builtin/merge-tree.c\n>> @@ -18,6 +18,7 @@\n>>  #include \"tree.h\"\n>>  #include \"config.h\"\n>>  #include \"strvec.h\"\n>> +#include \"write-or-die.h\"\n>>  \n>>  static int line_termination = '\\n';\n>>  \n>> @@ -623,6 +624,7 @@ int cmd_merge_tree(int argc,\n>>  \t\t\t} else {\n>>  \t\t\t\tdie(_(\"malformed input line: '%s'.\"), buf.buf);\n>>  \t\t\t}\n>> +\t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n>>  \n>>  \t\t\tif (result < 0)\n>>  \t\t\t\tdie(_(\"merging cannot continue; got unclean result of %d\"), result);\n>\n> I was briefly wondering whether we should rather move this into\n> `real_merge()` itself, which is responsible for writing to stdout.\n\nIndeed.  Its \"if we are working stdin mode, emit a line break\" near\nthe end does hint that the original intent was to ensure the output\ngoes out before we return to read more (even though the code forgets\nthat the stdio layer buffers), so it doubly makes sense to place the\nlogic to flush before the function returns, no?\n\n> But\n> the only other callsite doesn't really care as it will exit immediately\n> anyway. So this is probably fine.\n\nWith the current set of callers, yes.  When we write these\nsentences, our imagination most likely fails short to come up with a\nreason why the next callsite needs to be added to the program, so I\nwould strongly suggest flushing inside real_merge() IF it were a\npublic function, but because it is a file-scope static helper, we\nhopefully will remember we would need to add a flush to the caller\nwhen we add the fourth caller.  So I do not care too deeply either\nway.\n\n> Overall the series looks good to me, thanks!\n\nThanks, all.  Let's mark it for 'next'.\n\n"}]}