{"thread":{"id":"60495","subject":"[PATCH] merge-file: add --diff-algorithm option","startedAt":"2023-11-08T21:54:57Z","lastAt":"2023-11-21T14:58:53Z","messageCount":8,"participants":["Antonin Delpeuch via GitGitGadget","Antonin Delpeuch","Phillip Wood","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"484596","messageId":"pull.1606.git.git.1699480494355.gitgitgadget@gmail.com","threadId":"60495","inReplyTo":null,"subject":"[PATCH] merge-file: add --diff-algorithm option","fromName":"Antonin Delpeuch via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-08T21:54:54Z","receivedAt":"2023-11-08T21:54:57Z","isPatch":true,"sender":{"key":"antonin@delpeuch.eu","avatar":"https://avatars.githubusercontent.com/u/309908?v=4"},"body":"From: Antonin Delpeuch <antonin@delpeuch.eu>\n\nThis makes it possible to use other diff algorithms than the 'myers'\ndefault algorithm, when using the 'git merge-file' command.\n\nSigned-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\n---\n    merge-file: add --diff-algorithm option\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1606%2Fwetneb%2Fmerge_file_configurable_diff_algorithm-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1606/wetneb/merge_file_configurable_diff_algorithm-v1\nPull-Request: https://github.com/git/git/pull/1606\n\n Documentation/git-merge-file.txt |  5 +++++\n builtin/merge-file.c             | 28 ++++++++++++++++++++++++++++\n 2 files changed, 33 insertions(+)\n\ndiff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt\nindex 6a081eacb72..917535217c1 100644\n--- a/Documentation/git-merge-file.txt\n+++ b/Documentation/git-merge-file.txt\n@@ -92,6 +92,11 @@ object store and the object ID of its blob is written to standard output.\n \tInstead of leaving conflicts in the file, resolve conflicts\n \tfavouring our (or their or both) side of the lines.\n \n+--diff-algorithm <algorithm>::\n+\tUse a different diff algorithm while merging, which can help\n+\tavoid mismerges that occur due to unimportant matching lines\n+\t(such as braces from distinct functions).  See also\n+\tlinkgit:git-diff[1] `--diff-algorithm`.\n \n EXAMPLES\n --------\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex 832c93d8d54..1f987334a31 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"abspath.h\"\n+#include \"diff.h\"\n #include \"hex.h\"\n #include \"object-name.h\"\n #include \"object-store.h\"\n@@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+static int set_diff_algorithm(xpparam_t *xpp,\n+\t\t\t      const char *alg)\n+{\n+\tlong diff_algorithm = parse_algorithm_value(alg);\n+\tif (diff_algorithm < 0)\n+\t\treturn -1;\n+\txpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n+\treturn 0;\n+}\n+\n+static int diff_algorithm_cb(const struct option *opt,\n+\t\t\t\tconst char *arg, int unset)\n+{\n+\txpparam_t *xpp = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n+\tif (set_diff_algorithm(xpp, arg))\n+\t\treturn error(_(\"option diff-algorithm accepts \\\"myers\\\", \"\n+\t\t\t       \"\\\"minimal\\\", \\\"patience\\\" and \\\"histogram\\\"\"));\n+\n+\treturn 0;\n+}\n+\n int cmd_merge_file(int argc, const char **argv, const char *prefix)\n {\n \tconst char *names[3] = { 0 };\n@@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t    XDL_MERGE_FAVOR_THEIRS),\n \t\tOPT_SET_INT(0, \"union\", &xmp.favor, N_(\"for conflicts, use a union version\"),\n \t\t\t    XDL_MERGE_FAVOR_UNION),\n+\t\tOPT_CALLBACK_F(0, \"diff-algorithm\", &xmp.xpp, N_(\"<algorithm>\"),\n+\t\t\t     N_(\"choose a diff algorithm\"),\n+\t\t\t     PARSE_OPT_NONEG, diff_algorithm_cb),\n \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n \t\t\t    N_(\"for conflicts, use this marker size\")),\n \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\n\nbase-commit: 98009afd24e2304bf923a64750340423473809ff\n-- \ngitgitgadget\n"},{"id":"484998","messageId":"653b08fd-2df3-4a7a-8082-fdb809e87784@delpeuch.eu","threadId":"60495","inReplyTo":"pull.1606.git.git.1699480494355.gitgitgadget@gmail.com","subject":"Re: [PATCH] merge-file: add --diff-algorithm option","fromName":"Antonin Delpeuch","fromEmail":"antonin@delpeuch.eu","sentAt":"2023-11-17T21:42:05Z","receivedAt":"2023-11-17T21:47:10Z","isPatch":true,"sender":{"key":"antonin@delpeuch.eu","avatar":"https://avatars.githubusercontent.com/u/309908?v=4"},"body":"Hi all,\n\nHere a few more thoughts about this patch, to explain what brought me to \nneeding that. If this need is misguided, perhaps you could redirect me \nto a better solution.\n\nI am writing a custom merge driver for Java files. This merge driver \ninternally calls git-merge-file and then solves the merge conflicts \nwhich only consist of import statements (there might be cases where it \ngets it wrong, but I can then use other tools to cleanup those import \nstatements). When testing this, I noticed that the merge driver \nperformed more poorly on other sorts of conflicts, compared to the \nstandard \"ort\" merge strategy. This is because \"ort\" uses the \n\"histogram\" diff algorithm, which gives better results than the \"myers\" \ndiff algorithm that merge-file uses.\n\nIntuitively, if \"histogram\" is the default diff algorithm used by \"git \nmerge\", then it would also make sense to have the same default for \"git \nmerge-file\", but I assume that changing this default could be considered \na bad breaking change. So I thought that making this diff algorithm \nconfigurable would be an acceptable move, hence my patch.\n\nOf course, the diffing could be configured in other ways, for instance \nwith its handling of whitespace or EOL (similarly to what the \"git-diff\" \ncommand offers). I think those options would definitely be worth \nexposing in merge-file as well. If you think this makes sense, then I \nwould be happy to work on a new version of this patch which would \nattempt to include all the relevant options. I could also try to add the \ncorresponding tests.\n\nBut perhaps my need is misguided? Could it be that I should not be \nwriting a custom merge driver, but instead use another extension point \nto only process the conflicting hunks after execution of the existing \nmerge driver? I couldn't find such an extension point, but it can well \nbe that I missed it.\n\nThank you,\n\nAntonin\n\n"},{"id":"485004","messageId":"a83321f0-7184-4779-82d2-854a1e324f92@gmail.com","threadId":"60495","inReplyTo":"pull.1606.git.git.1699480494355.gitgitgadget@gmail.com","subject":"Re: [PATCH] merge-file: add --diff-algorithm option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-19T16:42:53Z","receivedAt":"2023-11-19T16:42:55Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Antonin\n\nOn 08/11/2023 21:54, Antonin Delpeuch via GitGitGadget wrote:\n> From: Antonin Delpeuch <antonin@delpeuch.eu>\n> \n> This makes it possible to use other diff algorithms than the 'myers'\n> default algorithm, when using the 'git merge-file' command.\n\nI think being able to select the diff algorithm is reasonable. I might \nbe nice to mention the use of \"git merge-file\" in custom merge drivers \nas a motivation in the commit message.\n\n> Signed-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\n> ---\n>      merge-file: add --diff-algorithm option\n> \n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1606%2Fwetneb%2Fmerge_file_configurable_diff_algorithm-v1\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1606/wetneb/merge_file_configurable_diff_algorithm-v1\n> Pull-Request: https://github.com/git/git/pull/1606\n> \n>   Documentation/git-merge-file.txt |  5 +++++\n>   builtin/merge-file.c             | 28 ++++++++++++++++++++++++++++\n>   2 files changed, 33 insertions(+)\n> \n> diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt\n> index 6a081eacb72..917535217c1 100644\n> --- a/Documentation/git-merge-file.txt\n> +++ b/Documentation/git-merge-file.txt\n> @@ -92,6 +92,11 @@ object store and the object ID of its blob is written to standard output.\n>   \tInstead of leaving conflicts in the file, resolve conflicts\n>   \tfavouring our (or their or both) side of the lines.\n>   \n> +--diff-algorithm <algorithm>::\n> +\tUse a different diff algorithm while merging, which can help\n> +\tavoid mismerges that occur due to unimportant matching lines\n> +\t(such as braces from distinct functions).  See also\n> +\tlinkgit:git-diff[1] `--diff-algorithm`.\n\nPerhaps we could list the available algorithms here so the user does not \nhave to go searching for them in another man page.\n\n>   EXAMPLES\n>   --------\n> diff --git a/builtin/merge-file.c b/builtin/merge-file.c\n> index 832c93d8d54..1f987334a31 100644\n> --- a/builtin/merge-file.c\n> +++ b/builtin/merge-file.c\n> @@ -1,5 +1,6 @@\n>   #include \"builtin.h\"\n>   #include \"abspath.h\"\n> +#include \"diff.h\"\n>   #include \"hex.h\"\n>   #include \"object-name.h\"\n>   #include \"object-store.h\"\n> @@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)\n>   \treturn 0;\n>   }\n>   \n> +static int set_diff_algorithm(xpparam_t *xpp,\n> +\t\t\t      const char *alg)\n> +{\n> +\tlong diff_algorithm = parse_algorithm_value(alg);\n> +\tif (diff_algorithm < 0)\n> +\t\treturn -1;\n> +\txpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n> +\treturn 0;\n> +}\n> +\n> +static int diff_algorithm_cb(const struct option *opt,\n> +\t\t\t\tconst char *arg, int unset)\n> +{\n> +\txpparam_t *xpp = opt->value;\n> +\n> +\tBUG_ON_OPT_NEG(unset);\n> +\n> +\tif (set_diff_algorithm(xpp, arg))\n> +\t\treturn error(_(\"option diff-algorithm accepts \\\"myers\\\", \"\n> +\t\t\t       \"\\\"minimal\\\", \\\"patience\\\" and \\\"histogram\\\"\"));\n> +\n> +\treturn 0;\n> +}\n> +\n>   int cmd_merge_file(int argc, const char **argv, const char *prefix)\n>   {\n>   \tconst char *names[3] = { 0 };\n> @@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n>   \t\t\t    XDL_MERGE_FAVOR_THEIRS),\n>   \t\tOPT_SET_INT(0, \"union\", &xmp.favor, N_(\"for conflicts, use a union version\"),\n>   \t\t\t    XDL_MERGE_FAVOR_UNION),\n> +\t\tOPT_CALLBACK_F(0, \"diff-algorithm\", &xmp.xpp, N_(\"<algorithm>\"),\n> +\t\t\t     N_(\"choose a diff algorithm\"),\n> +\t\t\t     PARSE_OPT_NONEG, diff_algorithm_cb),\n>   \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n>   \t\t\t    N_(\"for conflicts, use this marker size\")),\n>   \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\n\nThis patch looks sensible to me, it would be nice to have some tests though.\n\nBest Wishes\n\nPhillip\n\n> base-commit: 98009afd24e2304bf923a64750340423473809ff\n"},{"id":"485005","messageId":"de04aec0-a195-45da-8951-bb30f2a629a3@gmail.com","threadId":"60495","inReplyTo":"653b08fd-2df3-4a7a-8082-fdb809e87784@delpeuch.eu","subject":"Re: [PATCH] merge-file: add --diff-algorithm option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-19T16:43:19Z","receivedAt":"2023-11-19T16:43:22Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Antonin\n\nOn 17/11/2023 21:42, Antonin Delpeuch wrote:\n> Hi all,\n> \n> Here a few more thoughts about this patch, to explain what brought me to \n> needing that. If this need is misguided, perhaps you could redirect me \n> to a better solution.\n> \n> I am writing a custom merge driver for Java files. This merge driver \n> internally calls git-merge-file and then solves the merge conflicts \n> which only consist of import statements (there might be cases where it \n> gets it wrong, but I can then use other tools to cleanup those import \n> statements). When testing this, I noticed that the merge driver \n> performed more poorly on other sorts of conflicts, compared to the \n> standard \"ort\" merge strategy. This is because \"ort\" uses the \n> \"histogram\" diff algorithm, which gives better results than the \"myers\" \n> diff algorithm that merge-file uses.\n\nI cannot comment on this particular use but I think in general calling \n\"git merge-file\" from a custom merge driver is perfectly sensible. Have \nyou tested your driver with this patch to see if you get better results \nwith the histogram diff algorithm?\n\n> Intuitively, if \"histogram\" is the default diff algorithm used by \"git \n> merge\", then it would also make sense to have the same default for \"git \n> merge-file\", but I assume that changing this default could be considered \n> a bad breaking change. So I thought that making this diff algorithm \n> configurable would be an acceptable move, hence my patch.\n\nI can see there's an argument for changing the default algorithm of \"git \nmerge-file\" to match what \"ort\" uses. I know Elijah found the histogram \nalgorithm gave better results in his testing when he was developing \n\"ort\". While it would be a breaking change if on the average the new \ndefault gives better conflicts it might be worth it. This patch would \nmean that someone wanting to use the \"myers\" algorithm could still do so.\n\n> Of course, the diffing could be configured in other ways, for instance \n> with its handling of whitespace or EOL (similarly to what the \"git-diff\" \n> command offers). I think those options would definitely be worth \n> exposing in merge-file as well. If you think this makes sense, then I \n> would be happy to work on a new version of this patch which would \n> attempt to include all the relevant options. I could also try to add the \n> corresponding tests.\n\nIt would be nice to see some tests for this patch, ideally using a test \ncase that gives different conflicts for \"myers\" and \"histogram\". We \ncould add the other options later if there is a demand.\n\nBest Wishes\n\nPhillip\n\n> But perhaps my need is misguided? Could it be that I should not be \n> writing a custom merge driver, but instead use another extension point \n> to only process the conflicting hunks after execution of the existing \n> merge driver? I couldn't find such an extension point, but it can well \n> be that I missed it.\n> \n> Thank you,\n> \n> Antonin\n> \n> \n"},{"id":"485006","messageId":"5da59ea3-f814-4345-8206-856ae68be1c9@delpeuch.eu","threadId":"60495","inReplyTo":"de04aec0-a195-45da-8951-bb30f2a629a3@gmail.com","subject":"Re: [PATCH] merge-file: add --diff-algorithm option","fromName":"Antonin Delpeuch","fromEmail":"antonin@delpeuch.eu","sentAt":"2023-11-19T19:29:41Z","receivedAt":"2023-11-19T19:29:50Z","isPatch":true,"sender":{"key":"antonin@delpeuch.eu","avatar":"https://avatars.githubusercontent.com/u/309908?v=4"},"body":"Hi Phillip,\n\nThank you so much for taking the time to review this!\n\nOn 19/11/2023 17:43, Phillip Wood wrote:\n> I cannot comment on this particular use but I think in general calling \n> \"git merge-file\" from a custom merge driver is perfectly sensible. \n> Have you tested your driver with this patch to see if you get better \n> results with the histogram diff algorithm?\n\nYes, I can confirm that the results are better in my use case indeed.\n\n> I can see there's an argument for changing the default algorithm of \n> \"git merge-file\" to match what \"ort\" uses. I know Elijah found the \n> histogram algorithm gave better results in his testing when he was \n> developing \"ort\". While it would be a breaking change if on the \n> average the new default gives better conflicts it might be worth it. \n> This patch would mean that someone wanting to use the \"myers\" \n> algorithm could still do so.\n\nAgreed. I would be happy to submit a follow-up patch to change the \ndefault. Or would you prefer to have it in the same patch (as a separate \ncommit)? I was worried this would make my patch less likely to get merged.\n\n> It would be nice to see some tests for this patch, ideally using a \n> test case that gives different conflicts for \"myers\" and \"histogram\". \n> We could add the other options later if there is a demand.\n\nWill do.\n\n> Perhaps we could list the available algorithms here so the user does \n> not have to go searching for them in another man page.\n\nThis part is copied from \"Documentation/merge-strategies.txt\", which \nredirects to the manual for git-diff in the same way. I assume it was \ndone so that whenever a new diff algorithm is introduced, it only needs \ndocumenting in one place. But I agree it is definitely more \nuser-friendly to list the algorithms directly. Should I change the \ndocumentation of merge strategies in the same way?\n\nBest wishes,\n\nAntonin\n\n"},{"id":"485009","messageId":"xmqq7cmdpbhq.fsf@gitster.g","threadId":"60495","inReplyTo":"de04aec0-a195-45da-8951-bb30f2a629a3@gmail.com","subject":"Re: [PATCH] merge-file: add --diff-algorithm option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-19T23:30:25Z","receivedAt":"2023-11-19T23:30:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> I can see there's an argument for changing the default algorithm of\n> \"git merge-file\" to match what \"ort\" uses. I know Elijah found the\n> histogram algorithm gave better results in his testing when he was\n> developing \"ort\". While it would be a breaking change if on the\n> average the new default gives better conflicts it might be worth\n> it. This patch would mean that someone wanting to use the \"myers\"\n> algorithm could still do so.\n\nSounds like a sensible thing to do.  First allow to configure the\ncustom algorithm from the command line option (and optionally via a\nconfiguration variable) and ship it in a release, start giving a\nwarning if the using script did not specify the configuration or the\ncommand line option and used the current default and ship it in the\nnext release, wait for a few releases and then finally flip the\ndefault, or something like that.\n\nThanks.\n"},{"id":"485021","messageId":"pull.1606.v2.git.git.1700507932937.gitgitgadget@gmail.com","threadId":"60495","inReplyTo":"pull.1606.git.git.1699480494355.gitgitgadget@gmail.com","subject":"[PATCH v2] merge-file: add --diff-algorithm option","fromName":"Antonin Delpeuch via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-20T19:18:52Z","receivedAt":"2023-11-20T19:19:23Z","isPatch":true,"sender":{"key":"antonin@delpeuch.eu","avatar":"https://avatars.githubusercontent.com/u/309908?v=4"},"body":"From: Antonin Delpeuch <antonin@delpeuch.eu>\n\nThis makes it possible to use other diff algorithms than the 'myers'\ndefault algorithm, when using the 'git merge-file' command. This helps\navoid spurious conflicts by selecting a more recent algorithm such as\n'histogram', for instance when using 'git merge-file' as part of a custom\nmerge driver.\n\nSigned-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\nReviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n    merge-file: add --diff-algorithm option\n    \n    Changes since v1:\n    \n     * improve commit message to mention the use case of custom merge\n       drivers\n     * improve documentation to show available options and recommend\n       switching to \"histogram\"\n     * add tests\n    \n    I have left out:\n    \n     * switching the default to \"histogram\", because it should only be done\n       in a subsequent release\n     * adding a configuration variable to control this option, because I was\n       not sure how to call it. Perhaps \"merge-file.diffAlgorithm\"?\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1606%2Fwetneb%2Fmerge_file_configurable_diff_algorithm-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1606/wetneb/merge_file_configurable_diff_algorithm-v2\nPull-Request: https://github.com/git/git/pull/1606\n\nRange-diff vs v1:\n\n 1:  4aa453e30be ! 1:  842b5abf33c merge-file: add --diff-algorithm option\n     @@ Commit message\n          merge-file: add --diff-algorithm option\n      \n          This makes it possible to use other diff algorithms than the 'myers'\n     -    default algorithm, when using the 'git merge-file' command.\n     +    default algorithm, when using the 'git merge-file' command. This helps\n     +    avoid spurious conflicts by selecting a more recent algorithm such as\n     +    'histogram', for instance when using 'git merge-file' as part of a custom\n     +    merge driver.\n      \n          Signed-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\n     +    Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n      \n       ## Documentation/git-merge-file.txt ##\n      @@ Documentation/git-merge-file.txt: object store and the object ID of its blob is written to standard output.\n       \tInstead of leaving conflicts in the file, resolve conflicts\n       \tfavouring our (or their or both) side of the lines.\n       \n     -+--diff-algorithm <algorithm>::\n     -+\tUse a different diff algorithm while merging, which can help\n     ++--diff-algorithm={patience|minimal|histogram|myers}::\n     ++\tUse a different diff algorithm while merging. The current default is \"myers\",\n     ++\tbut selecting more recent algorithm such as \"histogram\" can help\n      +\tavoid mismerges that occur due to unimportant matching lines\n     -+\t(such as braces from distinct functions).  See also\n     ++\t(such as braces from distinct functions). See also\n      +\tlinkgit:git-diff[1] `--diff-algorithm`.\n       \n       EXAMPLES\n     @@ builtin/merge-file.c: int cmd_merge_file(int argc, const char **argv, const char\n       \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n       \t\t\t    N_(\"for conflicts, use this marker size\")),\n       \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\n     +\n     + ## t/t6403-merge-file.sh ##\n     +@@ t/t6403-merge-file.sh: test_expect_success 'setup' '\n     + \tdeduxit me super semitas jusitiae,\n     + \tEOF\n     + \n     +-\tprintf \"propter nomen suum.\" >>new4.txt\n     ++\tprintf \"propter nomen suum.\" >>new4.txt &&\n     ++\n     ++\tcat >base.c <<-\\EOF &&\n     ++\tint f(int x, int y)\n     ++\t{\n     ++\t\tif (x == 0)\n     ++\t\t{\n     ++\t\t\treturn y;\n     ++\t\t}\n     ++\t\treturn x;\n     ++\t}\n     ++\n     ++\tint g(size_t u)\n     ++\t{\n     ++\t\twhile (u < 30)\n     ++\t\t{\n     ++\t\t\tu++;\n     ++\t\t}\n     ++\t\treturn u;\n     ++\t}\n     ++\tEOF\n     ++\n     ++\tcat >ours.c <<-\\EOF &&\n     ++\tint g(size_t u)\n     ++\t{\n     ++\t\twhile (u < 30)\n     ++\t\t{\n     ++\t\t\tu++;\n     ++\t\t}\n     ++\t\treturn u;\n     ++\t}\n     ++\n     ++\tint h(int x, int y, int z)\n     ++\t{\n     ++\t\tif (z == 0)\n     ++\t\t{\n     ++\t\t\treturn x;\n     ++\t\t}\n     ++\t\treturn y;\n     ++\t}\n     ++\tEOF\n     ++\n     ++\tcat >theirs.c <<-\\EOF\n     ++\tint f(int x, int y)\n     ++\t{\n     ++\t\tif (x == 0)\n     ++\t\t{\n     ++\t\t\treturn y;\n     ++\t\t}\n     ++\t\treturn x;\n     ++\t}\n     ++\n     ++\tint g(size_t u)\n     ++\t{\n     ++\t\twhile (u > 34)\n     ++\t\t{\n     ++\t\t\tu--;\n     ++\t\t}\n     ++\t\treturn u;\n     ++\t}\n     ++\tEOF\n     + '\n     + \n     + test_expect_success 'merge with no changes' '\n     +@@ t/t6403-merge-file.sh: test_expect_success '--object-id fails without repository' '\n     + \tgrep \"not a git repository\" err\n     + '\n     + \n     ++test_expect_success 'merging C files with \"myers\" diff algorithm creates some spurious conflicts' '\n     ++\tcat >expect.c <<-\\EOF &&\n     ++\tint g(size_t u)\n     ++\t{\n     ++\t\twhile (u < 30)\n     ++\t\t{\n     ++\t\t\tu++;\n     ++\t\t}\n     ++\t\treturn u;\n     ++\t}\n     ++\n     ++\tint h(int x, int y, int z)\n     ++\t{\n     ++\t<<<<<<< ours.c\n     ++\t\tif (z == 0)\n     ++\t||||||| base.c\n     ++\t\twhile (u < 30)\n     ++\t=======\n     ++\t\twhile (u > 34)\n     ++\t>>>>>>> theirs.c\n     ++\t\t{\n     ++\t<<<<<<< ours.c\n     ++\t\t\treturn x;\n     ++\t||||||| base.c\n     ++\t\t\tu++;\n     ++\t=======\n     ++\t\t\tu--;\n     ++\t>>>>>>> theirs.c\n     ++\t\t}\n     ++\t\treturn y;\n     ++\t}\n     ++\tEOF\n     ++\n     ++\ttest_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&\n     ++\ttest_cmp expect.c myers_output.c\n     ++'\n     ++\n     ++test_expect_success 'merging C files with \"histogram\" diff algorithm avoids some spurious conflicts' '\n     ++\tcat >expect.c <<-\\EOF &&\n     ++\tint g(size_t u)\n     ++\t{\n     ++\t\twhile (u > 34)\n     ++\t\t{\n     ++\t\t\tu--;\n     ++\t\t}\n     ++\t\treturn u;\n     ++\t}\n     ++\n     ++\tint h(int x, int y, int z)\n     ++\t{\n     ++\t\tif (z == 0)\n     ++\t\t{\n     ++\t\t\treturn x;\n     ++\t\t}\n     ++\t\treturn y;\n     ++\t}\n     ++\tEOF\n     ++\n     ++\tgit merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&\n     ++\ttest_cmp expect.c histogram_output.c\n     ++'\n     ++\n     + test_done\n\n\n Documentation/git-merge-file.txt |   6 ++\n builtin/merge-file.c             |  28 +++++++\n t/t6403-merge-file.sh            | 124 ++++++++++++++++++++++++++++++-\n 3 files changed, 157 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt\nindex 6a081eacb72..71915a00fa4 100644\n--- a/Documentation/git-merge-file.txt\n+++ b/Documentation/git-merge-file.txt\n@@ -92,6 +92,12 @@ object store and the object ID of its blob is written to standard output.\n \tInstead of leaving conflicts in the file, resolve conflicts\n \tfavouring our (or their or both) side of the lines.\n \n+--diff-algorithm={patience|minimal|histogram|myers}::\n+\tUse a different diff algorithm while merging. The current default is \"myers\",\n+\tbut selecting more recent algorithm such as \"histogram\" can help\n+\tavoid mismerges that occur due to unimportant matching lines\n+\t(such as braces from distinct functions). See also\n+\tlinkgit:git-diff[1] `--diff-algorithm`.\n \n EXAMPLES\n --------\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex 832c93d8d54..1f987334a31 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"abspath.h\"\n+#include \"diff.h\"\n #include \"hex.h\"\n #include \"object-name.h\"\n #include \"object-store.h\"\n@@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+static int set_diff_algorithm(xpparam_t *xpp,\n+\t\t\t      const char *alg)\n+{\n+\tlong diff_algorithm = parse_algorithm_value(alg);\n+\tif (diff_algorithm < 0)\n+\t\treturn -1;\n+\txpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n+\treturn 0;\n+}\n+\n+static int diff_algorithm_cb(const struct option *opt,\n+\t\t\t\tconst char *arg, int unset)\n+{\n+\txpparam_t *xpp = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n+\tif (set_diff_algorithm(xpp, arg))\n+\t\treturn error(_(\"option diff-algorithm accepts \\\"myers\\\", \"\n+\t\t\t       \"\\\"minimal\\\", \\\"patience\\\" and \\\"histogram\\\"\"));\n+\n+\treturn 0;\n+}\n+\n int cmd_merge_file(int argc, const char **argv, const char *prefix)\n {\n \tconst char *names[3] = { 0 };\n@@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t    XDL_MERGE_FAVOR_THEIRS),\n \t\tOPT_SET_INT(0, \"union\", &xmp.favor, N_(\"for conflicts, use a union version\"),\n \t\t\t    XDL_MERGE_FAVOR_UNION),\n+\t\tOPT_CALLBACK_F(0, \"diff-algorithm\", &xmp.xpp, N_(\"<algorithm>\"),\n+\t\t\t     N_(\"choose a diff algorithm\"),\n+\t\t\t     PARSE_OPT_NONEG, diff_algorithm_cb),\n \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n \t\t\t    N_(\"for conflicts, use this marker size\")),\n \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\ndiff --git a/t/t6403-merge-file.sh b/t/t6403-merge-file.sh\nindex 2c92209ecab..fb872c5a113 100755\n--- a/t/t6403-merge-file.sh\n+++ b/t/t6403-merge-file.sh\n@@ -56,7 +56,67 @@ test_expect_success 'setup' '\n \tdeduxit me super semitas jusitiae,\n \tEOF\n \n-\tprintf \"propter nomen suum.\" >>new4.txt\n+\tprintf \"propter nomen suum.\" >>new4.txt &&\n+\n+\tcat >base.c <<-\\EOF &&\n+\tint f(int x, int y)\n+\t{\n+\t\tif (x == 0)\n+\t\t{\n+\t\t\treturn y;\n+\t\t}\n+\t\treturn x;\n+\t}\n+\n+\tint g(size_t u)\n+\t{\n+\t\twhile (u < 30)\n+\t\t{\n+\t\t\tu++;\n+\t\t}\n+\t\treturn u;\n+\t}\n+\tEOF\n+\n+\tcat >ours.c <<-\\EOF &&\n+\tint g(size_t u)\n+\t{\n+\t\twhile (u < 30)\n+\t\t{\n+\t\t\tu++;\n+\t\t}\n+\t\treturn u;\n+\t}\n+\n+\tint h(int x, int y, int z)\n+\t{\n+\t\tif (z == 0)\n+\t\t{\n+\t\t\treturn x;\n+\t\t}\n+\t\treturn y;\n+\t}\n+\tEOF\n+\n+\tcat >theirs.c <<-\\EOF\n+\tint f(int x, int y)\n+\t{\n+\t\tif (x == 0)\n+\t\t{\n+\t\t\treturn y;\n+\t\t}\n+\t\treturn x;\n+\t}\n+\n+\tint g(size_t u)\n+\t{\n+\t\twhile (u > 34)\n+\t\t{\n+\t\t\tu--;\n+\t\t}\n+\t\treturn u;\n+\t}\n+\tEOF\n '\n \n test_expect_success 'merge with no changes' '\n@@ -447,4 +507,66 @@ test_expect_success '--object-id fails without repository' '\n \tgrep \"not a git repository\" err\n '\n \n+test_expect_success 'merging C files with \"myers\" diff algorithm creates some spurious conflicts' '\n+\tcat >expect.c <<-\\EOF &&\n+\tint g(size_t u)\n+\t{\n+\t\twhile (u < 30)\n+\t\t{\n+\t\t\tu++;\n+\t\t}\n+\t\treturn u;\n+\t}\n+\n+\tint h(int x, int y, int z)\n+\t{\n+\t<<<<<<< ours.c\n+\t\tif (z == 0)\n+\t||||||| base.c\n+\t\twhile (u < 30)\n+\t=======\n+\t\twhile (u > 34)\n+\t>>>>>>> theirs.c\n+\t\t{\n+\t<<<<<<< ours.c\n+\t\t\treturn x;\n+\t||||||| base.c\n+\t\t\tu++;\n+\t=======\n+\t\t\tu--;\n+\t>>>>>>> theirs.c\n+\t\t}\n+\t\treturn y;\n+\t}\n+\tEOF\n+\n+\ttest_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&\n+\ttest_cmp expect.c myers_output.c\n+'\n+\n+test_expect_success 'merging C files with \"histogram\" diff algorithm avoids some spurious conflicts' '\n+\tcat >expect.c <<-\\EOF &&\n+\tint g(size_t u)\n+\t{\n+\t\twhile (u > 34)\n+\t\t{\n+\t\t\tu--;\n+\t\t}\n+\t\treturn u;\n+\t}\n+\n+\tint h(int x, int y, int z)\n+\t{\n+\t\tif (z == 0)\n+\t\t{\n+\t\t\treturn x;\n+\t\t}\n+\t\treturn y;\n+\t}\n+\tEOF\n+\n+\tgit merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&\n+\ttest_cmp expect.c histogram_output.c\n+'\n+\n test_done\n\nbase-commit: 98009afd24e2304bf923a64750340423473809ff\n-- \ngitgitgadget\n"},{"id":"485035","messageId":"4e06a674-e7b6-4be4-8f69-a8e83cce1bbb@gmail.com","threadId":"60495","inReplyTo":"pull.1606.v2.git.git.1700507932937.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] merge-file: add --diff-algorithm option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-21T14:58:50Z","receivedAt":"2023-11-21T14:58:53Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Antonin\n\nOn 20/11/2023 19:18, Antonin Delpeuch via GitGitGadget wrote:\n> From: Antonin Delpeuch <antonin@delpeuch.eu>\n> \n> This makes it possible to use other diff algorithms than the 'myers'\n> default algorithm, when using the 'git merge-file' command. This helps\n> avoid spurious conflicts by selecting a more recent algorithm such as\n> 'histogram', for instance when using 'git merge-file' as part of a custom\n> merge driver.\n> \n> Signed-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\n> Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis version looks good to me. Thanks for adding the tests and well done \nfor finding a test case that shows the benefits of changing the diff \nalgorithm so clearly.\n\nFor future reference note that the custom on this list is not to add \n\"Reviewed-by:\" unless the reviewer explicitly suggests it. In this case \nI'm happy for it to be left as is.\n\nBest Wishes\n\nPhillip\n\n> ---\n>      merge-file: add --diff-algorithm option\n>      \n>      Changes since v1:\n>      \n>       * improve commit message to mention the use case of custom merge\n>         drivers\n>       * improve documentation to show available options and recommend\n>         switching to \"histogram\"\n>       * add tests\n>      \n>      I have left out:\n>      \n>       * switching the default to \"histogram\", because it should only be done\n>         in a subsequent release\n>       * adding a configuration variable to control this option, because I was\n>         not sure how to call it. Perhaps \"merge-file.diffAlgorithm\"?\n> \n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1606%2Fwetneb%2Fmerge_file_configurable_diff_algorithm-v2\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1606/wetneb/merge_file_configurable_diff_algorithm-v2\n> Pull-Request: https://github.com/git/git/pull/1606\n> \n> Range-diff vs v1:\n> \n>   1:  4aa453e30be ! 1:  842b5abf33c merge-file: add --diff-algorithm option\n>       @@ Commit message\n>            merge-file: add --diff-algorithm option\n>        \n>            This makes it possible to use other diff algorithms than the 'myers'\n>       -    default algorithm, when using the 'git merge-file' command.\n>       +    default algorithm, when using the 'git merge-file' command. This helps\n>       +    avoid spurious conflicts by selecting a more recent algorithm such as\n>       +    'histogram', for instance when using 'git merge-file' as part of a custom\n>       +    merge driver.\n>        \n>            Signed-off-by: Antonin Delpeuch <antonin@delpeuch.eu>\n>       +    Reviewed-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>        \n>         ## Documentation/git-merge-file.txt ##\n>        @@ Documentation/git-merge-file.txt: object store and the object ID of its blob is written to standard output.\n>         \tInstead of leaving conflicts in the file, resolve conflicts\n>         \tfavouring our (or their or both) side of the lines.\n>         \n>       -+--diff-algorithm <algorithm>::\n>       -+\tUse a different diff algorithm while merging, which can help\n>       ++--diff-algorithm={patience|minimal|histogram|myers}::\n>       ++\tUse a different diff algorithm while merging. The current default is \"myers\",\n>       ++\tbut selecting more recent algorithm such as \"histogram\" can help\n>        +\tavoid mismerges that occur due to unimportant matching lines\n>       -+\t(such as braces from distinct functions).  See also\n>       ++\t(such as braces from distinct functions). See also\n>        +\tlinkgit:git-diff[1] `--diff-algorithm`.\n>         \n>         EXAMPLES\n>       @@ builtin/merge-file.c: int cmd_merge_file(int argc, const char **argv, const char\n>         \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n>         \t\t\t    N_(\"for conflicts, use this marker size\")),\n>         \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\n>       +\n>       + ## t/t6403-merge-file.sh ##\n>       +@@ t/t6403-merge-file.sh: test_expect_success 'setup' '\n>       + \tdeduxit me super semitas jusitiae,\n>       + \tEOF\n>       +\n>       +-\tprintf \"propter nomen suum.\" >>new4.txt\n>       ++\tprintf \"propter nomen suum.\" >>new4.txt &&\n>       ++\n>       ++\tcat >base.c <<-\\EOF &&\n>       ++\tint f(int x, int y)\n>       ++\t{\n>       ++\t\tif (x == 0)\n>       ++\t\t{\n>       ++\t\t\treturn y;\n>       ++\t\t}\n>       ++\t\treturn x;\n>       ++\t}\n>       ++\n>       ++\tint g(size_t u)\n>       ++\t{\n>       ++\t\twhile (u < 30)\n>       ++\t\t{\n>       ++\t\t\tu++;\n>       ++\t\t}\n>       ++\t\treturn u;\n>       ++\t}\n>       ++\tEOF\n>       ++\n>       ++\tcat >ours.c <<-\\EOF &&\n>       ++\tint g(size_t u)\n>       ++\t{\n>       ++\t\twhile (u < 30)\n>       ++\t\t{\n>       ++\t\t\tu++;\n>       ++\t\t}\n>       ++\t\treturn u;\n>       ++\t}\n>       ++\n>       ++\tint h(int x, int y, int z)\n>       ++\t{\n>       ++\t\tif (z == 0)\n>       ++\t\t{\n>       ++\t\t\treturn x;\n>       ++\t\t}\n>       ++\t\treturn y;\n>       ++\t}\n>       ++\tEOF\n>       ++\n>       ++\tcat >theirs.c <<-\\EOF\n>       ++\tint f(int x, int y)\n>       ++\t{\n>       ++\t\tif (x == 0)\n>       ++\t\t{\n>       ++\t\t\treturn y;\n>       ++\t\t}\n>       ++\t\treturn x;\n>       ++\t}\n>       ++\n>       ++\tint g(size_t u)\n>       ++\t{\n>       ++\t\twhile (u > 34)\n>       ++\t\t{\n>       ++\t\t\tu--;\n>       ++\t\t}\n>       ++\t\treturn u;\n>       ++\t}\n>       ++\tEOF\n>       + '\n>       +\n>       + test_expect_success 'merge with no changes' '\n>       +@@ t/t6403-merge-file.sh: test_expect_success '--object-id fails without repository' '\n>       + \tgrep \"not a git repository\" err\n>       + '\n>       +\n>       ++test_expect_success 'merging C files with \"myers\" diff algorithm creates some spurious conflicts' '\n>       ++\tcat >expect.c <<-\\EOF &&\n>       ++\tint g(size_t u)\n>       ++\t{\n>       ++\t\twhile (u < 30)\n>       ++\t\t{\n>       ++\t\t\tu++;\n>       ++\t\t}\n>       ++\t\treturn u;\n>       ++\t}\n>       ++\n>       ++\tint h(int x, int y, int z)\n>       ++\t{\n>       ++\t<<<<<<< ours.c\n>       ++\t\tif (z == 0)\n>       ++\t||||||| base.c\n>       ++\t\twhile (u < 30)\n>       ++\t=======\n>       ++\t\twhile (u > 34)\n>       ++\t>>>>>>> theirs.c\n>       ++\t\t{\n>       ++\t<<<<<<< ours.c\n>       ++\t\t\treturn x;\n>       ++\t||||||| base.c\n>       ++\t\t\tu++;\n>       ++\t=======\n>       ++\t\t\tu--;\n>       ++\t>>>>>>> theirs.c\n>       ++\t\t}\n>       ++\t\treturn y;\n>       ++\t}\n>       ++\tEOF\n>       ++\n>       ++\ttest_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&\n>       ++\ttest_cmp expect.c myers_output.c\n>       ++'\n>       ++\n>       ++test_expect_success 'merging C files with \"histogram\" diff algorithm avoids some spurious conflicts' '\n>       ++\tcat >expect.c <<-\\EOF &&\n>       ++\tint g(size_t u)\n>       ++\t{\n>       ++\t\twhile (u > 34)\n>       ++\t\t{\n>       ++\t\t\tu--;\n>       ++\t\t}\n>       ++\t\treturn u;\n>       ++\t}\n>       ++\n>       ++\tint h(int x, int y, int z)\n>       ++\t{\n>       ++\t\tif (z == 0)\n>       ++\t\t{\n>       ++\t\t\treturn x;\n>       ++\t\t}\n>       ++\t\treturn y;\n>       ++\t}\n>       ++\tEOF\n>       ++\n>       ++\tgit merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&\n>       ++\ttest_cmp expect.c histogram_output.c\n>       ++'\n>       ++\n>       + test_done\n> \n> \n>   Documentation/git-merge-file.txt |   6 ++\n>   builtin/merge-file.c             |  28 +++++++\n>   t/t6403-merge-file.sh            | 124 ++++++++++++++++++++++++++++++-\n>   3 files changed, 157 insertions(+), 1 deletion(-)\n> \n> diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt\n> index 6a081eacb72..71915a00fa4 100644\n> --- a/Documentation/git-merge-file.txt\n> +++ b/Documentation/git-merge-file.txt\n> @@ -92,6 +92,12 @@ object store and the object ID of its blob is written to standard output.\n>   \tInstead of leaving conflicts in the file, resolve conflicts\n>   \tfavouring our (or their or both) side of the lines.\n>   \n> +--diff-algorithm={patience|minimal|histogram|myers}::\n> +\tUse a different diff algorithm while merging. The current default is \"myers\",\n> +\tbut selecting more recent algorithm such as \"histogram\" can help\n> +\tavoid mismerges that occur due to unimportant matching lines\n> +\t(such as braces from distinct functions). See also\n> +\tlinkgit:git-diff[1] `--diff-algorithm`.\n>   \n>   EXAMPLES\n>   --------\n> diff --git a/builtin/merge-file.c b/builtin/merge-file.c\n> index 832c93d8d54..1f987334a31 100644\n> --- a/builtin/merge-file.c\n> +++ b/builtin/merge-file.c\n> @@ -1,5 +1,6 @@\n>   #include \"builtin.h\"\n>   #include \"abspath.h\"\n> +#include \"diff.h\"\n>   #include \"hex.h\"\n>   #include \"object-name.h\"\n>   #include \"object-store.h\"\n> @@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)\n>   \treturn 0;\n>   }\n>   \n> +static int set_diff_algorithm(xpparam_t *xpp,\n> +\t\t\t      const char *alg)\n> +{\n> +\tlong diff_algorithm = parse_algorithm_value(alg);\n> +\tif (diff_algorithm < 0)\n> +\t\treturn -1;\n> +\txpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n> +\treturn 0;\n> +}\n> +\n> +static int diff_algorithm_cb(const struct option *opt,\n> +\t\t\t\tconst char *arg, int unset)\n> +{\n> +\txpparam_t *xpp = opt->value;\n> +\n> +\tBUG_ON_OPT_NEG(unset);\n> +\n> +\tif (set_diff_algorithm(xpp, arg))\n> +\t\treturn error(_(\"option diff-algorithm accepts \\\"myers\\\", \"\n> +\t\t\t       \"\\\"minimal\\\", \\\"patience\\\" and \\\"histogram\\\"\"));\n> +\n> +\treturn 0;\n> +}\n> +\n>   int cmd_merge_file(int argc, const char **argv, const char *prefix)\n>   {\n>   \tconst char *names[3] = { 0 };\n> @@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n>   \t\t\t    XDL_MERGE_FAVOR_THEIRS),\n>   \t\tOPT_SET_INT(0, \"union\", &xmp.favor, N_(\"for conflicts, use a union version\"),\n>   \t\t\t    XDL_MERGE_FAVOR_UNION),\n> +\t\tOPT_CALLBACK_F(0, \"diff-algorithm\", &xmp.xpp, N_(\"<algorithm>\"),\n> +\t\t\t     N_(\"choose a diff algorithm\"),\n> +\t\t\t     PARSE_OPT_NONEG, diff_algorithm_cb),\n>   \t\tOPT_INTEGER(0, \"marker-size\", &xmp.marker_size,\n>   \t\t\t    N_(\"for conflicts, use this marker size\")),\n>   \t\tOPT__QUIET(&quiet, N_(\"do not warn about conflicts\")),\n> diff --git a/t/t6403-merge-file.sh b/t/t6403-merge-file.sh\n> index 2c92209ecab..fb872c5a113 100755\n> --- a/t/t6403-merge-file.sh\n> +++ b/t/t6403-merge-file.sh\n> @@ -56,7 +56,67 @@ test_expect_success 'setup' '\n>   \tdeduxit me super semitas jusitiae,\n>   \tEOF\n>   \n> -\tprintf \"propter nomen suum.\" >>new4.txt\n> +\tprintf \"propter nomen suum.\" >>new4.txt &&\n> +\n> +\tcat >base.c <<-\\EOF &&\n> +\tint f(int x, int y)\n> +\t{\n> +\t\tif (x == 0)\n> +\t\t{\n> +\t\t\treturn y;\n> +\t\t}\n> +\t\treturn x;\n> +\t}\n> +\n> +\tint g(size_t u)\n> +\t{\n> +\t\twhile (u < 30)\n> +\t\t{\n> +\t\t\tu++;\n> +\t\t}\n> +\t\treturn u;\n> +\t}\n> +\tEOF\n> +\n> +\tcat >ours.c <<-\\EOF &&\n> +\tint g(size_t u)\n> +\t{\n> +\t\twhile (u < 30)\n> +\t\t{\n> +\t\t\tu++;\n> +\t\t}\n> +\t\treturn u;\n> +\t}\n> +\n> +\tint h(int x, int y, int z)\n> +\t{\n> +\t\tif (z == 0)\n> +\t\t{\n> +\t\t\treturn x;\n> +\t\t}\n> +\t\treturn y;\n> +\t}\n> +\tEOF\n> +\n> +\tcat >theirs.c <<-\\EOF\n> +\tint f(int x, int y)\n> +\t{\n> +\t\tif (x == 0)\n> +\t\t{\n> +\t\t\treturn y;\n> +\t\t}\n> +\t\treturn x;\n> +\t}\n> +\n> +\tint g(size_t u)\n> +\t{\n> +\t\twhile (u > 34)\n> +\t\t{\n> +\t\t\tu--;\n> +\t\t}\n> +\t\treturn u;\n> +\t}\n> +\tEOF\n>   '\n>   \n>   test_expect_success 'merge with no changes' '\n> @@ -447,4 +507,66 @@ test_expect_success '--object-id fails without repository' '\n>   \tgrep \"not a git repository\" err\n>   '\n>   \n> +test_expect_success 'merging C files with \"myers\" diff algorithm creates some spurious conflicts' '\n> +\tcat >expect.c <<-\\EOF &&\n> +\tint g(size_t u)\n> +\t{\n> +\t\twhile (u < 30)\n> +\t\t{\n> +\t\t\tu++;\n> +\t\t}\n> +\t\treturn u;\n> +\t}\n> +\n> +\tint h(int x, int y, int z)\n> +\t{\n> +\t<<<<<<< ours.c\n> +\t\tif (z == 0)\n> +\t||||||| base.c\n> +\t\twhile (u < 30)\n> +\t=======\n> +\t\twhile (u > 34)\n> +\t>>>>>>> theirs.c\n> +\t\t{\n> +\t<<<<<<< ours.c\n> +\t\t\treturn x;\n> +\t||||||| base.c\n> +\t\t\tu++;\n> +\t=======\n> +\t\t\tu--;\n> +\t>>>>>>> theirs.c\n> +\t\t}\n> +\t\treturn y;\n> +\t}\n> +\tEOF\n> +\n> +\ttest_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&\n> +\ttest_cmp expect.c myers_output.c\n> +'\n> +\n> +test_expect_success 'merging C files with \"histogram\" diff algorithm avoids some spurious conflicts' '\n> +\tcat >expect.c <<-\\EOF &&\n> +\tint g(size_t u)\n> +\t{\n> +\t\twhile (u > 34)\n> +\t\t{\n> +\t\t\tu--;\n> +\t\t}\n> +\t\treturn u;\n> +\t}\n> +\n> +\tint h(int x, int y, int z)\n> +\t{\n> +\t\tif (z == 0)\n> +\t\t{\n> +\t\t\treturn x;\n> +\t\t}\n> +\t\treturn y;\n> +\t}\n> +\tEOF\n> +\n> +\tgit merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&\n> +\ttest_cmp expect.c histogram_output.c\n> +'\n> +\n>   test_done\n> \n> base-commit: 98009afd24e2304bf923a64750340423473809ff\n"}]}