{"thread":{"id":"63226","subject":"[PATCH 0/8] Debug merge-recursive.[ch]","startedAt":"2025-03-31T15:51:23Z","lastAt":"2025-04-08T15:48:54Z","messageCount":31,"participants":["Elijah Newren via GitGitGadget","Eric Sunshine","Elijah Newren","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"515378","messageId":"pull.1898.git.1743436279.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":null,"subject":"[PATCH 0/8] Debug merge-recursive.[ch]","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:11Z","receivedAt":"2025-03-31T15:51:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"As a wise man once told me, \"Deleted code is debugged code!\"\n\nThis series does some preparation, then moves the code shared between\nmerge-recursive and merge-ort from the former to the latter, and then debugs\nthe remainder of merge-recursive.[ch].\n\nSeries overview:\n\n * Patches 1-5: Preparation; switch remaining callers of\n   merge-recursive.[ch] functions to merge-ort equivalents, and add sole\n   remaining missing feature (diff-algorithm selection)\n * Patch 6: Nuke merge-recursive.[ch]\n * Patch 7-8: Cleanup testsuite; we don't need GIT_TEST_MERGE_ALGORITHM\n   anymore\n\nWhile the diffstat might look large, the non-test code changes are actually\npretty small. The drivers of the big diffstat are:\n\n * We move a significant chunk of shared code from merge-recursive.[ch] to\n   merge-ort.[ch], without modifying it\n * We delete (the remainder of) merge-recursive.[ch]\n * We rip out all the temporary GIT_TEST_MERGE_ALGORITHM stuff designed to\n   let us reuse tests between recursive and ort\n\nElijah Newren (8):\n  checkout: replace merge_trees() with merge_ort_nonrecursive()\n  builtin/merge-recursive: switch to using merge_ort_generic()\n  merge-ort: enable diff-algorithms other than histogram\n  sequencer: switch non-recursive merges over to ort\n  merge, sequencer: switch recursive merges over to ort\n  merge-recursive.[ch]: thoroughly debug these\n  tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n  builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM\n\n Documentation/merge-strategies.adoc           |   51 +-\n Documentation/technical/sparse-checkout.adoc  |    2 -\n Makefile                                      |    1 -\n builtin/checkout.c                            |   10 +-\n builtin/merge-recursive.c                     |    4 +-\n builtin/merge.c                               |   23 +-\n builtin/rebase.c                              |    5 -\n builtin/revert.c                              |    2 -\n ci/run-build-and-tests.sh                     |    1 -\n merge-ort-wrappers.h                          |    2 +-\n merge-ort.c                                   |  162 +-\n merge-ort.h                                   |   60 +-\n merge-recursive.c                             | 4079 -----------------\n merge-recursive.h                             |  132 -\n meson.build                                   |    1 -\n sequencer.c                                   |   58 +-\n t/lib-merge.sh                                |   13 -\n t/t1092-sparse-checkout-compatibility.sh      |    2 -\n t/t2501-cwd-empty.sh                          |    2 -\n t/t3512-cherry-pick-submodule.sh              |    5 -\n t/t3513-revert-submodule.sh                   |    4 -\n t/t4069-remerge-diff.sh                       |    7 -\n t/t4301-merge-tree-write-tree.sh              |    7 -\n t/t5572-pull-submodule.sh                     |    5 -\n t/t6400-merge-df.sh                           |   14 +-\n t/t6402-merge-rename.sh                       |  125 +-\n t/t6404-recursive-merge.sh                    |   21 +-\n t/t6406-merge-attr.sh                         |    7 +-\n t/t6416-recursive-corner-cases.sh             |  194 +-\n t/t6421-merge-partial-clone.sh                |    7 +-\n t/t6422-merge-rename-corner-cases.sh          |   31 +-\n t/t6423-merge-rename-directories.sh           |  517 +--\n t/t6424-merge-unrelated-index-changes.sh      |    8 +-\n t/t6426-merge-skip-unneeded-updates.sh        |    4 +-\n t/t6428-merge-conflicts-sparse.sh             |    2 -\n t/t6430-merge-recursive.sh                    |   46 +-\n t/t6434-merge-recursive-rename-options.sh     |   16 +-\n t/t6436-merge-overwrite.sh                    |   17 +-\n t/t6437-submodule-merge.sh                    |   65 +-\n t/t6438-submodule-directory-file-conflicts.sh |    5 -\n t/t6439-merge-co-error-msgs.sh                |    2 +-\n t/t7402-submodule-rebase.sh                   |    7 +-\n t/t7602-merge-octopus-many.sh                 |    9 +-\n t/t7610-mergetool.sh                          |   40 +-\n t/t7615-diff-algo-with-mergy-operations.sh    |    2 -\n t/test-lib.sh                                 |    2 -\n 46 files changed, 538 insertions(+), 5241 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n delete mode 100644 t/lib-merge.sh\n\n\nbase-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1898%2Fnewren%2Fendit-quote-debugging-unquote-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1898/newren/endit-quote-debugging-unquote-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1898\n-- \ngitgitgadget\n"},{"id":"515379","messageId":"0e150ee90659c89399bec614902077729cb2c917.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 1/8] checkout: replace merge_trees() with merge_ort_nonrecursive()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:12Z","receivedAt":"2025-03-31T15:51:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nReplace the use of merge_trees() from merge-recursive.[ch] with the\nmerge-ort equivalent.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/checkout.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 01ea9ff8b28..67879e72362 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -17,7 +17,7 @@\n #include \"merge-ll.h\"\n #include \"lockfile.h\"\n #include \"mem-pool.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n #include \"object-store-ll.h\"\n #include \"parse-options.h\"\n@@ -907,10 +907,10 @@ static int merge_working_tree(const struct checkout_opts *opts,\n \t\t\to.branch1 = new_branch_info->name;\n \t\t\to.branch2 = \"local\";\n \t\t\to.conflict_style = opts->conflict_style;\n-\t\t\tret = merge_trees(&o,\n-\t\t\t\t\t  new_tree,\n-\t\t\t\t\t  work,\n-\t\t\t\t\t  old_tree);\n+\t\t\tret = merge_ort_nonrecursive(&o,\n+\t\t\t\t\t\t     new_tree,\n+\t\t\t\t\t\t     work,\n+\t\t\t\t\t\t     old_tree);\n \t\t\tif (ret < 0)\n \t\t\t\texit(128);\n \t\t\tret = reset_tree(new_tree,\n-- \ngitgitgadget\n\n"},{"id":"515380","messageId":"44be41da6c5ebc0cb20e4465e01ee2748310d436.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 2/8] builtin/merge-recursive: switch to using merge_ort_generic()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:13Z","receivedAt":"2025-03-31T15:51:25Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nSwitch from merge-recursive to merge-ort.  Adjust the following\ntestcases due to the switch:\n\n* t6430: most of the test differences here were due to improved D/F\n  conflict handling explained in more detail in ef527787089c (merge\n  tests: expect improved directory/file conflict handling in ort,\n  2020-10-26).  These changes weren't made to this test back in that\n  commit simply because I had been looking at `git merge` rather than\n  `git merge-recursive`.  The final test in this testsuite, though, was\n  expunged because it was looking for specific output, and the calls to\n  output_commit_title() were discarded from merge_ort_internal() in its\n  adaptation from merge_recursive_internal(); see 8119214f4e70\n  (merge-ort: implement merge_incore_recursive(), 2020-12-16).\n\n* t6436: This test is built entirely around rename/delete conflicts,\n  which had a suboptimal handling under merge-recursive.  As explained\n  in more detail in commits 1f3c9ba707 (\"t6425: be more flexible with\n  rename/delete conflict messages\", 2020-08-10) and 727c75b23f (\"t6404,\n  t6423: expect improved rename/delete handling in ort backend\",\n  2020-10-26), rename/delete conflicts should each have two entries in\n  the index rather than just one.  Adjust the expectations for all the\n  tests in this testcase to see the two entries per rename/delete\n  conflict.\n\n* t6424: merge-recursive had a special check-if-toplevel-trees-match\n  check that it ran at the beginning on both the merge-base and the\n  other side being merged in.  In such a case, it exited early and\n  printed an \"Already up to date.\" message.  merge-ort got rid of\n  this, and instead checks the merge base tree matching the other\n  side throughout the tree instead of just at the toplevel, allowing\n  it to avoid recursing into various subtrees.  As part of that, it\n  got rid of the specialty toplevel message.  That message hasn't\n  been missed for years from `git merge`, so I don't think it is\n  necessary to keep it just for `git merge-recursive`, especially\n  since the latter is rarely used.  (git itself only references it\n  in the testsuite, whereas it used to power one of the three\n  rebase backends that existed once upon a time.)\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge-recursive.c                 |  4 +--\n t/t6424-merge-unrelated-index-changes.sh  |  4 ++-\n t/t6430-merge-recursive.sh                | 43 +++++------------------\n t/t6434-merge-recursive-rename-options.sh | 16 +++++----\n 4 files changed, 22 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c\nindex abfc060e28a..03b5100cfae 100644\n--- a/builtin/merge-recursive.c\n+++ b/builtin/merge-recursive.c\n@@ -3,7 +3,7 @@\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hash.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n \n static const char builtin_merge_recursive_usage[] =\n@@ -89,7 +89,7 @@ int cmd_merge_recursive(int argc,\n \tif (o.verbosity >= 3)\n \t\tprintf(_(\"Merging %s with %s\\n\"), o.branch1, o.branch2);\n \n-\tfailed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);\n+\tfailed = merge_ort_generic(&o, &h1, &h2, bases_count, bases, &result);\n \n \tfree(better1);\n \tfree(better2);\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 7677c5f08d0..084bfe7e6ce 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -176,9 +176,11 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' '\n \t# Make index match B\n \tgit diff C B -- | git apply --cached &&\n \ttest_when_finished \"git clean -fd\" &&  # Do not leave untracked around\n+\tgit write-tree >index-before &&\n \t# Merge B & F, with B as \"head\"\n \tgit merge-recursive A -- B F > out &&\n-\ttest_grep \"Already up to date\" out\n+\tgit write-tree >index-after &&\n+\ttest_cmp index-before index-after\n '\n \n test_expect_success 'recursive, when file has staged changes not matching HEAD nor what a merge would give' '\ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex ca15e6dd6da..c539a68fd07 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -373,9 +373,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 2\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 2\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -397,9 +397,9 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 3\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 3\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -424,9 +424,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 3\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 2\td/e\"\n+\t\techo \"100644 $o1 2\td/e\" &&\n+\t\techo \"100644 $o6 3\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -448,9 +448,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 2\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 3\td/e\"\n+\t\techo \"100644 $o1 3\td/e\" &&\n+\t\techo \"100644 $o6 2\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -696,33 +696,6 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n \tgit merge other\n '\n \n-test_expect_success 'merge-recursive remembers the names of all base trees' '\n-\tgit reset --hard HEAD &&\n-\n-\t# make the index match $c1 so that merge-recursive below does not\n-\t# fail early\n-\tgit diff --binary HEAD $c1 -- | git apply --cached &&\n-\n-\t# more trees than static slots used by oid_to_hex()\n-\tfor commit in $c0 $c2 $c4 $c5 $c6 $c7\n-\tdo\n-\t\tgit rev-parse \"$commit^{tree}\" || return 1\n-\tdone >trees &&\n-\n-\t# ignore the return code; it only fails because the input is weird...\n-\ttest_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&\n-\n-\t# ...but make sure it fails in the expected way\n-\ttest_grep CONFLICT.*rename/rename out &&\n-\n-\t# merge-recursive prints in reverse order, but we do not care\n-\tsort <trees >expect &&\n-\tsed -n \"s/^virtual //p\" out | sort >actual &&\n-\ttest_cmp expect actual &&\n-\n-\tgit clean -fd\n-'\n-\n test_expect_success 'merge-recursive internal merge resolves to the sameness' '\n \tgit reset --hard HEAD &&\n \ndiff --git a/t/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh\nindex 6e913c30a13..5a6f74839cb 100755\n--- a/t/t6434-merge-recursive-rename-options.sh\n+++ b/t/t6434-merge-recursive-rename-options.sh\n@@ -34,7 +34,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n get_expected_stages () {\n \tgit checkout rename -- $1-new &&\n \tgit ls-files --stage $1-new >expected-stages-undetected-$1 &&\n-\tsed \"s/ 0\t/ 2\t/\" <expected-stages-undetected-$1 \\\n+\tgit ls-tree HEAD^ $1-old >tmp &&\n+\tgit ls-tree HEAD  $1-new >>tmp &&\n+\tcat tmp | awk '{print $1 \" \" $3 \" \" NR \"\\t\" '$1'\"-new\"}' \\\n \t\t>expected-stages-detected-$1 &&\n \tgit read-tree -u --reset HEAD\n }\n@@ -51,11 +53,11 @@ rename_undetected () {\n \n check_common () {\n \tgit ls-files --stage >stages-actual &&\n-\ttest_line_count = 4 stages-actual\n+\ttest_line_count = $1 stages-actual\n }\n \n check_threshold_0 () {\n-\tcheck_common &&\n+\tcheck_common 8 &&\n \trename_detected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -63,7 +65,7 @@ check_threshold_0 () {\n }\n \n check_threshold_1 () {\n-\tcheck_common &&\n+\tcheck_common 7 &&\n \trename_undetected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -71,7 +73,7 @@ check_threshold_1 () {\n }\n \n check_threshold_2 () {\n-\tcheck_common &&\n+\tcheck_common 6 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_detected 2 &&\n@@ -79,7 +81,7 @@ check_threshold_2 () {\n }\n \n check_exact_renames () {\n-\tcheck_common &&\n+\tcheck_common 5 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n@@ -87,7 +89,7 @@ check_exact_renames () {\n }\n \n check_no_renames () {\n-\tcheck_common &&\n+\tcheck_common 4 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n-- \ngitgitgadget\n\n"},{"id":"515381","messageId":"3945c471b0c40b49e9a48feaba6dae2afc96fa6a.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 3/8] merge-ort: enable diff-algorithms other than histogram","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:14Z","receivedAt":"2025-03-31T15:51:26Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe ort merge strategy has always used the histogram diff algorithm.\nThe recursive merge strategy, in contrast, defaults to the myers\ndiff algorithm, while allowing it to be changed.\n\nChange the ort merge strategy to allow different diff algorithms, by\nremoving the hard coded value in merge_start() and instead just making\nit a default in init_merge_options().  Technically, this also changes\nthe default diff algorithm for the recursive backend too, but we're\ngoing to remove the final callers of the recursive backend in the next\ntwo commits.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc | 29 +++++++++++++++--------------\n merge-ort.c                         |  3 ---\n merge-recursive.c                   |  1 +\n 3 files changed, 16 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 59f5ae36ccb..8c87dd70210 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -87,6 +87,20 @@ no-renames;;\n \tconfiguration variable.\n \tSee also linkgit:git-diff[1] `--no-renames`.\n \n+histogram;;\n+\tDeprecated synonym for `diff-algorithm=histogram`.\n+\n+patience;;\n+\tDeprecated synonym for `diff-algorithm=patience`.\n+\n+diff-algorithm=[histogram|minimal|myers|patience];;\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`.  Note that `ort`\n+\tdefaults to `diff-algorithm=histogram`, while regular diffs\n+\tcurrently default to the `diff.algorithm` config setting.\n+\n subtree[=<path>];;\n \tThis option is a more advanced form of 'subtree' strategy, where\n \tthe strategy makes a guess on how two trees must be shifted to\n@@ -111,20 +125,7 @@ recursive::\n For a path that is a submodule, the same caution as 'ort' applies to this\n strategy.\n +\n-The 'recursive' strategy takes the same options as 'ort'.  However,\n-there are two additional options that 'ort' ignores (not documented\n-above) that are potentially useful with the 'recursive' strategy:\n-\n-patience;;\n-\tDeprecated synonym for `diff-algorithm=patience`.\n-\n-diff-algorithm=[patience|minimal|histogram|myers];;\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`.  Note that `ort`\n-\tspecifically uses `diff-algorithm=histogram`, while `recursive`\n-\tdefaults to the `diff.algorithm` config setting.\n+The 'recursive' strategy takes the same options as 'ort'.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 2b7d86aa4ec..14a7ae4a6bf 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -4957,9 +4957,6 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)\n \t}\n \ttrace2_region_leave(\"merge\", \"sanity checks\", opt->repo);\n \n-\t/* Default to histogram diff.  Actually, just hardcode it...for now. */\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n \t/* Handle attr direction stuff for renormalization */\n \tif (opt->renormalize)\n \t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 884ccf99a58..f3df127ad9b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -3981,6 +3981,7 @@ static void init_merge_options(struct merge_options *opt,\n \topt->renormalize = 0;\n \n \topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n \n \tmerge_recursive_config(opt, ui);\n \tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-- \ngitgitgadget\n\n"},{"id":"515382","messageId":"39ff4860fcdfd5c80181971fa2b3fdd90428a163.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 4/8] sequencer: switch non-recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:15Z","receivedAt":"2025-03-31T15:51:27Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe do_recursive_merge() function, which is somewhat misleadingly named\nsince its purpose in life is to do a *non*-recursive merge, had code to\nallow either using the recursive or ort backends.  The default has been\nort for a very long time, let's just remove the code path for allowing\nthe recursive backend to be selected.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n sequencer.c | 35 +++++++++++++----------------------\n 1 file changed, 13 insertions(+), 22 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ad0ab75c8d4..b5d91fd3515 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -781,28 +781,19 @@ static int do_recursive_merge(struct repository *r,\n \tfor (i = 0; i < opts->xopts.nr; i++)\n \t\tparse_merge_opt(&o, opts->xopts.v[i]);\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\tmemset(&result, 0, sizeof(result));\n-\t\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,\n-\t\t\t\t\t    &result);\n-\t\tshow_output = !is_rebase_i(opts) || !result.clean;\n-\t\t/*\n-\t\t * TODO: merge_switch_to_result will update index/working tree;\n-\t\t * we only really want to do that if !result.clean || this is\n-\t\t * the final patch to be picked.  But determining this is the\n-\t\t * final patch would take some work, and \"head_tree\" would need\n-\t\t * to be replace with the tree the index matched before we\n-\t\t * started doing any picks.\n-\t\t */\n-\t\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n-\t\tclean = result.clean;\n-\t} else {\n-\t\tensure_full_index(r->index);\n-\t\tclean = merge_trees(&o, head_tree, next_tree, base_tree);\n-\t\tif (is_rebase_i(opts) && clean <= 0)\n-\t\t\tfputs(o.obuf.buf, stdout);\n-\t\tstrbuf_release(&o.obuf);\n-\t}\n+\tmemset(&result, 0, sizeof(result));\n+\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree, &result);\n+\tshow_output = !is_rebase_i(opts) || !result.clean;\n+\t/*\n+\t * TODO: merge_switch_to_result will update index/working tree;\n+\t * we only really want to do that if !result.clean || this is\n+\t * the final patch to be picked.  But determining this is the\n+\t * final patch would take some work, and \"head_tree\" would need\n+\t * to be replace with the tree the index matched before we\n+\t * started doing any picks.\n+\t */\n+\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n+\tclean = result.clean;\n \tif (clean < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn clean;\n-- \ngitgitgadget\n\n"},{"id":"515383","messageId":"91398ffd1e12e42fe9c9233a6ec14c448dea79ae.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 5/8] merge, sequencer: switch recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:16Z","receivedAt":"2025-03-31T15:51:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nMore precisely, replace calls to merge_recursive() with\nmerge_ort_recursive().\n\nAlso change t7615 to quit calling out recursive; it is not needed\nanymore, and we are in fact using ort now.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c                            |  9 ++-------\n sequencer.c                                | 23 ++++++++--------------\n t/t7615-diff-algo-with-mergy-operations.sh |  2 --\n 3 files changed, 10 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex ba9faf126aa..c0bbdab7104 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -39,7 +39,6 @@\n #include \"rerere.h\"\n #include \"help.h\"\n #include \"merge.h\"\n-#include \"merge-recursive.h\"\n #include \"merge-ort-wrappers.h\"\n #include \"resolve-undo.h\"\n #include \"remote.h\"\n@@ -750,12 +749,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \n \t\trepo_hold_locked_index(the_repository, &lock,\n \t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (!strcmp(strategy, \"ort\"))\n-\t\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\t    reversed, &result);\n-\t\telse\n-\t\t\tclean = merge_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\treversed, &result);\n+\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n+\t\t\t\t\t    reversed, &result);\n \t\tfree_commit_list(reversed);\n \t\tstrbuf_release(&o.obuf);\n \ndiff --git a/sequencer.c b/sequencer.c\nindex b5d91fd3515..8bb49735891 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4319,20 +4319,13 @@ static int do_merge(struct repository *r,\n \to.branch2 = ref_name.buf;\n \to.buffer_output = 2;\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\t/*\n-\t\t * TODO: Should use merge_incore_recursive() and\n-\t\t * merge_switch_to_result(), skipping the call to\n-\t\t * merge_switch_to_result() when we don't actually need to\n-\t\t * update the index and working copy immediately.\n-\t\t */\n-\t\tret = merge_ort_recursive(&o,\n-\t\t\t\t\t  head_commit, merge_commit, bases,\n-\t\t\t\t\t  &i);\n-\t} else {\n-\t\tret = merge_recursive(&o, head_commit, merge_commit, bases,\n-\t\t\t\t      &i);\n-\t}\n+\t/*\n+\t * TODO: Should use merge_incore_recursive() and\n+\t * merge_switch_to_result(), skipping the call to\n+\t * merge_switch_to_result() when we don't actually need to\n+\t * update the index and working copy immediately.\n+\t */\n+\tret = merge_ort_recursive(&o, head_commit, merge_commit, bases, &i);\n \tif (ret <= 0)\n \t\tfputs(o.obuf.buf, stdout);\n \tstrbuf_release(&o.obuf);\n@@ -4343,7 +4336,7 @@ static int do_merge(struct repository *r,\n \t\tgoto leave_merge;\n \t}\n \t/*\n-\t * The return value of merge_recursive() is 1 on clean, and 0 on\n+\t * The return value of merge_ort_recursive() is 1 on clean, and 0 on\n \t * unclean merge.\n \t *\n \t * Let's reverse that, so that do_merge() returns 0 upon success and\ndiff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh\nindex ac5863e788c..5822d02d517 100755\n--- a/t/t7615-diff-algo-with-mergy-operations.sh\n+++ b/t/t7615-diff-algo-with-mergy-operations.sh\n@@ -22,8 +22,6 @@ test_expect_success 'setup' '\n \tgit tag c2\n '\n \n-GIT_TEST_MERGE_ALGORITHM=recursive\n-\n test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '\n \tgit reset --hard c1 &&\n \ttest_must_fail git merge -s recursive -Xdiff-algorithm=myers c2\n-- \ngitgitgadget\n\n"},{"id":"515385","messageId":"0b6bcd225dc1444f4debe5fb8c499c6cad0a4ab2.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 7/8] tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:18Z","receivedAt":"2025-03-31T15:51:31Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nBoth of these existed to allow use to reuse all the merge-related tests\nin the testsuite while easily flipping between the 'recursive' and the\n'ort' backends.  Now that we have removed merge-recursive and remapped\n'recursive' to mean 'ort', we don't need this scaffolding anymore.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n ci/run-build-and-tests.sh                     |   1 -\n t/lib-merge.sh                                |  13 -\n t/t1092-sparse-checkout-compatibility.sh      |   2 -\n t/t2501-cwd-empty.sh                          |   2 -\n t/t3512-cherry-pick-submodule.sh              |   5 -\n t/t3513-revert-submodule.sh                   |   4 -\n t/t4069-remerge-diff.sh                       |   7 -\n t/t4301-merge-tree-write-tree.sh              |   7 -\n t/t5572-pull-submodule.sh                     |   5 -\n t/t6400-merge-df.sh                           |  14 +-\n t/t6402-merge-rename.sh                       | 125 +----\n t/t6404-recursive-merge.sh                    |  21 +-\n t/t6406-merge-attr.sh                         |   7 +-\n t/t6416-recursive-corner-cases.sh             | 194 ++-----\n t/t6421-merge-partial-clone.sh                |   7 +-\n t/t6422-merge-rename-corner-cases.sh          |  31 +-\n t/t6423-merge-rename-directories.sh           | 517 ++++--------------\n t/t6424-merge-unrelated-index-changes.sh      |   4 +-\n t/t6426-merge-skip-unneeded-updates.sh        |   4 +-\n t/t6428-merge-conflicts-sparse.sh             |   2 -\n t/t6430-merge-recursive.sh                    |   3 +-\n t/t6436-merge-overwrite.sh                    |  17 +-\n t/t6437-submodule-merge.sh                    |  65 +--\n t/t6438-submodule-directory-file-conflicts.sh |   5 -\n t/t6439-merge-co-error-msgs.sh                |   2 +-\n t/t7402-submodule-rebase.sh                   |   7 +-\n t/t7602-merge-octopus-many.sh                 |   9 +-\n t/t7610-mergetool.sh                          |  40 +-\n t/test-lib.sh                                 |   2 -\n 29 files changed, 248 insertions(+), 874 deletions(-)\n delete mode 100644 t/lib-merge.sh\n\ndiff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\nindex 1c698467235..f99b7db2ee8 100755\n--- a/ci/run-build-and-tests.sh\n+++ b/ci/run-build-and-tests.sh\n@@ -20,7 +20,6 @@ linux-breaking-changes)\n linux-TEST-vars)\n \texport OPENSSL_SHA1_UNSAFE=YesPlease\n \texport GIT_TEST_SPLIT_INDEX=yes\n-\texport GIT_TEST_MERGE_ALGORITHM=recursive\n \texport GIT_TEST_FULL_IN_PACK_ARRAY=true\n \texport GIT_TEST_OE_SIZE=10\n \texport GIT_TEST_OE_DELTA_SIZE=5\ndiff --git a/t/lib-merge.sh b/t/lib-merge.sh\ndeleted file mode 100644\nindex 8734ebfc17f..00000000000\n--- a/t/lib-merge.sh\n+++ /dev/null\n@@ -1,13 +0,0 @@\n-# Helper functions used by merge tests.\n-\n-test_expect_merge_algorithm () {\n-\tstatus_for_recursive=$1 status_for_ort=$2\n-\tshift 2\n-\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_expect_${status_for_ort} \"$@\"\n-\telse\n-\t\ttest_expect_${status_for_recursive} \"$@\"\n-\tfi\n-}\ndiff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh\nindex a4c7c41fc00..f9b448792cb 100755\n--- a/t/t1092-sparse-checkout-compatibility.sh\n+++ b/t/t1092-sparse-checkout-compatibility.sh\n@@ -1486,7 +1486,6 @@ test_expect_success 'sparse-index is not expanded' '\n \tensure_not_expanded checkout -f update-deep &&\n \ttest_config -C sparse-index pull.twohead ort &&\n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tfor OPERATION in \"merge -m merge\" cherry-pick rebase\n \t\tdo\n \t\t\tensure_not_expanded merge -m merge update-folder1 &&\n@@ -1506,7 +1505,6 @@ test_expect_success 'sparse-index is not expanded: merge conflict in cone' '\n \tdone &&\n \n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tgit -C sparse-index config pull.twohead ort &&\n \t\tensure_not_expanded ! merge -m merged expand-right\n \t)\ndiff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh\nindex f6d8d7d03d7..be9140bbaa4 100755\n--- a/t/t2501-cwd-empty.sh\n+++ b/t/t2501-cwd-empty.sh\n@@ -117,8 +117,6 @@ test_expect_success 'merge fails if cwd needs to be removed; recursive friendly'\n \tgrep \"Refusing to remove the current working directory\" error\n '\n \n-GIT_TEST_MERGE_ALGORITHM=ort\n-\n test_expect_success 'merge fails if cwd needs to be removed' '\n \ttest_required_dir_removal git merge fd_conflict\n '\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex f22d1ddead1..85a79326977 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -8,11 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 8bfe3ed2467..32e15c72eee 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -30,10 +30,6 @@ git_revert () {\n \tgit revert HEAD\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-fi\n test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh\nindex c6c94aef14d..966882ce912 100755\n--- a/t/t4069-remerge-diff.sh\n+++ b/t/t4069-remerge-diff.sh\n@@ -4,13 +4,6 @@ test_description='remerge-diff handling'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"${GIT_TEST_MERGE_ALGORITHM}\" != ort\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success 'setup basic merges' '\n \ttest_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&\n \tgit add numbers &&\ndiff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh\nindex 44f7d077593..f9c5883a7f7 100755\n--- a/t/t4301-merge-tree-write-tree.sh\n+++ b/t/t4301-merge-tree-write-tree.sh\n@@ -4,13 +4,6 @@ test_description='git merge-tree --write-tree'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != \"ort\"\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \ttest_write_lines 1 2 3 4 5 >numbers &&\n \techo hello >greeting &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f7650e8475e..45f384dd328 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -45,11 +45,6 @@ git_pull_noff () {\n \t$2 git pull --no-ff\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'setup' '\ndiff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh\nindex 3de4ef6bd9e..b46fe494409 100755\n--- a/t/t6400-merge-df.sh\n+++ b/t/t6400-merge-df.sh\n@@ -84,12 +84,7 @@ test_expect_success 'modify/delete + directory/file conflict' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\n@@ -105,12 +100,7 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\ndiff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh\nindex 2738b50c2a9..ff00b74e9c1 100755\n--- a/t/t6402-merge-rename.sh\n+++ b/t/t6402-merge-rename.sh\n@@ -313,12 +313,7 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '\n \n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~HEAD instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~HEAD instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~HEAD instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -340,12 +335,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \t! grep \"error: refusing to lose untracked file at\" errors &&\n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~renamed-file-has-no-conflicts instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -400,14 +390,7 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t\n \ttest_must_fail git merge --strategy=recursive dir-in-way &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -425,14 +408,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \ttest_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -488,12 +464,7 @@ test_expect_success 'both rename source and destination involved in D/F conflict\n \tgit checkout -q rename-dest^0 &&\n \ttest_must_fail git merge --strategy=recursive source-conflict &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 2 git ls-files -u\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -u\n-\tfi &&\n+\ttest_stdout_line_count = 2 git ls-files -u &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -527,63 +498,33 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '\n \tgit commit -m \"Rename one/file -> two\"\n '\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-then\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n-\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two &&\n-\n-\t\ttest_must_fail git diff --quiet &&\n-\n-\t\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n-\n-\t\ttest_path_is_file one &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-else\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n+test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n+\tgit checkout -q rename-one^0 &&\n+\tmkdir one &&\n+\ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n-\t\ttest_must_fail git diff --quiet &&\n+\ttest_must_fail git diff --quiet &&\n \n-\t\ttest 4 -eq $(find . | grep -v .git | wc -l) &&\n+\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n \n-\t\ttest_path_is_dir one &&\n-\t\ttest_path_is_file one~rename-two &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one~rename-two) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-fi\n+\ttest_path_is_file one &&\n+\ttest_path_is_file two &&\n+\ttest \"other\" = $(cat one) &&\n+\ttest \"stuff\" = $(cat two)\n+'\n \n test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '\n \tgit reset --hard &&\n \tgit clean -fdqx &&\n \ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two\n-\telse\n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two\n-\tfi &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -623,22 +564,12 @@ test_expect_success 'check handling of differently renamed file with D/F conflic\n \tgit checkout -q first-rename^0 &&\n \ttest_must_fail git merge --strategy=recursive second-rename &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 2 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 5 git ls-files -s &&\n+\ttest_stdout_line_count = 3 git ls-files -u &&\n+\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n+\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n+\ttest_stdout_line_count = 1 git ls-files -u original &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file one/file &&\n \ttest_path_is_file two/file &&\ndiff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh\nindex ae687f2ce54..346f3608b98 100755\n--- a/t/t6404-recursive-merge.sh\n+++ b/t/t6404-recursive-merge.sh\n@@ -108,12 +108,7 @@ test_expect_success 'refuse to merge binary files' '\n \tprintf \"\\0\\0\" >binary-file &&\n \tgit add binary-file &&\n \tgit commit -m binary2 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge F >merge_output\n-\telse\n-\t\ttest_must_fail git merge F 2>merge_output\n-\tfi &&\n+\ttest_must_fail git merge F >merge_output &&\n \tgrep \"Cannot merge binary files: binary-file (HEAD vs. F)\" merge_output\n '\n \n@@ -129,22 +124,12 @@ test_expect_success 'mark rename/delete as unmerged' '\n \ttest_tick &&\n \tgit commit -m rename &&\n \ttest_must_fail git merge delete &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \tgit rev-parse --verify :2:a2 &&\n \ttest_must_fail git rev-parse --verify :3:a2 &&\n \tgit checkout -f delete &&\n \ttest_must_fail git merge rename &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \ttest_must_fail git rev-parse --verify :2:a2 &&\n \tgit rev-parse --verify :3:a2\n '\ndiff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh\nindex 66e01464b5e..8f6fbef0024 100755\n--- a/t/t6406-merge-attr.sh\n+++ b/t/t6406-merge-attr.sh\n@@ -259,12 +259,7 @@ test_expect_success 'binary files with union attribute' '\n \tprintf \"two\\0\" >bin.txt &&\n \tgit commit -am two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge bin-main >output\n-\telse\n-\t\ttest_must_fail git merge bin-main 2>output\n-\tfi &&\n+\ttest_must_fail git merge bin-main >output &&\n \tgrep -i \"warning.*cannot merge.*HEAD vs. bin-main\" output\n '\n \ndiff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh\nindex 17b54d625d0..ed20de8ea22 100755\n--- a/t/t6416-recursive-corner-cases.sh\n+++ b/t/t6416-recursive-corner-cases.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n #  L1  L2\n@@ -529,15 +528,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git merge C^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~HEAD\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~HEAD &&\n \t\tgit cat-file -p B:a >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m D2 &&\n@@ -556,12 +548,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd\n-\t\tfi &&\n+\t\tgit rm a~B^0 &&\n \t\tgit rm -rf a/ &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a &&\n \t\tgit add a &&\n@@ -570,15 +557,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~B^0 &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m E4 &&\n@@ -596,34 +576,16 @@ test_expect_success 'merge of D1 & E1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    A:ignore-me  B:a D1:a &&\n+\t\tgit rev-parse >actual   :0:ignore-me :1:a :2:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -637,34 +599,18 @@ test_expect_success 'merge of E1 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tA:ignore-me  B:a  D1:a &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:0:ignore-me :1:a :3:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -678,32 +624,17 @@ test_expect_success 'merge of D1 & E2 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E2^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a    E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:2:a   :3:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~HEAD\n@@ -720,32 +651,17 @@ test_expect_success 'merge of E2 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a   E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:3:a  :2:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~D1^0\n@@ -777,7 +693,7 @@ test_expect_success 'merge of D1 & E3 succeeds' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n+test_expect_success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n \ttest_when_finished \"git -C directory-file reset --hard\" &&\n \ttest_when_finished \"git -C directory-file clean -fdqx\" &&\n \t(\n@@ -1140,7 +1056,7 @@ test_expect_success 'setup symlink modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink modify/modify' '\n+test_expect_success 'check symlink modify/modify' '\n \t(\n \t\tcd symlink-modify-modify &&\n \n@@ -1206,7 +1122,7 @@ test_expect_success 'setup symlink add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink add/add' '\n+test_expect_success 'check symlink add/add' '\n \t(\n \t\tcd symlink-add-add &&\n \n@@ -1294,7 +1210,7 @@ test_expect_success 'setup submodule modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule modify/modify' '\n+test_expect_success 'check submodule modify/modify' '\n \t(\n \t\tcd submodule-modify-modify &&\n \n@@ -1382,7 +1298,7 @@ test_expect_success 'setup submodule add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule add/add' '\n+test_expect_success 'check submodule add/add' '\n \t(\n \t\tcd submodule-add-add &&\n \n@@ -1457,7 +1373,7 @@ test_expect_success 'setup conflicting entry types (submodule vs symlink)' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check conflicting entry types (submodule vs symlink)' '\n+test_expect_success 'check conflicting entry types (submodule vs symlink)' '\n \t(\n \t\tcd submodule-symlink-add-add &&\n \ndiff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh\nindex b99f29ef9ba..6eb51285a0c 100755\n--- a/t/t6421-merge-partial-clone.sh\n+++ b/t/t6421-merge-partial-clone.sh\n@@ -27,7 +27,6 @@ test_description=\"limiting blob downloads when merging with partial clones\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_repo () {\n \ttest -d server && return\n@@ -207,7 +206,7 @@ test_setup_repo () {\n #\n #   Summary: 2 fetches (1 for 2 objects, 1 for 1 object)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded for single relevant rename' '\n+test_expect_success 'Objects downloaded for single relevant rename' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-single &&\n \t(\n@@ -297,7 +296,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded for single relev\n #      this are not all that common.)\n #   Summary: 1 fetches for 6 objects\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded when a directory rename triggered' '\n+test_expect_success 'Objects downloaded when a directory rename triggered' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-dir &&\n \t(\n@@ -399,7 +398,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory\n #\n #   Summary: 4 fetches (1 for 6 objects, 1 for 8, 1 for 3, 1 for 2)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded with lots of renames and modifications' '\n+test_expect_success 'Objects downloaded with lots of renames and modifications' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-many &&\n \t(\ndiff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh\nindex 62b49c67e22..9cbe7ca7824 100755\n--- a/t/t6422-merge-rename-corner-cases.sh\n+++ b/t/t6422-merge-rename-corner-cases.sh\n@@ -7,7 +7,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_rename_delete_untracked () {\n \tgit init rename-delete-untracked &&\n@@ -316,12 +315,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\techo 0 >expect &&\n \t\tgit cat-file -p base:file >>expect &&\n@@ -350,12 +344,7 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 3 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\tgit cat-file -p left-conflict:newfile >left &&\n \t\tgit cat-file -p base:file    >base &&\n@@ -369,14 +358,8 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \n \t\tgit rev-parse >expect   \\\n \t\t\tbase:file       left-conflict:newfile right:file &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD\n-\t\telse\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile      :2:newfile      :3:newfile\n-\t\tfi &&\n+\t\tgit rev-parse >actual \\\n+\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file newfile/realfile &&\n@@ -896,7 +879,7 @@ test_setup_rad () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rad-check: rename/add/delete conflict' '\n+test_expect_success 'rad-check: rename/add/delete conflict' '\n \ttest_setup_rad &&\n \t(\n \t\tcd rad &&\n@@ -969,7 +952,7 @@ test_setup_rrdd () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n+test_expect_success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n \ttest_setup_rrdd &&\n \t(\n \t\tcd rrdd &&\n@@ -1058,7 +1041,7 @@ test_setup_mod6 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n+test_expect_success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n \ttest_setup_mod6 &&\n \t(\n \t\tcd mod6 &&\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex e0785410cd9..f48ed6d0353 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -26,8 +26,6 @@ test_description=\"recursive merge with directory renames\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Basic cases we should be able to handle\n@@ -302,20 +300,11 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'\n \t\tgit cat-file -p :2:x/wham >expect &&\n \t\tgit cat-file -p :3:x/wham >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/wham\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/wham\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/wham\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/wham\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect x/wham\n \t)\n '\n@@ -1186,18 +1175,10 @@ test_expect_success '5d: Directory/file/file conflict due to directory rename' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e\n-\t\telse\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d      :0:y/d/e\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e &&\n \t\tgit rev-parse >expect \\\n \t\t\t O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&\n \t\ttest_cmp expect actual &&\n@@ -1280,32 +1261,17 @@ test_expect_success '6a: Tricky rename/delete' '\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*z/c.*y/c\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :1:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:z/c\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :1:y/c :3:y/c &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:z/c &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -1372,7 +1338,7 @@ test_setup_6b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b1: Same renames done on both sides, plus another rename' '\n+test_expect_success '6b1: Same renames done on both sides, plus another rename' '\n \ttest_setup_6b1 &&\n \t(\n \t\tcd 6b1 &&\n@@ -1445,7 +1411,7 @@ test_setup_6b2 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b2: Same rename done on both sides' '\n+test_expect_success '6b2: Same rename done on both sides' '\n \ttest_setup_6b2 &&\n \t(\n \t\tcd 6b2 &&\n@@ -1832,20 +1798,11 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'\n \t\tgit cat-file -p :2:y/d >expect &&\n \t\tgit cat-file -p :3:y/d >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/d\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/d\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/d\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/d\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect y/d\n \t)\n '\n@@ -1967,32 +1924,17 @@ test_expect_success '7d: transitive rename involved in rename/delete; how is it\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d  O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:x/d  O:x/d &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -2073,32 +2015,17 @@ test_expect_success '7e: transitive rename in rename/delete AND dirs in the way'\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d &&\n \t\ttest_cmp expect actual &&\n \n \t\tgit hash-object y/d~B^0 >actual &&\n@@ -3284,34 +3211,15 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '\n \t\techo contents >y/e &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/delete).*Version B\\^0 of y/d left in tree at y/d~B\\^0\" out &&\n-\t\t\ttest_grep \"Error: Refusing to lose untracked file at y/e; writing to y/e~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/d :3:y/e &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\tO:z/b  O:z/c  B:z/e &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 1 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 5 out &&\n \n \t\techo very >expect &&\n \t\ttest_cmp expect y/c &&\n@@ -3374,38 +3282,15 @@ test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~B^0 >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3425,38 +3310,15 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~HEAD instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3514,47 +3376,15 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '\n \t\techo important >y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/wham\n@@ -3596,7 +3426,7 @@ test_setup_10e () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '10e: Does git complain about untracked file that is not really in the way?' '\n+test_expect_success '10e: Does git complain about untracked file that is not really in the way?' '\n \ttest_setup_10e &&\n \t(\n \t\tcd 10e &&\n@@ -3687,30 +3517,8 @@ test_expect_success '11a: Avoid losing dirty contents with simple rename' '\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:z/a :2:z/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  B:z/b &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object z/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:z/b >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo stuff >>expected &&\n@@ -3766,34 +3574,9 @@ test_expect_success '11b: Avoid losing dirty file involved in directory rename'\n \t\tgit checkout A^0 &&\n \t\techo stuff >>z/c &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\tgit -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -m >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3850,13 +3633,8 @@ test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"following files would be overwritten by merge\" err\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff y/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3924,30 +3702,8 @@ test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c/d :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:y/c/d  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -4010,39 +3766,8 @@ test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to\n \t\techo mods >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 7 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# See if y/c~merged has expected contents; requires manually\n-\t\t\t# doing the expected file merge\n-\t\t\tgit cat-file -p A:y/c >c1 &&\n-\t\t\tgit cat-file -p B:z/c >c2 &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\tc1 empty c2 &&\n-\t\t\ttest_cmp c1 y/c~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\techo different >expected &&\n \t\techo mods >>expected &&\n@@ -4099,40 +3824,8 @@ test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to\n \t\techo important >>y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/c     O:x/d &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo important >>expected &&\n@@ -4267,7 +3960,7 @@ test_setup_12b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12b1: Moving two directory hierarchies into each other' '\n+test_expect_success '12b1: Moving two directory hierarchies into each other' '\n \ttest_setup_12b1 &&\n \t(\n \t\tcd 12b1 &&\n@@ -4435,7 +4128,7 @@ test_setup_12c1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12c1: Moving one directory hierarchy into another w/ content merge' '\n+test_expect_success '12c1: Moving one directory hierarchy into another w/ content merge' '\n \ttest_setup_12c1 &&\n \t(\n \t\tcd 12c1 &&\n@@ -4797,7 +4490,7 @@ test_setup_12f () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '\n+test_expect_success '12f: Trivial directory resolve, caching, all kinds of fun' '\n \ttest_setup_12f &&\n \t(\n \t\tcd 12f &&\n@@ -5253,7 +4946,7 @@ test_setup_12l () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12l (B into A): Rename into each other + add/add conflict' '\n+test_expect_success '12l (B into A): Rename into each other + add/add conflict' '\n \ttest_setup_12l BintoA &&\n \t(\n \t\tcd 12l_BintoA &&\n@@ -5280,7 +4973,7 @@ test_expect_merge_algorithm failure success '12l (B into A): Rename into each ot\n \t)\n '\n \n-test_expect_merge_algorithm failure success '12l (A into B): Rename into each other + add/add conflict' '\n+test_expect_success '12l (A into B): Rename into each other + add/add conflict' '\n \ttest_setup_12l AintoB &&\n \t(\n \t\tcd 12l_AintoB &&\n@@ -5348,7 +5041,7 @@ test_setup_12m () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 084bfe7e6ce..ddc7524f6c1 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -296,10 +296,8 @@ test_expect_success 'with multiple strategies, recursive or ort failure do not e\n \tgit add a &&\n \tgit rev-parse :a >expect &&\n \n-\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n-\ttest_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&\n+\ttest_must_fail git merge -s ort -s octopus C^0 >output 2>&1 &&\n \n-\tgrep \"Trying merge strategy recursive...\" output &&\n \tgrep \"Trying merge strategy ort...\" output &&\n \tgrep \"Trying merge strategy octopus...\" output &&\n \tgrep \"No merge strategy handled the merge.\" output &&\ndiff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh\nindex b059475ed03..404cd3f2ca1 100755\n--- a/t/t6426-merge-skip-unneeded-updates.sh\n+++ b/t/t6426-merge-skip-unneeded-updates.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Cases involving no renames (one side has subset of changes of\n@@ -663,7 +661,7 @@ test_setup_4a () {\n #   correct requires doing the merge in-memory first, then realizing that no\n #   updates to the file are necessary, and thus that we can just leave the path\n #   alone.\n-test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '\n+test_expect_success '4a: Change on A, change on B subset of A, dirty mods present' '\n \ttest_setup_4a &&\n \t(\n \t\tcd 4a &&\ndiff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh\nindex 9919c3fa7cd..c86e02c6e23 100755\n--- a/t/t6428-merge-conflicts-sparse.sh\n+++ b/t/t6428-merge-conflicts-sparse.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n # Testcase basic, conflicting changes in 'numerals'\n \ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex c539a68fd07..e59560a5dd9 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_expect_success 'setup 1' '\n \n@@ -645,7 +644,7 @@ test_expect_success 'merge-recursive copy vs. rename' '\n \ttest_cmp expected actual\n '\n \n-test_expect_merge_algorithm failure success 'merge-recursive rename vs. rename/symlink' '\n+test_expect_success 'merge-recursive rename vs. rename/symlink' '\n \n \tgit checkout -f rename &&\n \tgit merge rename-ln &&\ndiff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh\nindex 4f4376421e7..70b5d2d6944 100755\n--- a/t/t6436-merge-overwrite.sh\n+++ b/t/t6436-merge-overwrite.sh\n@@ -101,19 +101,10 @@ test_expect_success 'will not overwrite unstaged changes in renamed file' '\n \tgit mv c1.c other.c &&\n \tgit commit -m rename &&\n \tcp important other.c &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge c1a >out 2>err &&\n-\t\ttest_grep \"would be overwritten by merge\" err &&\n-\t\ttest_cmp important other.c &&\n-\t\ttest_path_is_missing .git/MERGE_HEAD\n-\telse\n-\t\ttest_must_fail git merge c1a >out &&\n-\t\ttest_grep \"Refusing to lose dirty file at other.c\" out &&\n-\t\ttest_path_is_file other.c~HEAD &&\n-\t\ttest $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&\n-\t\ttest_cmp important other.c\n-\tfi\n+\ttest_must_fail git merge c1a >out 2>err &&\n+\ttest_grep \"would be overwritten by merge\" err &&\n+\ttest_cmp important other.c &&\n+\ttest_path_is_missing .git/MERGE_HEAD\n '\n \n test_expect_success 'will not overwrite untracked subtree' '\ndiff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\nindex 4815559157b..a564758f528 100755\n--- a/t/t6437-submodule-merge.sh\n+++ b/t/t6437-submodule-merge.sh\n@@ -9,7 +9,6 @@ GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1\n export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n # history\n@@ -110,14 +109,10 @@ test_expect_success 'merging should conflict for non fast-forward' '\n \ttest_when_finished \"git -C merge-search reset --hard\" &&\n \t(cd merge-search &&\n \t git checkout -b test-nonforward-a b &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c 2>actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi)\n+\t test_must_fail git merge c 2>actual &&\n+\t sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t grep \"$sub_expect\" actual\n+\t )\n '\n \n test_expect_success 'finish setup for merge-search' '\n@@ -151,14 +146,9 @@ test_expect_success 'merging should conflict for non fast-forward (resolution ex\n \t git checkout -b test-nonforward-b b &&\n \t (cd sub &&\n \t  git rev-parse --short sub-d > ../expect) &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi &&\n+\t  test_must_fail git merge c >actual 2>sub-actual &&\n+\t  sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t  grep \"$sub_expect\" sub-actual &&\n \t grep $(cat expect) actual > /dev/null &&\n \t git reset --hard)\n '\n@@ -169,23 +159,12 @@ test_expect_success 'merging should fail for ambiguous common parent' '\n \t(cd sub &&\n \t git checkout -b ambiguous sub-b &&\n \t git merge sub-c &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\tgit rev-parse --short sub-d >../expect1 &&\n-\t\tgit rev-parse --short ambiguous >../expect2\n-\t else\n-\t\tgit rev-parse sub-d > ../expect1 &&\n-\t\tgit rev-parse ambiguous > ../expect2\n-\t fi\n+\t git rev-parse --short sub-d >../expect1 &&\n+\t git rev-parse --short ambiguous >../expect2\n \t ) &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t else\n-\t\ttest_must_fail git merge c 2> actual\n-\t fi &&\n+\ttest_must_fail git merge c >actual 2>sub-actual &&\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\tgrep \"$sub_expect\" sub-actual &&\n \tgrep $(cat expect1) actual > /dev/null &&\n \tgrep $(cat expect2) actual > /dev/null &&\n \tgit reset --hard)\n@@ -227,11 +206,9 @@ test_expect_success 'merging should fail for changes that are backwards' '\n \n \tgit checkout -b test-backward e &&\n \ttest_must_fail git merge f 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n \n@@ -358,7 +335,7 @@ test_expect_success 'setup file/submodule conflict' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'file/submodule conflict' '\n+test_expect_success 'file/submodule conflict' '\n \ttest_when_finished \"git -C file-submodule reset --hard\" &&\n \t(\n \t\tcd file-submodule &&\n@@ -467,7 +444,7 @@ test_expect_failure 'directory/submodule conflict; keep submodule clean' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n+test_expect_success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n \ttest_when_finished \"git -C directory-submodule/path reset --hard\" &&\n \ttest_when_finished \"git -C directory-submodule reset --hard\" &&\n \t(\n@@ -535,11 +512,9 @@ test_expect_success 'merging should fail with no merge base' '\n \tgit add sub &&\n \tgit commit -m \"b\" &&\n \ttest_must_fail git merge a 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n test_done\ndiff --git a/t/t6438-submodule-directory-file-conflicts.sh b/t/t6438-submodule-directory-file-conflicts.sh\nindex 8df67a0ef99..53d83c828a7 100755\n--- a/t/t6438-submodule-directory-file-conflicts.sh\n+++ b/t/t6438-submodule-directory-file-conflicts.sh\n@@ -12,11 +12,6 @@ test_submodule_switch \"merge --ff\"\n \n test_submodule_switch \"merge --ff-only\"\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"merge --no-ff\"\n \n test_done\ndiff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh\nindex 55bd744a3f4..643c9368e0e 100755\n--- a/t/t6439-merge-co-error-msgs.sh\n+++ b/t/t6439-merge-co-error-msgs.sh\n@@ -47,7 +47,7 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for\n \t\texport GIT_MERGE_VERBOSITY &&\n \t\ttest_must_fail git merge branch 2>out2\n \t) &&\n-\techo \"Merge with strategy ${GIT_TEST_MERGE_ALGORITHM:-ort} failed.\" >>expect &&\n+\techo \"Merge with strategy ort failed.\" >>expect &&\n \ttest_cmp out2 expect &&\n \tgit reset --hard HEAD^\n '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 25b33a1e875..06cee3432fe 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -124,11 +124,8 @@ test_expect_success 'rebasing submodule that should conflict' '\n \t\techo \"160000 $(git rev-parse HEAD) 3\tsubmodule\"\n \t) >expect &&\n \ttest_cmp expect actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n-\t\tgrep \"$sub_expect\" actual_output\n-\tfi\n+\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n+\tgrep \"$sub_expect\" actual_output\n '\n \n test_done\ndiff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh\nindex ff085b086cc..42f675b7399 100755\n--- a/t/t7602-merge-octopus-many.sh\n+++ b/t/t7602-merge-octopus-many.sh\n@@ -77,12 +77,9 @@ Merge made by the 'recursive' strategy.\n EOF\n \n test_expect_success 'merge reduces irrelevant remote heads' '\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv expected expected.tmp &&\n-\t\tsed s/recursive/ort/ expected.tmp >expected &&\n-\t\trm expected.tmp\n-\tfi &&\n+\tmv expected expected.tmp &&\n+\tsed s/recursive/ort/ expected.tmp >expected &&\n+\trm expected.tmp &&\n \tGIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&\n \ttest_cmp expected actual\n '\ndiff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh\nindex c077aba7ced..957f8e20ba3 100755\n--- a/t/t7610-mergetool.sh\n+++ b/t/t7610-mergetool.sh\n@@ -535,14 +535,9 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"c\" | git mergetool submod~HEAD &&\n-\t\tgit rm submod &&\n-\t\tgit mv submod~HEAD submod\n-\telse\n-\t\tyes \"l\" | git mergetool submod\n-\tfi &&\n+\tyes \"c\" | git mergetool submod~HEAD &&\n+\tgit rm submod &&\n+\tgit mv submod~HEAD submod &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod &&\n@@ -559,15 +554,10 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv submod submod.orig &&\n-\t\tgit rm --cached submod &&\n-\t\tyes \"c\" | git mergetool submod~test19 &&\n-\t\tgit mv submod~test19 submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tmv submod submod.orig &&\n+\tgit rm --cached submod &&\n+\tyes \"c\" | git mergetool submod~test19 &&\n+\tgit mv submod~test19 submod &&\n \ttest -d submod.orig &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n@@ -585,10 +575,7 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n \tyes \"l\" | git mergetool submod &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"d\" | git mergetool submod~test19\n-\tfi &&\n+\tyes \"d\" | git mergetool submod~test19 &&\n \techo \"main submodule\" >expect &&\n \ttest_cmp expect submod/bar &&\n \tgit submodule update -N &&\n@@ -686,14 +673,9 @@ test_expect_success 'directory vs modified submodule' '\n \ttest_must_fail git merge main &&\n \ttest -n \"$(git ls-files -u)\" &&\n \ttest ! -e submod.orig &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"r\" | git mergetool submod~main &&\n-\t\tgit mv submod submod.orig &&\n-\t\tgit mv submod~main submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tyes \"r\" | git mergetool submod~main &&\n+\tgit mv submod submod.orig &&\n+\tgit mv submod~main submod &&\n \ttest -d submod.orig &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod.orig/file16 &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..5952eb56e27 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -544,8 +544,6 @@ GIT_DEFAULT_HASH=\"${GIT_TEST_DEFAULT_HASH:-sha1}\"\n export GIT_DEFAULT_HASH\n GIT_DEFAULT_REF_FORMAT=\"${GIT_TEST_DEFAULT_REF_FORMAT:-files}\"\n export GIT_DEFAULT_REF_FORMAT\n-GIT_TEST_MERGE_ALGORITHM=\"${GIT_TEST_MERGE_ALGORITHM:-ort}\"\n-export GIT_TEST_MERGE_ALGORITHM\n \n # Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output\n GIT_TRACE_BARE=1\n-- \ngitgitgadget\n\n"},{"id":"515386","messageId":"6ef536cdbcdf493b3a212895b4c42d6850420633.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 6/8] merge-recursive.[ch]: thoroughly debug these","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:17Z","receivedAt":"2025-03-31T15:51:31Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAs a wise man once told me, \"Deleted code is debugged code!\"  So, move\nthe functions that are shared between merge-recursive and merge-ort from\nthe former to the latter, and then debug the remainder of\nmerge-recursive.[ch].\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc          |   24 +-\n Documentation/technical/sparse-checkout.adoc |    2 -\n Makefile                                     |    1 -\n merge-ort-wrappers.h                         |    2 +-\n merge-ort.c                                  |  159 +\n merge-ort.h                                  |   60 +-\n merge-recursive.c                            | 4080 ------------------\n merge-recursive.h                            |  132 -\n meson.build                                  |    1 -\n 9 files changed, 225 insertions(+), 4236 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 8c87dd70210..9e034f447e7 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -109,23 +109,11 @@ subtree[=<path>];;\n \ttwo trees to match.\n \n recursive::\n-\tThis can only resolve two heads using a 3-way merge\n-\talgorithm.  When there is more than one common\n-\tancestor that can be used for 3-way merge, it creates a\n-\tmerged tree of the common ancestors and uses that as\n-\tthe reference tree for the 3-way merge.  This has been\n-\treported to result in fewer merge conflicts without\n-\tcausing mismerges by tests done on actual merge commits\n-\ttaken from Linux 2.6 kernel development history.\n-\tAdditionally this can detect and handle merges involving\n-\trenames.  It does not make use of detected copies.  This was\n-\tthe default strategy for resolving two heads from Git v0.99.9k\n-\tuntil v2.33.0.\n-+\n-For a path that is a submodule, the same caution as 'ort' applies to this\n-strategy.\n-+\n-The 'recursive' strategy takes the same options as 'ort'.\n+\tThis is now a synonym for `ort`.  It was an alternative\n+\timplementation until v2.49.0, but was redirected to mean `ort`\n+\tin v2.50.0.  The previous recursive strategy was the default\n+\tstrategy for resolving two heads from Git v0.99.9k until\n+\tv2.33.0.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\n@@ -146,7 +134,7 @@ ours::\n \tignoring all changes from all other branches.  It is meant to\n \tbe used to supersede old development history of side\n \tbranches.  Note that this is different from the -Xours option to\n-\tthe 'recursive' merge strategy.\n+\tthe 'ort' merge strategy.\n \n subtree::\n \tThis is a modified `ort` strategy. When merging trees A and\ndiff --git a/Documentation/technical/sparse-checkout.adoc b/Documentation/technical/sparse-checkout.adoc\nindex d9686593548..dc2e763bbec 100644\n--- a/Documentation/technical/sparse-checkout.adoc\n+++ b/Documentation/technical/sparse-checkout.adoc\n@@ -356,8 +356,6 @@ understanding these differences can be beneficial.\n     The behavior for these commands somewhat depends upon the merge\n     strategy being used:\n       * `ort` behaves as described above\n-      * `recursive` tries to not vivify files unnecessarily, but does sometimes\n-\tvivify files without conflicts.\n       * `octopus` and `resolve` will always vivify any file changed in the merge\n \trelative to the first parent, which is rather suboptimal.\n \ndiff --git a/Makefile b/Makefile\nindex ac32d2d0bda..4fbd29cc7e9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1069,7 +1069,6 @@ LIB_OBJS += merge-blobs.o\n LIB_OBJS += merge-ll.o\n LIB_OBJS += merge-ort.o\n LIB_OBJS += merge-ort-wrappers.o\n-LIB_OBJS += merge-recursive.o\n LIB_OBJS += merge.o\n LIB_OBJS += midx.o\n LIB_OBJS += midx-write.o\ndiff --git a/merge-ort-wrappers.h b/merge-ort-wrappers.h\nindex aeffa1c87b4..b7e1ced9d7f 100644\n--- a/merge-ort-wrappers.h\n+++ b/merge-ort-wrappers.h\n@@ -1,7 +1,7 @@\n #ifndef MERGE_ORT_WRAPPERS_H\n #define MERGE_ORT_WRAPPERS_H\n \n-#include \"merge-recursive.h\"\n+#include \"merge-ort.h\"\n \n /*\n  * rename-detecting three-way merge, no recursion.\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 14a7ae4a6bf..f943f5ddcba 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -26,6 +26,7 @@\n #include \"cache-tree.h\"\n #include \"commit.h\"\n #include \"commit-reach.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"dir.h\"\n@@ -5322,3 +5323,161 @@ void merge_incore_recursive(struct merge_options *opt,\n \tmerge_ort_internal(opt, merge_bases, side1, side2, result);\n \ttrace2_region_leave(\"merge\", \"incore_recursive\", opt->repo);\n }\n+\n+static void merge_recursive_config(struct merge_options *opt, int ui)\n+{\n+\tchar *value = NULL;\n+\tint renormalize = 0;\n+\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n+\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n+\topt->renormalize = renormalize;\n+\tif (!git_config_get_string(\"diff.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n+\t\tint boolval = git_parse_maybe_bool(value);\n+\t\tif (0 <= boolval) {\n+\t\t\topt->detect_directory_renames = boolval ?\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n+\t\t} else if (!strcasecmp(value, \"conflict\")) {\n+\t\t\topt->detect_directory_renames =\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n+\t\t} /* avoid erroring on values from future versions of git */\n+\t\tfree(value);\n+\t}\n+\tif (ui) {\n+\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n+\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n+\t\t\tif (diff_algorithm < 0)\n+\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n+\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n+\t\t\tfree(value);\n+\t\t}\n+\t}\n+\tgit_config(git_xmerge_config, NULL);\n+}\n+\n+static void init_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo, int ui)\n+{\n+\tconst char *merge_verbosity;\n+\tmemset(opt, 0, sizeof(struct merge_options));\n+\n+\topt->repo = repo;\n+\n+\topt->detect_renames = -1;\n+\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n+\topt->rename_limit = -1;\n+\n+\topt->verbosity = 2;\n+\topt->buffer_output = 1;\n+\tstrbuf_init(&opt->obuf, 0);\n+\n+\topt->renormalize = 0;\n+\n+\topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\n+\tmerge_recursive_config(opt, ui);\n+\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n+\tif (merge_verbosity)\n+\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n+\tif (opt->verbosity >= 5)\n+\t\topt->buffer_output = 0;\n+}\n+\n+void init_ui_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 1);\n+}\n+\n+void init_basic_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 0);\n+}\n+\n+/*\n+ * For now, members of merge_options do not need deep copying, but\n+ * it may change in the future, in which case we would need to update\n+ * this, and also make a matching change to clear_merge_options() to\n+ * release the resources held by a copied instance.\n+ */\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n+{\n+\t*dst = *src;\n+}\n+\n+void clear_merge_options(struct merge_options *opt UNUSED)\n+{\n+\t; /* no-op as our copy is shallow right now */\n+}\n+\n+int parse_merge_opt(struct merge_options *opt, const char *s)\n+{\n+\tconst char *arg;\n+\n+\tif (!s || !*s)\n+\t\treturn -1;\n+\tif (!strcmp(s, \"ours\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n+\telse if (!strcmp(s, \"theirs\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n+\telse if (!strcmp(s, \"subtree\"))\n+\t\topt->subtree_shift = \"\";\n+\telse if (skip_prefix(s, \"subtree=\", &arg))\n+\t\topt->subtree_shift = arg;\n+\telse if (!strcmp(s, \"patience\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n+\telse if (!strcmp(s, \"histogram\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n+\t\tlong value = parse_algorithm_value(arg);\n+\t\tif (value < 0)\n+\t\t\treturn -1;\n+\t\t/* clear out previous settings */\n+\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n+\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n+\t\topt->xdl_opts |= value;\n+\t}\n+\telse if (!strcmp(s, \"ignore-space-change\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n+\telse if (!strcmp(s, \"ignore-all-space\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n+\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n+\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n+\telse if (!strcmp(s, \"renormalize\"))\n+\t\topt->renormalize = 1;\n+\telse if (!strcmp(s, \"no-renormalize\"))\n+\t\topt->renormalize = 0;\n+\telse if (!strcmp(s, \"no-renames\"))\n+\t\topt->detect_renames = 0;\n+\telse if (!strcmp(s, \"find-renames\")) {\n+\t\topt->detect_renames = 1;\n+\t\topt->rename_score = 0;\n+\t}\n+\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n+\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n+\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n+\t\t\treturn -1;\n+\t\topt->detect_renames = 1;\n+\t}\n+\t/*\n+\t * Please update $__git_merge_strategy_options in\n+\t * git-completion.bash when you add new options\n+\t */\n+\telse\n+\t\treturn -1;\n+\treturn 0;\n+}\ndiff --git a/merge-ort.h b/merge-ort.h\nindex b63bc5424e7..30750c03962 100644\n--- a/merge-ort.h\n+++ b/merge-ort.h\n@@ -1,10 +1,11 @@\n #ifndef MERGE_ORT_H\n #define MERGE_ORT_H\n \n-#include \"merge-recursive.h\"\n #include \"hash.h\"\n+#include \"strbuf.h\"\n \n struct commit;\n+struct commit_list;\n struct tree;\n struct strmap;\n \n@@ -44,6 +45,51 @@ struct merge_result {\n \tunsigned _properly_initialized;\n };\n \n+struct merge_options_internal;\n+struct merge_options {\n+\tstruct repository *repo;\n+\n+\t/* ref names used in console messages and conflict markers */\n+\tconst char *ancestor;\n+\tconst char *branch1;\n+\tconst char *branch2;\n+\n+\t/* rename related options */\n+\tint detect_renames;\n+\tenum {\n+\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n+\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n+\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n+\t} detect_directory_renames;\n+\tint rename_limit;\n+\tint rename_score;\n+\tint show_rename_progress;\n+\n+\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n+\tlong xdl_opts;\n+\tint conflict_style;\n+\tenum {\n+\t\tMERGE_VARIANT_NORMAL = 0,\n+\t\tMERGE_VARIANT_OURS,\n+\t\tMERGE_VARIANT_THEIRS\n+\t} recursive_variant;\n+\n+\t/* console output related options */\n+\tint verbosity;\n+\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n+\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n+\t\t\t\t * must handle and call strbuf_release */\n+\n+\t/* miscellaneous control options */\n+\tconst char *subtree_shift;\n+\tunsigned renormalize : 1;\n+\tunsigned record_conflict_msgs_as_headers : 1;\n+\tconst char *msg_header_prefix;\n+\n+\t/* internal fields used by the implementation */\n+\tstruct merge_options_internal *priv;\n+};\n+\n /* Mostly internal function also used by merge-ort-wrappers.c */\n struct commit *make_virtual_commit(struct repository *repo,\n \t\t\t\t   struct tree *tree,\n@@ -119,4 +165,16 @@ void merge_get_conflicted_files(struct merge_result *result,\n void merge_finalize(struct merge_options *opt,\n \t\t    struct merge_result *result);\n \n+\n+/* for use by porcelain commands */\n+void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n+/* for use by plumbing commands */\n+void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n+\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n+void clear_merge_options(struct merge_options *opt);\n+\n+/* parse the option in s and update the relevant field of opt */\n+int parse_merge_opt(struct merge_options *opt, const char *s);\n+\n #endif\ndiff --git a/merge-recursive.c b/merge-recursive.c\ndeleted file mode 100644\nindex f3df127ad9b..00000000000\n--- a/merge-recursive.c\n+++ /dev/null\n@@ -1,4080 +0,0 @@\n-/*\n- * Recursive Merge algorithm stolen from git-merge-recursive.py by\n- * Fredrik Kuivinen.\n- * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006\n- */\n-\n-#define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n-\n-#include \"git-compat-util.h\"\n-#include \"merge-recursive.h\"\n-\n-#include \"alloc.h\"\n-#include \"cache-tree.h\"\n-#include \"commit.h\"\n-#include \"commit-reach.h\"\n-#include \"config.h\"\n-#include \"diff.h\"\n-#include \"diffcore.h\"\n-#include \"dir.h\"\n-#include \"environment.h\"\n-#include \"gettext.h\"\n-#include \"hex.h\"\n-#include \"merge-ll.h\"\n-#include \"lockfile.h\"\n-#include \"match-trees.h\"\n-#include \"name-hash.h\"\n-#include \"object-file.h\"\n-#include \"object-name.h\"\n-#include \"object-store-ll.h\"\n-#include \"path.h\"\n-#include \"repository.h\"\n-#include \"revision.h\"\n-#include \"sparse-index.h\"\n-#include \"string-list.h\"\n-#include \"symlinks.h\"\n-#include \"tag.h\"\n-#include \"tree-walk.h\"\n-#include \"unpack-trees.h\"\n-#include \"xdiff-interface.h\"\n-\n-struct merge_options_internal {\n-\tint call_depth;\n-\tint needed_rename_limit;\n-\tstruct hashmap current_file_dir_set;\n-\tstruct string_list df_conflict_file_set;\n-\tstruct unpack_trees_options unpack_opts;\n-\tstruct index_state orig_index;\n-};\n-\n-struct path_hashmap_entry {\n-\tstruct hashmap_entry e;\n-\tchar path[FLEX_ARRAY];\n-};\n-\n-static int path_hashmap_cmp(const void *cmp_data UNUSED,\n-\t\t\t    const struct hashmap_entry *eptr,\n-\t\t\t    const struct hashmap_entry *entry_or_key,\n-\t\t\t    const void *keydata)\n-{\n-\tconst struct path_hashmap_entry *a, *b;\n-\tconst char *key = keydata;\n-\n-\ta = container_of(eptr, const struct path_hashmap_entry, e);\n-\tb = container_of(entry_or_key, const struct path_hashmap_entry, e);\n-\n-\treturn fspathcmp(a->path, key ? key : b->path);\n-}\n-\n-/*\n- * For dir_rename_entry, directory names are stored as a full path from the\n- * toplevel of the repository and do not include a trailing '/'.  Also:\n- *\n- *   dir:                original name of directory being renamed\n- *   non_unique_new_dir: if true, could not determine new_dir\n- *   new_dir:            final name of directory being renamed\n- *   possible_new_dirs:  temporary used to help determine new_dir; see comments\n- *                       in get_directory_renames() for details\n- */\n-struct dir_rename_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *dir;\n-\tunsigned non_unique_new_dir:1;\n-\tstruct strbuf new_dir;\n-\tstruct string_list possible_new_dirs;\n-};\n-\n-static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t      char *dir)\n-{\n-\tstruct dir_rename_entry key;\n-\n-\tif (!dir)\n-\t\treturn NULL;\n-\thashmap_entry_init(&key.ent, strhash(dir));\n-\tkey.dir = dir;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int dir_rename_cmp(const void *cmp_data UNUSED,\n-\t\t\t  const struct hashmap_entry *eptr,\n-\t\t\t  const struct hashmap_entry *entry_or_key,\n-\t\t\t  const void *keydata UNUSED)\n-{\n-\tconst struct dir_rename_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct dir_rename_entry, ent);\n-\te2 = container_of(entry_or_key, const struct dir_rename_entry, ent);\n-\n-\treturn strcmp(e1->dir, e2->dir);\n-}\n-\n-static void dir_rename_init(struct hashmap *map)\n-{\n-\thashmap_init(map, dir_rename_cmp, NULL, 0);\n-}\n-\n-static void dir_rename_entry_init(struct dir_rename_entry *entry,\n-\t\t\t\t  char *directory)\n-{\n-\thashmap_entry_init(&entry->ent, strhash(directory));\n-\tentry->dir = directory;\n-\tentry->non_unique_new_dir = 0;\n-\tstrbuf_init(&entry->new_dir, 0);\n-\tstring_list_init_nodup(&entry->possible_new_dirs);\n-}\n-\n-struct collision_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *target_file;\n-\tstruct string_list source_files;\n-\tunsigned reported_already:1;\n-};\n-\n-static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t    char *target_file)\n-{\n-\tstruct collision_entry key;\n-\n-\thashmap_entry_init(&key.ent, strhash(target_file));\n-\tkey.target_file = target_file;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int collision_cmp(const void *cmp_data UNUSED,\n-\t\t\t const struct hashmap_entry *eptr,\n-\t\t\t const struct hashmap_entry *entry_or_key,\n-\t\t\t const void *keydata UNUSED)\n-{\n-\tconst struct collision_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct collision_entry, ent);\n-\te2 = container_of(entry_or_key, const struct collision_entry, ent);\n-\n-\treturn strcmp(e1->target_file, e2->target_file);\n-}\n-\n-static void collision_init(struct hashmap *map)\n-{\n-\thashmap_init(map, collision_cmp, NULL, 0);\n-}\n-\n-static void flush_output(struct merge_options *opt)\n-{\n-\tif (opt->buffer_output < 2 && opt->obuf.len) {\n-\t\tfputs(opt->obuf.buf, stdout);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-}\n-\n-__attribute__((format (printf, 2, 3)))\n-static int err(struct merge_options *opt, const char *err, ...)\n-{\n-\tva_list params;\n-\n-\tif (opt->buffer_output < 2)\n-\t\tflush_output(opt);\n-\telse {\n-\t\tstrbuf_complete(&opt->obuf, '\\n');\n-\t\tstrbuf_addstr(&opt->obuf, \"error: \");\n-\t}\n-\tva_start(params, err);\n-\tstrbuf_vaddf(&opt->obuf, err, params);\n-\tva_end(params);\n-\tif (opt->buffer_output > 1)\n-\t\tstrbuf_addch(&opt->obuf, '\\n');\n-\telse {\n-\t\terror(\"%s\", opt->obuf.buf);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-\n-\treturn -1;\n-}\n-\n-static struct tree *shift_tree_object(struct repository *repo,\n-\t\t\t\t      struct tree *one, struct tree *two,\n-\t\t\t\t      const char *subtree_shift)\n-{\n-\tstruct object_id shifted;\n-\n-\tif (!*subtree_shift) {\n-\t\tshift_tree(repo, &one->object.oid, &two->object.oid, &shifted, 0);\n-\t} else {\n-\t\tshift_tree_by(repo, &one->object.oid, &two->object.oid, &shifted,\n-\t\t\t      subtree_shift);\n-\t}\n-\tif (oideq(&two->object.oid, &shifted))\n-\t\treturn two;\n-\treturn lookup_tree(repo, &shifted);\n-}\n-\n-static inline void set_commit_tree(struct commit *c, struct tree *t)\n-{\n-\tc->maybe_tree = t;\n-}\n-\n-static struct commit *make_virtual_commit(struct repository *repo,\n-\t\t\t\t\t  struct tree *tree,\n-\t\t\t\t\t  const char *comment)\n-{\n-\tstruct commit *commit = alloc_commit_node(repo);\n-\n-\tset_merge_remote_desc(commit, comment, (struct object *)commit);\n-\tset_commit_tree(commit, tree);\n-\tcommit->object.parsed = 1;\n-\treturn commit;\n-}\n-\n-enum rename_type {\n-\tRENAME_NORMAL = 0,\n-\tRENAME_VIA_DIR,\n-\tRENAME_ADD,\n-\tRENAME_DELETE,\n-\tRENAME_ONE_FILE_TO_ONE,\n-\tRENAME_ONE_FILE_TO_TWO,\n-\tRENAME_TWO_FILES_TO_ONE\n-};\n-\n-/*\n- * Since we want to write the index eventually, we cannot reuse the index\n- * for these (temporary) data.\n- */\n-struct stage_data {\n-\tstruct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */\n-\tstruct rename_conflict_info *rename_conflict_info;\n-\tunsigned processed:1,\n-\t\t rename_conflict_info_owned:1;\n-};\n-\n-struct rename {\n-\tunsigned processed:1;\n-\tstruct diff_filepair *pair;\n-\tconst char *branch; /* branch that the rename occurred on */\n-\t/*\n-\t * If directory rename detection affected this rename, what was its\n-\t * original type ('A' or 'R') and it's original destination before\n-\t * the directory rename (otherwise, '\\0' and NULL for these two vars).\n-\t */\n-\tchar dir_rename_original_type;\n-\tchar *dir_rename_original_dest;\n-\t/*\n-\t * Purpose of src_entry and dst_entry:\n-\t *\n-\t * If 'before' is renamed to 'after' then src_entry will contain\n-\t * the versions of 'before' from the merge_base, HEAD, and MERGE in\n-\t * stages 1, 2, and 3; dst_entry will contain the respective\n-\t * versions of 'after' in corresponding locations.  Thus, we have a\n-\t * total of six modes and oids, though some will be null.  (Stage 0\n-\t * is ignored; we're interested in handling conflicts.)\n-\t *\n-\t * Since we don't turn on break-rewrites by default, neither\n-\t * src_entry nor dst_entry can have all three of their stages have\n-\t * non-null oids, meaning at most four of the six will be non-null.\n-\t * Also, since this is a rename, both src_entry and dst_entry will\n-\t * have at least one non-null oid, meaning at least two will be\n-\t * non-null.  Of the six oids, a typical rename will have three be\n-\t * non-null.  Only two implies a rename/delete, and four implies a\n-\t * rename/add.\n-\t */\n-\tstruct stage_data *src_entry;\n-\tstruct stage_data *dst_entry;\n-};\n-\n-struct rename_conflict_info {\n-\tenum rename_type rename_type;\n-\tstruct rename *ren1;\n-\tstruct rename *ren2;\n-};\n-\n-static inline void setup_rename_conflict_info(enum rename_type rename_type,\n-\t\t\t\t\t      struct merge_options *opt,\n-\t\t\t\t\t      struct rename *ren1,\n-\t\t\t\t\t      struct rename *ren2)\n-{\n-\tstruct rename_conflict_info *ci;\n-\n-\t/*\n-\t * When we have two renames involved, it's easiest to get the\n-\t * correct things into stage 2 and 3, and to make sure that the\n-\t * content merge puts HEAD before the other branch if we just\n-\t * ensure that branch1 == opt->branch1.  So, simply flip arguments\n-\t * around if we don't have that.\n-\t */\n-\tif (ren2 && ren1->branch != opt->branch1) {\n-\t\tsetup_rename_conflict_info(rename_type, opt, ren2, ren1);\n-\t\treturn;\n-\t}\n-\n-\tCALLOC_ARRAY(ci, 1);\n-\tci->rename_type = rename_type;\n-\tci->ren1 = ren1;\n-\tci->ren2 = ren2;\n-\n-\tci->ren1->dst_entry->processed = 0;\n-\tci->ren1->dst_entry->rename_conflict_info = ci;\n-\tci->ren1->dst_entry->rename_conflict_info_owned = 1;\n-\tif (ren2) {\n-\t\tci->ren2->dst_entry->rename_conflict_info = ci;\n-\t}\n-}\n-\n-static int show(struct merge_options *opt, int v)\n-{\n-\treturn (!opt->priv->call_depth && opt->verbosity >= v) ||\n-\t\topt->verbosity >= 5;\n-}\n-\n-__attribute__((format (printf, 3, 4)))\n-static void output(struct merge_options *opt, int v, const char *fmt, ...)\n-{\n-\tva_list ap;\n-\n-\tif (!show(opt, v))\n-\t\treturn;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\n-\tva_start(ap, fmt);\n-\tstrbuf_vaddf(&opt->obuf, fmt, ap);\n-\tva_end(ap);\n-\n-\tstrbuf_addch(&opt->obuf, '\\n');\n-\tif (!opt->buffer_output)\n-\t\tflush_output(opt);\n-}\n-\n-static void repo_output_commit_title(struct merge_options *opt,\n-\t\t\t\t     struct repository *repo,\n-\t\t\t\t     struct commit *commit)\n-{\n-\tstruct merge_remote_desc *desc;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\tdesc = merge_remote_util(commit);\n-\tif (desc)\n-\t\tstrbuf_addf(&opt->obuf, \"virtual %s\\n\", desc->name);\n-\telse {\n-\t\tstrbuf_repo_add_unique_abbrev(&opt->obuf, repo,\n-\t\t\t\t\t      &commit->object.oid,\n-\t\t\t\t\t      DEFAULT_ABBREV);\n-\t\tstrbuf_addch(&opt->obuf, ' ');\n-\t\tif (repo_parse_commit(repo, commit) != 0)\n-\t\t\tstrbuf_addstr(&opt->obuf, _(\"(bad commit)\\n\"));\n-\t\telse {\n-\t\t\tconst char *title;\n-\t\t\tconst char *msg = repo_get_commit_buffer(repo, commit, NULL);\n-\t\t\tint len = find_commit_subject(msg, &title);\n-\t\t\tif (len)\n-\t\t\t\tstrbuf_addf(&opt->obuf, \"%.*s\\n\", len, title);\n-\t\t\trepo_unuse_commit_buffer(repo, commit, msg);\n-\t\t}\n-\t}\n-\tflush_output(opt);\n-}\n-\n-static void output_commit_title(struct merge_options *opt, struct commit *commit)\n-{\n-\trepo_output_commit_title(opt, the_repository, commit);\n-}\n-\n-static int add_cacheinfo(struct merge_options *opt,\n-\t\t\t const struct diff_filespec *blob,\n-\t\t\t const char *path, int stage, int refresh, int options)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tstruct cache_entry *ce;\n-\tint ret;\n-\n-\tce = make_cache_entry(istate, blob->mode, &blob->oid, path, stage, 0);\n-\tif (!ce)\n-\t\treturn err(opt, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n-\n-\tret = add_index_entry(istate, ce, options);\n-\tif (refresh) {\n-\t\tstruct cache_entry *nce;\n-\n-\t\tnce = refresh_cache_entry(istate, ce,\n-\t\t\t\t\t  CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);\n-\t\tif (!nce)\n-\t\t\treturn err(opt, _(\"add_cacheinfo failed to refresh for path '%s'; merge aborting.\"), path);\n-\t\tif (nce != ce)\n-\t\t\tret = add_index_entry(istate, nce, options);\n-\t}\n-\treturn ret;\n-}\n-\n-static inline int merge_detect_rename(struct merge_options *opt)\n-{\n-\treturn (opt->detect_renames >= 0) ? opt->detect_renames : 1;\n-}\n-\n-static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)\n-{\n-\tif (parse_tree(tree) < 0)\n-\t\texit(128);\n-\tinit_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size);\n-}\n-\n-static int unpack_trees_start(struct merge_options *opt,\n-\t\t\t      struct tree *common,\n-\t\t\t      struct tree *head,\n-\t\t\t      struct tree *merge)\n-{\n-\tint rc;\n-\tstruct tree_desc t[3];\n-\tstruct index_state tmp_index = INDEX_STATE_INIT(opt->repo);\n-\n-\tmemset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));\n-\tif (opt->priv->call_depth)\n-\t\topt->priv->unpack_opts.index_only = 1;\n-\telse {\n-\t\topt->priv->unpack_opts.update = 1;\n-\t\t/* FIXME: should only do this if !overwrite_ignore */\n-\t\topt->priv->unpack_opts.preserve_ignored = 0;\n-\t}\n-\topt->priv->unpack_opts.merge = 1;\n-\topt->priv->unpack_opts.head_idx = 2;\n-\topt->priv->unpack_opts.fn = threeway_merge;\n-\topt->priv->unpack_opts.src_index = opt->repo->index;\n-\topt->priv->unpack_opts.dst_index = &tmp_index;\n-\topt->priv->unpack_opts.aggressive = !merge_detect_rename(opt);\n-\tsetup_unpack_trees_porcelain(&opt->priv->unpack_opts, \"merge\");\n-\n-\tinit_tree_desc_from_tree(t+0, common);\n-\tinit_tree_desc_from_tree(t+1, head);\n-\tinit_tree_desc_from_tree(t+2, merge);\n-\n-\trc = unpack_trees(3, t, &opt->priv->unpack_opts);\n-\tcache_tree_free(&opt->repo->index->cache_tree);\n-\n-\t/*\n-\t * Update opt->repo->index to match the new results, AFTER saving a\n-\t * copy in opt->priv->orig_index.  Update src_index to point to the\n-\t * saved copy.  (verify_uptodate() checks src_index, and the original\n-\t * index is the one that had the necessary modification timestamps.)\n-\t */\n-\topt->priv->orig_index = *opt->repo->index;\n-\t*opt->repo->index = tmp_index;\n-\topt->priv->unpack_opts.src_index = &opt->priv->orig_index;\n-\n-\treturn rc;\n-}\n-\n-static void unpack_trees_finish(struct merge_options *opt)\n-{\n-\tdiscard_index(&opt->priv->orig_index);\n-\tclear_unpack_trees_porcelain(&opt->priv->unpack_opts);\n-}\n-\n-static int save_files_dirs(const struct object_id *oid UNUSED,\n-\t\t\t   struct strbuf *base, const char *path,\n-\t\t\t   unsigned int mode, void *context)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tint baselen = base->len;\n-\tstruct merge_options *opt = context;\n-\n-\tstrbuf_addstr(base, path);\n-\n-\tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\n-\tstrbuf_setlen(base, baselen);\n-\treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n-}\n-\n-static void get_files_dirs(struct merge_options *opt, struct tree *tree)\n-{\n-\tstruct pathspec match_all;\n-\tmemset(&match_all, 0, sizeof(match_all));\n-\tread_tree(opt->repo, tree,\n-\t\t  &match_all, save_files_dirs, opt);\n-}\n-\n-static int get_tree_entry_if_blob(struct repository *r,\n-\t\t\t\t  const struct object_id *tree,\n-\t\t\t\t  const char *path,\n-\t\t\t\t  struct diff_filespec *dfs)\n-{\n-\tint ret;\n-\n-\tret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);\n-\tif (S_ISDIR(dfs->mode)) {\n-\t\toidcpy(&dfs->oid, null_oid());\n-\t\tdfs->mode = 0;\n-\t}\n-\treturn ret;\n-}\n-\n-/*\n- * Returns an index_entry instance which doesn't have to correspond to\n- * a real cache entry in Git's index.\n- */\n-static struct stage_data *insert_stage_data(struct repository *r,\n-\t\tconst char *path,\n-\t\tstruct tree *o, struct tree *a, struct tree *b,\n-\t\tstruct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tstruct stage_data *e = xcalloc(1, sizeof(struct stage_data));\n-\tget_tree_entry_if_blob(r, &o->object.oid, path, &e->stages[1]);\n-\tget_tree_entry_if_blob(r, &a->object.oid, path, &e->stages[2]);\n-\tget_tree_entry_if_blob(r, &b->object.oid, path, &e->stages[3]);\n-\titem = string_list_insert(entries, path);\n-\titem->util = e;\n-\treturn e;\n-}\n-\n-/*\n- * Create a dictionary mapping file names to stage_data objects. The\n- * dictionary contains one entry for every path with a non-zero stage entry.\n- */\n-static struct string_list *get_unmerged(struct index_state *istate)\n-{\n-\tstruct string_list *unmerged = xmalloc(sizeof(struct string_list));\n-\tint i;\n-\n-\tstring_list_init_dup(unmerged);\n-\n-\t/* TODO: audit for interaction with sparse-index. */\n-\tensure_full_index(istate);\n-\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct stage_data *e;\n-\t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_stage(ce))\n-\t\t\tcontinue;\n-\n-\t\titem = string_list_lookup(unmerged, ce->name);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(unmerged, ce->name);\n-\t\t\titem->util = xcalloc(1, sizeof(struct stage_data));\n-\t\t}\n-\t\te = item->util;\n-\t\te->stages[ce_stage(ce)].mode = ce->ce_mode;\n-\t\toidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid);\n-\t}\n-\n-\treturn unmerged;\n-}\n-\n-static int string_list_df_name_compare(const char *one, const char *two)\n-{\n-\tint onelen = strlen(one);\n-\tint twolen = strlen(two);\n-\t/*\n-\t * Here we only care that entries for D/F conflicts are\n-\t * adjacent, in particular with the file of the D/F conflict\n-\t * appearing before files below the corresponding directory.\n-\t * The order of the rest of the list is irrelevant for us.\n-\t *\n-\t * To achieve this, we sort with df_name_compare and provide\n-\t * the mode S_IFDIR so that D/F conflicts will sort correctly.\n-\t * We use the mode S_IFDIR for everything else for simplicity,\n-\t * since in other cases any changes in their order due to\n-\t * sorting cause no problems for us.\n-\t */\n-\tint cmp = df_name_compare(one, onelen, S_IFDIR,\n-\t\t\t\t  two, twolen, S_IFDIR);\n-\t/*\n-\t * Now that 'foo' and 'foo/bar' compare equal, we have to make sure\n-\t * that 'foo' comes before 'foo/bar'.\n-\t */\n-\tif (cmp)\n-\t\treturn cmp;\n-\treturn onelen - twolen;\n-}\n-\n-static void record_df_conflict_files(struct merge_options *opt,\n-\t\t\t\t     struct string_list *entries)\n-{\n-\t/* If there is a D/F conflict and the file for such a conflict\n-\t * currently exists in the working tree, we want to allow it to be\n-\t * removed to make room for the corresponding directory if needed.\n-\t * The files underneath the directories of such D/F conflicts will\n-\t * be processed before the corresponding file involved in the D/F\n-\t * conflict.  If the D/F directory ends up being removed by the\n-\t * merge, then we won't have to touch the D/F file.  If the D/F\n-\t * directory needs to be written to the working copy, then the D/F\n-\t * file will simply be removed (in make_room_for_path()) to make\n-\t * room for the necessary paths.  Note that if both the directory\n-\t * and the file need to be present, then the D/F file will be\n-\t * reinstated with a new unique name at the time it is processed.\n-\t */\n-\tstruct string_list df_sorted_entries = STRING_LIST_INIT_NODUP;\n-\tconst char *last_file = NULL;\n-\tint last_len = 0;\n-\tint i;\n-\n-\t/*\n-\t * If we're merging merge-bases, we don't want to bother with\n-\t * any working directory changes.\n-\t */\n-\tif (opt->priv->call_depth)\n-\t\treturn;\n-\n-\t/* Ensure D/F conflicts are adjacent in the entries list. */\n-\tfor (i = 0; i < entries->nr; i++) {\n-\t\tstruct string_list_item *next = &entries->items[i];\n-\t\tstring_list_append(&df_sorted_entries, next->string)->util =\n-\t\t\t\t   next->util;\n-\t}\n-\tdf_sorted_entries.cmp = string_list_df_name_compare;\n-\tstring_list_sort(&df_sorted_entries);\n-\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 1);\n-\tfor (i = 0; i < df_sorted_entries.nr; i++) {\n-\t\tconst char *path = df_sorted_entries.items[i].string;\n-\t\tint len = strlen(path);\n-\t\tstruct stage_data *e = df_sorted_entries.items[i].util;\n-\n-\t\t/*\n-\t\t * Check if last_file & path correspond to a D/F conflict;\n-\t\t * i.e. whether path is last_file+'/'+<something>.\n-\t\t * If so, record that it's okay to remove last_file to make\n-\t\t * room for path and friends if needed.\n-\t\t */\n-\t\tif (last_file &&\n-\t\t    len > last_len &&\n-\t\t    memcmp(path, last_file, last_len) == 0 &&\n-\t\t    path[last_len] == '/') {\n-\t\t\tstring_list_insert(&opt->priv->df_conflict_file_set, last_file);\n-\t\t}\n-\n-\t\t/*\n-\t\t * Determine whether path could exist as a file in the\n-\t\t * working directory as a possible D/F conflict.  This\n-\t\t * will only occur when it exists in stage 2 as a\n-\t\t * file.\n-\t\t */\n-\t\tif (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) {\n-\t\t\tlast_file = path;\n-\t\t\tlast_len = len;\n-\t\t} else {\n-\t\t\tlast_file = NULL;\n-\t\t}\n-\t}\n-\tstring_list_clear(&df_sorted_entries, 0);\n-}\n-\n-static int update_stages(struct merge_options *opt, const char *path,\n-\t\t\t const struct diff_filespec *o,\n-\t\t\t const struct diff_filespec *a,\n-\t\t\t const struct diff_filespec *b)\n-{\n-\n-\t/*\n-\t * NOTE: It is usually a bad idea to call update_stages on a path\n-\t * before calling update_file on that same path, since it can\n-\t * sometimes lead to spurious \"refusing to lose untracked file...\"\n-\t * messages from update_file (via make_room_for path via\n-\t * would_lose_untracked).  Instead, reverse the order of the calls\n-\t * (executing update_file first and then update_stages).\n-\t */\n-\tint clear = 1;\n-\tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;\n-\tif (clear)\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\tif (o)\n-\t\tif (add_cacheinfo(opt, o, path, 1, 0, options))\n-\t\t\treturn -1;\n-\tif (a)\n-\t\tif (add_cacheinfo(opt, a, path, 2, 0, options))\n-\t\t\treturn -1;\n-\tif (b)\n-\t\tif (add_cacheinfo(opt, b, path, 3, 0, options))\n-\t\t\treturn -1;\n-\treturn 0;\n-}\n-\n-static void update_entry(struct stage_data *entry,\n-\t\t\t struct diff_filespec *o,\n-\t\t\t struct diff_filespec *a,\n-\t\t\t struct diff_filespec *b)\n-{\n-\tentry->processed = 0;\n-\tentry->stages[1].mode = o->mode;\n-\tentry->stages[2].mode = a->mode;\n-\tentry->stages[3].mode = b->mode;\n-\toidcpy(&entry->stages[1].oid, &o->oid);\n-\toidcpy(&entry->stages[2].oid, &a->oid);\n-\toidcpy(&entry->stages[3].oid, &b->oid);\n-}\n-\n-static int remove_file(struct merge_options *opt, int clean,\n-\t\t       const char *path, int no_wd)\n-{\n-\tint update_cache = opt->priv->call_depth || clean;\n-\tint update_working_directory = !opt->priv->call_depth && !no_wd;\n-\n-\tif (update_cache) {\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\t}\n-\tif (update_working_directory) {\n-\t\tif (ignore_case) {\n-\t\t\tstruct cache_entry *ce;\n-\t\t\tce = index_file_exists(opt->repo->index, path, strlen(path),\n-\t\t\t\t\t       ignore_case);\n-\t\t\tif (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))\n-\t\t\t\treturn 0;\n-\t\t}\n-\t\tif (remove_path(path))\n-\t\t\treturn -1;\n-\t}\n-\treturn 0;\n-}\n-\n-/* add a string to a strbuf, but converting \"/\" to \"_\" */\n-static void add_flattened_path(struct strbuf *out, const char *s)\n-{\n-\tsize_t i = out->len;\n-\tstrbuf_addstr(out, s);\n-\tfor (; i < out->len; i++)\n-\t\tif (out->buf[i] == '/')\n-\t\t\tout->buf[i] = '_';\n-}\n-\n-static char *unique_path(struct merge_options *opt,\n-\t\t\t const char *path,\n-\t\t\t const char *branch)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tstruct strbuf newpath = STRBUF_INIT;\n-\tint suffix = 0;\n-\tsize_t base_len;\n-\n-\tstrbuf_addf(&newpath, \"%s~\", path);\n-\tadd_flattened_path(&newpath, branch);\n-\n-\tbase_len = newpath.len;\n-\twhile (hashmap_get_from_hash(&opt->priv->current_file_dir_set,\n-\t\t\t\t     fspathhash(newpath.buf), newpath.buf) ||\n-\t       (!opt->priv->call_depth && file_exists(newpath.buf))) {\n-\t\tstrbuf_setlen(&newpath, base_len);\n-\t\tstrbuf_addf(&newpath, \"_%d\", suffix++);\n-\t}\n-\n-\tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\treturn strbuf_detach(&newpath, NULL);\n-}\n-\n-/**\n- * Check whether a directory in the index is in the way of an incoming\n- * file.  Return 1 if so.  If check_working_copy is non-zero, also\n- * check the working directory.  If empty_ok is non-zero, also return\n- * 0 in the case where the working-tree dir exists but is empty.\n- */\n-static int dir_in_way(struct index_state *istate, const char *path,\n-\t\t      int check_working_copy, int empty_ok)\n-{\n-\tint pos;\n-\tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct stat st;\n-\n-\tstrbuf_addstr(&dirpath, path);\n-\tstrbuf_addch(&dirpath, '/');\n-\n-\tpos = index_name_pos(istate, dirpath.buf, dirpath.len);\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\tif (pos < istate->cache_nr &&\n-\t    !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {\n-\t\tstrbuf_release(&dirpath);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_release(&dirpath);\n-\treturn check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&\n-\t\t!(empty_ok && is_empty_dir(path)) &&\n-\t\t!has_symlink_leading_path(path, strlen(path));\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started,\n- * and its oid and mode match the specified values\n- */\n-static int was_tracked_and_matches(struct merge_options *opt, const char *path,\n-\t\t\t\t   const struct diff_filespec *blob)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\tstruct cache_entry *ce;\n-\n-\tif (0 > pos)\n-\t\t/* we were not tracking this path before the merge */\n-\t\treturn 0;\n-\n-\t/* See if the file we were tracking before matches */\n-\tce = opt->priv->orig_index.cache[pos];\n-\treturn (oideq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started\n- */\n-static int was_tracked(struct merge_options *opt, const char *path)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\n-\tif (0 <= pos)\n-\t\t/* we were tracking this path before the merge */\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-static int would_lose_untracked(struct merge_options *opt, const char *path)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\n-\t/*\n-\t * This may look like it can be simplified to:\n-\t *   return !was_tracked(opt, path) && file_exists(path)\n-\t * but it can't.  This function needs to know whether path was in\n-\t * the working tree due to EITHER having been tracked in the index\n-\t * before the merge OR having been put into the working copy and\n-\t * index by unpack_trees().  Due to that either-or requirement, we\n-\t * check the current index instead of the original one.\n-\t *\n-\t * Note that we do not need to worry about merge-recursive itself\n-\t * updating the index after unpack_trees() and before calling this\n-\t * function, because we strictly require all code paths in\n-\t * merge-recursive to update the working tree first and the index\n-\t * second.  Doing otherwise would break\n-\t * update_file()/would_lose_untracked(); see every comment in this\n-\t * file which mentions \"update_stages\".\n-\t */\n-\tint pos = index_name_pos(istate, path, strlen(path));\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\twhile (pos < istate->cache_nr &&\n-\t       !strcmp(path, istate->cache[pos]->name)) {\n-\t\t/*\n-\t\t * If stage #0, it is definitely tracked.\n-\t\t * If it has stage #2 then it was tracked\n-\t\t * before this merge started.  All other\n-\t\t * cases the path was not tracked.\n-\t\t */\n-\t\tswitch (ce_stage(istate->cache[pos])) {\n-\t\tcase 0:\n-\t\tcase 2:\n-\t\t\treturn 0;\n-\t\t}\n-\t\tpos++;\n-\t}\n-\treturn file_exists(path);\n-}\n-\n-static int was_dirty(struct merge_options *opt, const char *path)\n-{\n-\tstruct cache_entry *ce;\n-\tint dirty = 1;\n-\n-\tif (opt->priv->call_depth || !was_tracked(opt, path))\n-\t\treturn !dirty;\n-\n-\tce = index_file_exists(opt->priv->unpack_opts.src_index,\n-\t\t\t       path, strlen(path), ignore_case);\n-\tdirty = verify_uptodate(ce, &opt->priv->unpack_opts) != 0;\n-\treturn dirty;\n-}\n-\n-static int make_room_for_path(struct merge_options *opt, const char *path)\n-{\n-\tint status, i;\n-\tconst char *msg = _(\"failed to create path '%s'%s\");\n-\n-\t/* Unlink any D/F conflict files that are in the way */\n-\tfor (i = 0; i < opt->priv->df_conflict_file_set.nr; i++) {\n-\t\tconst char *df_path = opt->priv->df_conflict_file_set.items[i].string;\n-\t\tsize_t pathlen = strlen(path);\n-\t\tsize_t df_pathlen = strlen(df_path);\n-\t\tif (df_pathlen < pathlen &&\n-\t\t    path[df_pathlen] == '/' &&\n-\t\t    strncmp(path, df_path, df_pathlen) == 0) {\n-\t\t\toutput(opt, 3,\n-\t\t\t       _(\"Removing %s to make room for subdirectory\\n\"),\n-\t\t\t       df_path);\n-\t\t\tunlink(df_path);\n-\t\t\tunsorted_string_list_delete_item(&opt->priv->df_conflict_file_set,\n-\t\t\t\t\t\t\t i, 0);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\t/* Make sure leading directories are created */\n-\tstatus = safe_create_leading_directories_const(path);\n-\tif (status) {\n-\t\tif (status == SCLD_EXISTS)\n-\t\t\t/* something else exists */\n-\t\t\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-\t\treturn err(opt, msg, path, \"\");\n-\t}\n-\n-\t/*\n-\t * Do not unlink a file in the work tree if we are not\n-\t * tracking it.\n-\t */\n-\tif (would_lose_untracked(opt, path))\n-\t\treturn err(opt, _(\"refusing to lose untracked file at '%s'\"),\n-\t\t\t   path);\n-\n-\t/* Successful unlink is good.. */\n-\tif (!unlink(path))\n-\t\treturn 0;\n-\t/* .. and so is no existing file */\n-\tif (errno == ENOENT)\n-\t\treturn 0;\n-\t/* .. but not some other error (who really cares what?) */\n-\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-}\n-\n-static int update_file_flags(struct merge_options *opt,\n-\t\t\t     const struct diff_filespec *contents,\n-\t\t\t     const char *path,\n-\t\t\t     int update_cache,\n-\t\t\t     int update_wd)\n-{\n-\tint ret = 0;\n-\n-\tif (opt->priv->call_depth)\n-\t\tupdate_wd = 0;\n-\n-\tif (update_wd) {\n-\t\tenum object_type type;\n-\t\tvoid *buf;\n-\t\tunsigned long size;\n-\n-\t\tif (S_ISGITLINK(contents->mode)) {\n-\t\t\t/*\n-\t\t\t * We may later decide to recursively descend into\n-\t\t\t * the submodule directory and update its index\n-\t\t\t * and/or work tree, but we do not do that now.\n-\t\t\t */\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto update_index;\n-\t\t}\n-\n-\t\tbuf = repo_read_object_file(the_repository, &contents->oid,\n-\t\t\t\t\t    &type, &size);\n-\t\tif (!buf) {\n-\t\t\tret = err(opt, _(\"cannot read object %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (type != OBJ_BLOB) {\n-\t\t\tret = err(opt, _(\"blob expected for %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode)) {\n-\t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(opt->repo->index,\n-\t\t\t\t\t\t    path, buf, size, &strbuf, NULL)) {\n-\t\t\t\tfree(buf);\n-\t\t\t\tsize = strbuf.len;\n-\t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (make_room_for_path(opt, path) < 0) {\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode) ||\n-\t\t    (!has_symlinks && S_ISLNK(contents->mode))) {\n-\t\t\tint fd;\n-\t\t\tint mode = (contents->mode & 0100 ? 0777 : 0666);\n-\n-\t\t\tfd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);\n-\t\t\tif (fd < 0) {\n-\t\t\t\tret = err(opt, _(\"failed to open '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\t\tgoto free_buf;\n-\t\t\t}\n-\t\t\twrite_in_full(fd, buf, size);\n-\t\t\tclose(fd);\n-\t\t} else if (S_ISLNK(contents->mode)) {\n-\t\t\tchar *lnk = xmemdupz(buf, size);\n-\t\t\tsafe_create_leading_directories_const(path);\n-\t\t\tunlink(path);\n-\t\t\tif (symlink(lnk, path))\n-\t\t\t\tret = err(opt, _(\"failed to symlink '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\tfree(lnk);\n-\t\t} else\n-\t\t\tret = err(opt,\n-\t\t\t\t  _(\"do not know what to do with %06o %s '%s'\"),\n-\t\t\t\t  contents->mode, oid_to_hex(&contents->oid), path);\n-\tfree_buf:\n-\t\tfree(buf);\n-\t}\n-update_index:\n-\tif (!ret && update_cache) {\n-\t\tint refresh = (!opt->priv->call_depth &&\n-\t\t\t       contents->mode != S_IFGITLINK);\n-\t\tif (add_cacheinfo(opt, contents, path, 0, refresh,\n-\t\t\t\t  ADD_CACHE_OK_TO_ADD))\n-\t\t\treturn -1;\n-\t}\n-\treturn ret;\n-}\n-\n-static int update_file(struct merge_options *opt,\n-\t\t       int clean,\n-\t\t       const struct diff_filespec *contents,\n-\t\t       const char *path)\n-{\n-\treturn update_file_flags(opt, contents, path,\n-\t\t\t\t opt->priv->call_depth || clean, !opt->priv->call_depth);\n-}\n-\n-/* Low level file merging, update and removal */\n-\n-struct merge_file_info {\n-\tstruct diff_filespec blob; /* mostly use oid & mode; sometimes path */\n-\tunsigned clean:1,\n-\t\t merge:1;\n-};\n-\n-static int merge_3way(struct merge_options *opt,\n-\t\t      mmbuffer_t *result_buf,\n-\t\t      const struct diff_filespec *o,\n-\t\t      const struct diff_filespec *a,\n-\t\t      const struct diff_filespec *b,\n-\t\t      const char *branch1,\n-\t\t      const char *branch2,\n-\t\t      const int extra_marker_size)\n-{\n-\tmmfile_t orig, src1, src2;\n-\tstruct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;\n-\tchar *base, *name1, *name2;\n-\tenum ll_merge_result merge_status;\n-\n-\tll_opts.renormalize = opt->renormalize;\n-\tll_opts.extra_marker_size = extra_marker_size;\n-\tll_opts.xdl_opts = opt->xdl_opts;\n-\tll_opts.conflict_style = opt->conflict_style;\n-\n-\tif (opt->priv->call_depth) {\n-\t\tll_opts.virtual_ancestor = 1;\n-\t\tll_opts.variant = 0;\n-\t} else {\n-\t\tswitch (opt->recursive_variant) {\n-\t\tcase MERGE_VARIANT_OURS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_OURS;\n-\t\t\tbreak;\n-\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_THEIRS;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tll_opts.variant = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tassert(a->path && b->path && o->path && opt->ancestor);\n-\tif (strcmp(a->path, b->path) || strcmp(a->path, o->path) != 0) {\n-\t\tbase  = mkpathdup(\"%s:%s\", opt->ancestor, o->path);\n-\t\tname1 = mkpathdup(\"%s:%s\", branch1, a->path);\n-\t\tname2 = mkpathdup(\"%s:%s\", branch2, b->path);\n-\t} else {\n-\t\tbase  = mkpathdup(\"%s\", opt->ancestor);\n-\t\tname1 = mkpathdup(\"%s\", branch1);\n-\t\tname2 = mkpathdup(\"%s\", branch2);\n-\t}\n-\n-\tread_mmblob(&orig, &o->oid);\n-\tread_mmblob(&src1, &a->oid);\n-\tread_mmblob(&src2, &b->oid);\n-\n-\t/*\n-\t * FIXME: Using a->path for normalization rules in ll_merge could be\n-\t * wrong if we renamed from a->path to b->path.  We should use the\n-\t * target path for where the file will be written.\n-\t */\n-\tmerge_status = ll_merge(result_buf, a->path, &orig, base,\n-\t\t\t\t&src1, name1, &src2, name2,\n-\t\t\t\topt->repo->index, &ll_opts);\n-\tif (merge_status == LL_MERGE_BINARY_CONFLICT)\n-\t\twarning(\"Cannot merge binary files: %s (%s vs. %s)\",\n-\t\t\ta->path, name1, name2);\n-\n-\tfree(base);\n-\tfree(name1);\n-\tfree(name2);\n-\tfree(orig.ptr);\n-\tfree(src1.ptr);\n-\tfree(src2.ptr);\n-\treturn merge_status;\n-}\n-\n-static int find_first_merges(struct repository *repo,\n-\t\t\t     struct object_array *result, const char *path,\n-\t\t\t     struct commit *a, struct commit *b)\n-{\n-\tint i, j;\n-\tstruct object_array merges = OBJECT_ARRAY_INIT;\n-\tstruct commit *commit;\n-\tint contains_another;\n-\n-\tchar merged_revision[GIT_MAX_HEXSZ + 2];\n-\tconst char *rev_args[] = { \"rev-list\", \"--merges\", \"--ancestry-path\",\n-\t\t\t\t   \"--all\", merged_revision, NULL };\n-\tstruct rev_info revs;\n-\tstruct setup_revision_opt rev_opts;\n-\n-\tmemset(result, 0, sizeof(struct object_array));\n-\tmemset(&rev_opts, 0, sizeof(rev_opts));\n-\n-\t/* get all revisions that merge commit a */\n-\txsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n-\t\t  oid_to_hex(&a->object.oid));\n-\trepo_init_revisions(repo, &revs, NULL);\n-\t/* FIXME: can't handle linked worktrees in submodules yet */\n-\trevs.single_worktree = path != NULL;\n-\tsetup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);\n-\n-\t/* save all revisions from the above list that contain b */\n-\tif (prepare_revision_walk(&revs))\n-\t\tdie(\"revision walk setup failed\");\n-\twhile ((commit = get_revision(&revs)) != NULL) {\n-\t\tstruct object *o = &(commit->object);\n-\t\tint ret = repo_in_merge_bases(repo, b, commit);\n-\t\tif (ret < 0) {\n-\t\t\tobject_array_clear(&merges);\n-\t\t\trelease_revisions(&revs);\n-\t\t\treturn ret;\n-\t\t}\n-\t\tif (ret)\n-\t\t\tadd_object_array(o, NULL, &merges);\n-\t}\n-\treset_revision_walk();\n-\n-\t/* Now we've got all merges that contain a and b. Prune all\n-\t * merges that contain another found merge and save them in\n-\t * result.\n-\t */\n-\tfor (i = 0; i < merges.nr; i++) {\n-\t\tstruct commit *m1 = (struct commit *) merges.objects[i].item;\n-\n-\t\tcontains_another = 0;\n-\t\tfor (j = 0; j < merges.nr; j++) {\n-\t\t\tstruct commit *m2 = (struct commit *) merges.objects[j].item;\n-\t\t\tif (i != j) {\n-\t\t\t\tint ret = repo_in_merge_bases(repo, m2, m1);\n-\t\t\t\tif (ret < 0) {\n-\t\t\t\t\tobject_array_clear(&merges);\n-\t\t\t\t\trelease_revisions(&revs);\n-\t\t\t\t\treturn ret;\n-\t\t\t\t}\n-\t\t\t\tif (ret > 0) {\n-\t\t\t\t\tcontains_another = 1;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (!contains_another)\n-\t\t\tadd_object_array(merges.objects[i].item, NULL, result);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-\trelease_revisions(&revs);\n-\treturn result->nr;\n-}\n-\n-static void print_commit(struct repository *repo, struct commit *commit)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tstruct pretty_print_context ctx = {0};\n-\tctx.date_mode.type = DATE_NORMAL;\n-\t/* FIXME: Merge this with output_commit_title() */\n-\tassert(!merge_remote_util(commit));\n-\trepo_format_commit_message(repo, commit, \" %h: %m %s\", &sb, &ctx);\n-\tfprintf(stderr, \"%s\\n\", sb.buf);\n-\tstrbuf_release(&sb);\n-}\n-\n-static int is_valid(const struct diff_filespec *dfs)\n-{\n-\treturn dfs->mode != 0 && !is_null_oid(&dfs->oid);\n-}\n-\n-static int merge_submodule(struct merge_options *opt,\n-\t\t\t   struct object_id *result, const char *path,\n-\t\t\t   const struct object_id *base, const struct object_id *a,\n-\t\t\t   const struct object_id *b)\n-{\n-\tstruct repository subrepo;\n-\tint ret = 0, ret2;\n-\tstruct commit *commit_base, *commit_a, *commit_b;\n-\tint parent_count;\n-\tstruct object_array merges;\n-\n-\tint i;\n-\tint search = !opt->priv->call_depth;\n-\n-\t/* store a in result in case we fail */\n-\t/* FIXME: This is the WRONG resolution for the recursive case when\n-\t * we need to be careful to avoid accidentally matching either side.\n-\t * Should probably use o instead there, much like we do for merging\n-\t * binaries.\n-\t */\n-\toidcpy(result, a);\n-\n-\t/* we can not handle deletion conflicts */\n-\tif (is_null_oid(base))\n-\t\treturn 0;\n-\tif (is_null_oid(a))\n-\t\treturn 0;\n-\tif (is_null_oid(b))\n-\t\treturn 0;\n-\n-\tif (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not checked out)\"), path);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!(commit_base = lookup_commit_reference(&subrepo, base)) ||\n-\t    !(commit_a = lookup_commit_reference(&subrepo, a)) ||\n-\t    !(commit_b = lookup_commit_reference(&subrepo, b))) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits not present)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* check whether both changes are forward */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2 > 0)\n-\t\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (!ret2) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits don't follow merge-base)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* Case #1: a is contained in b or vice versa */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, b);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_b);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\tret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, a);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_a);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/*\n-\t * Case #2: There are one or more merges that contain a and b in\n-\t * the submodule. If there is only one, then present it as a\n-\t * suggestion to the user, but leave it marked unmerged so the\n-\t * user needs to confirm the resolution.\n-\t */\n-\n-\t/* Skip the search if makes no sense to the calling context.  */\n-\tif (!search)\n-\t\tgoto cleanup;\n-\n-\t/* find commit which merges them */\n-\tparent_count = find_first_merges(&subrepo, &merges, path,\n-\t\t\t\t\t commit_a, commit_b);\n-\tswitch (parent_count) {\n-\tcase -1:\n-\t\toutput(opt, 1,_(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tbreak;\n-\tcase 0:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (merge following commits not found)\"), path);\n-\t\tbreak;\n-\n-\tcase 1:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not fast-forward)\"), path);\n-\t\toutput(opt, 2, _(\"Found a possible merge resolution for the submodule:\\n\"));\n-\t\tprint_commit(&subrepo, (struct commit *) merges.objects[0].item);\n-\t\toutput(opt, 2, _(\n-\t\t       \"If this is correct simply add it to the index \"\n-\t\t       \"for example\\n\"\n-\t\t       \"by using:\\n\\n\"\n-\t\t       \"  git update-index --cacheinfo 160000 %s \\\"%s\\\"\\n\\n\"\n-\t\t       \"which will accept this suggestion.\\n\"),\n-\t\t       oid_to_hex(&merges.objects[0].item->oid), path);\n-\t\tbreak;\n-\n-\tdefault:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (multiple merges found)\"), path);\n-\t\tfor (i = 0; i < merges.nr; i++)\n-\t\t\tprint_commit(&subrepo, (struct commit *) merges.objects[i].item);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-cleanup:\n-\trepo_clear(&subrepo);\n-\treturn ret;\n-}\n-\n-static int merge_mode_and_contents(struct merge_options *opt,\n-\t\t\t\t   const struct diff_filespec *o,\n-\t\t\t\t   const struct diff_filespec *a,\n-\t\t\t\t   const struct diff_filespec *b,\n-\t\t\t\t   const char *filename,\n-\t\t\t\t   const char *branch1,\n-\t\t\t\t   const char *branch2,\n-\t\t\t\t   const int extra_marker_size,\n-\t\t\t\t   struct merge_file_info *result)\n-{\n-\tif (opt->branch1 != branch1) {\n-\t\t/*\n-\t\t * It's weird getting a reverse merge with HEAD on the bottom\n-\t\t * side of the conflict markers and the other branch on the\n-\t\t * top.  Fix that.\n-\t\t */\n-\t\treturn merge_mode_and_contents(opt, o, b, a,\n-\t\t\t\t\t       filename,\n-\t\t\t\t\t       branch2, branch1,\n-\t\t\t\t\t       extra_marker_size, result);\n-\t}\n-\n-\tresult->merge = 0;\n-\tresult->clean = 1;\n-\n-\tif ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {\n-\t\tresult->clean = 0;\n-\t\t/*\n-\t\t * FIXME: This is a bad resolution for recursive case; for\n-\t\t * the recursive case we want something that is unlikely to\n-\t\t * accidentally match either side.  Also, while it makes\n-\t\t * sense to prefer regular files over symlinks, it doesn't\n-\t\t * make sense to prefer regular files over submodules.\n-\t\t */\n-\t\tif (S_ISREG(a->mode)) {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t} else {\n-\t\t\tresult->blob.mode = b->mode;\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t}\n-\t} else {\n-\t\tif (!oideq(&a->oid, &o->oid) && !oideq(&b->oid, &o->oid))\n-\t\t\tresult->merge = 1;\n-\n-\t\t/*\n-\t\t * Merge modes\n-\t\t */\n-\t\tif (a->mode == b->mode || a->mode == o->mode)\n-\t\t\tresult->blob.mode = b->mode;\n-\t\telse {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\tif (b->mode != o->mode) {\n-\t\t\t\tresult->clean = 0;\n-\t\t\t\tresult->merge = 1;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\telse if (oideq(&b->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\telse if (S_ISREG(a->mode)) {\n-\t\t\tmmbuffer_t result_buf;\n-\t\t\tint ret = 0, merge_status;\n-\n-\t\t\tmerge_status = merge_3way(opt, &result_buf, o, a, b,\n-\t\t\t\t\t\t  branch1, branch2,\n-\t\t\t\t\t\t  extra_marker_size);\n-\n-\t\t\tif ((merge_status < 0) || !result_buf.ptr)\n-\t\t\t\tret = err(opt, _(\"failed to execute internal merge\"));\n-\n-\t\t\tif (!ret &&\n-\t\t\t    write_object_file(result_buf.ptr, result_buf.size,\n-\t\t\t\t\t      OBJ_BLOB, &result->blob.oid))\n-\t\t\t\tret = err(opt, _(\"unable to add %s to database\"),\n-\t\t\t\t\t  a->path);\n-\n-\t\t\tfree(result_buf.ptr);\n-\t\t\tif (ret)\n-\t\t\t\treturn ret;\n-\t\t\t/* FIXME: bug, what if modes didn't match? */\n-\t\t\tresult->clean = (merge_status == 0);\n-\t\t} else if (S_ISGITLINK(a->mode)) {\n-\t\t\tint clean = merge_submodule(opt, &result->blob.oid,\n-\t\t\t\t\t\t    o->path,\n-\t\t\t\t\t\t    &o->oid,\n-\t\t\t\t\t\t    &a->oid,\n-\t\t\t\t\t\t    &b->oid);\n-\t\t\tif (clean < 0)\n-\t\t\t\treturn -1;\n-\t\t\tresult->clean = clean;\n-\t\t} else if (S_ISLNK(a->mode)) {\n-\t\t\tswitch (opt->recursive_variant) {\n-\t\t\tcase MERGE_VARIANT_NORMAL:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tif (!oideq(&a->oid, &b->oid))\n-\t\t\t\t\tresult->clean = 0;\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_OURS:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t} else\n-\t\t\tBUG(\"unsupported object type in the tree\");\n-\t}\n-\n-\tif (result->merge)\n-\t\toutput(opt, 2, _(\"Auto-merging %s\"), filename);\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_via_dir(struct merge_options *opt,\n-\t\t\t\t struct rename_conflict_info *ci)\n-{\n-\t/*\n-\t * Handle file adds that need to be renamed due to directory rename\n-\t * detection.  This differs from handle_rename_normal, because\n-\t * there is no content merge to do; just move the file into the\n-\t * desired final location.\n-\t */\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tchar *file_path = dest->path;\n-\tint mark_conflicted = (opt->detect_directory_renames ==\n-\t\t\t       MERGE_DIRECTORY_RENAMES_CONFLICT);\n-\tassert(ren->dir_rename_original_dest);\n-\n-\tif (!opt->priv->call_depth && would_lose_untracked(opt, dest->path)) {\n-\t\tmark_conflicted = 1;\n-\t\tfile_path = unique_path(opt, dest->path, ren->branch);\n-\t\toutput(opt, 1, _(\"Error: Refusing to lose untracked file at %s; \"\n-\t\t\t\t \"writing to %s instead.\"),\n-\t\t       dest->path, file_path);\n-\t}\n-\n-\tif (mark_conflicted) {\n-\t\t/*\n-\t\t * Write the file in worktree at file_path.  In the index,\n-\t\t * only record the file at dest->path in the appropriate\n-\t\t * higher stage.\n-\t\t */\n-\t\tif (update_file(opt, 0, dest, file_path))\n-\t\t\treturn -1;\n-\t\tif (file_path != dest->path)\n-\t\t\tfree(file_path);\n-\t\tif (update_stages(opt, dest->path, NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? NULL : dest))\n-\t\t\treturn -1;\n-\t\treturn 0; /* not clean, but conflicted */\n-\t} else {\n-\t\t/* Update dest->path both in index and in worktree */\n-\t\tif (update_file(opt, 1, dest, dest->path))\n-\t\t\treturn -1;\n-\t\treturn 1; /* clean */\n-\t}\n-}\n-\n-static int handle_change_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path, const char *old_path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *changed,\n-\t\t\t\tconst char *change_branch,\n-\t\t\t\tconst char *delete_branch,\n-\t\t\t\tconst char *change, const char *change_past)\n-{\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = path;\n-\tint ret = 0;\n-\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0) ||\n-\t    (!opt->priv->call_depth && would_lose_untracked(opt, path))) {\n-\t\tupdate_path = alt_path = unique_path(opt, path, change_branch);\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t/*\n-\t\t * We cannot arbitrarily accept either a_sha or b_sha as\n-\t\t * correct; since there is no true \"middle point\" between\n-\t\t * them, simply reuse the base version for virtual merge base.\n-\t\t */\n-\t\tret = remove_file_from_index(opt->repo->index, path);\n-\t\tif (!ret)\n-\t\t\tret = update_file(opt, 0, o, update_path);\n-\t} else {\n-\t\t/*\n-\t\t * Despite the four nearly duplicate messages and argument\n-\t\t * lists below and the ugliness of the nested if-statements,\n-\t\t * having complete messages makes the job easier for\n-\t\t * translators.\n-\t\t *\n-\t\t * The slight variance among the cases is due to the fact\n-\t\t * that:\n-\t\t *   1) directory/file conflicts (in effect if\n-\t\t *      !alt_path) could cause us to need to write the\n-\t\t *      file to a different path.\n-\t\t *   2) renames (in effect if !old_path) could mean that\n-\t\t *      there are two names for the path that the user\n-\t\t *      may know the file by.\n-\t\t */\n-\t\tif (!alt_path) {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t}\n-\t\t}\n-\t\t/*\n-\t\t * No need to call update_file() on path when change_branch ==\n-\t\t * opt->branch1 && !alt_path, since that would needlessly touch\n-\t\t * path.  We could call update_file_flags() with update_cache=0\n-\t\t * and update_wd=0, but that's a no-op.\n-\t\t */\n-\t\tif (change_branch != opt->branch1 || alt_path)\n-\t\t\tret = update_file(opt, 0, changed, update_path);\n-\t}\n-\tfree(alt_path);\n-\n-\treturn ret;\n-}\n-\n-static int handle_rename_delete(struct merge_options *opt,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *orig = ren->pair->one;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tconst char *rename_branch = ren->branch;\n-\tconst char *delete_branch = (opt->branch1 == ren->branch ?\n-\t\t\t\t     opt->branch2 : opt->branch1);\n-\n-\tif (handle_change_delete(opt,\n-\t\t\t\t opt->priv->call_depth ? orig->path : dest->path,\n-\t\t\t\t opt->priv->call_depth ? NULL : orig->path,\n-\t\t\t\t orig, dest,\n-\t\t\t\t rename_branch, delete_branch,\n-\t\t\t\t _(\"rename\"), _(\"renamed\")))\n-\t\treturn -1;\n-\n-\tif (opt->priv->call_depth)\n-\t\treturn remove_file_from_index(opt->repo->index, dest->path);\n-\telse\n-\t\treturn update_stages(opt, dest->path, NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? NULL : dest);\n-}\n-\n-static int handle_file_collision(struct merge_options *opt,\n-\t\t\t\t const char *collide_path,\n-\t\t\t\t const char *prev_path1,\n-\t\t\t\t const char *prev_path2,\n-\t\t\t\t const char *branch1, const char *branch2,\n-\t\t\t\t struct diff_filespec *a,\n-\t\t\t\t struct diff_filespec *b)\n-{\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec null;\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = collide_path;\n-\n-\t/*\n-\t * It's easiest to get the correct things into stage 2 and 3, and\n-\t * to make sure that the content merge puts HEAD before the other\n-\t * branch if we just ensure that branch1 == opt->branch1.  So, simply\n-\t * flip arguments around if we don't have that.\n-\t */\n-\tif (branch1 != opt->branch1) {\n-\t\treturn handle_file_collision(opt, collide_path,\n-\t\t\t\t\t     prev_path2, prev_path1,\n-\t\t\t\t\t     branch2, branch1,\n-\t\t\t\t\t     b, a);\n-\t}\n-\n-\t/* Remove rename sources if rename/add or rename/rename(2to1) */\n-\tif (prev_path1)\n-\t\tremove_file(opt, 1, prev_path1,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path1));\n-\tif (prev_path2)\n-\t\tremove_file(opt, 1, prev_path2,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path2));\n-\n-\t/*\n-\t * Remove the collision path, if it wouldn't cause dirty contents\n-\t * or an untracked file to get lost.  We'll either overwrite with\n-\t * merged contents, or just write out to differently named files.\n-\t */\n-\tif (was_dirty(opt, collide_path)) {\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else if (would_lose_untracked(opt, collide_path)) {\n-\t\t/*\n-\t\t * Only way we get here is if both renames were from\n-\t\t * a directory rename AND user had an untracked file\n-\t\t * at the location where both files end up after the\n-\t\t * two directory renames.  See testcase 10d of t6043.\n-\t\t */\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file at \"\n-\t\t\t       \"%s, even though it's in the way.\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else {\n-\t\t/*\n-\t\t * FIXME: It's possible that the two files are identical\n-\t\t * and that the current working copy happens to match, in\n-\t\t * which case we are unnecessarily touching the working\n-\t\t * tree file.  It's not a likely enough scenario that I\n-\t\t * want to code up the checks for it and a better fix is\n-\t\t * available if we restructure how unpack_trees() and\n-\t\t * merge-recursive interoperate anyway, so punting for\n-\t\t * now...\n-\t\t */\n-\t\tremove_file(opt, 0, collide_path, 0);\n-\t}\n-\n-\t/* Store things in diff_filespecs for functions that need it */\n-\tnull.path = (char *)collide_path;\n-\toidcpy(&null.oid, null_oid());\n-\tnull.mode = 0;\n-\n-\tif (merge_mode_and_contents(opt, &null, a, b, collide_path,\n-\t\t\t\t    branch1, branch2, opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tmfi.clean &= !alt_path;\n-\tif (update_file(opt, mfi.clean, &mfi.blob, update_path))\n-\t\treturn -1;\n-\tif (!mfi.clean && !opt->priv->call_depth &&\n-\t    update_stages(opt, collide_path, NULL, a, b))\n-\t\treturn -1;\n-\tfree(alt_path);\n-\t/*\n-\t * FIXME: If both a & b both started with conflicts (only possible\n-\t * if they came from a rename/rename(2to1)), but had IDENTICAL\n-\t * contents including those conflicts, then in the next line we claim\n-\t * it was clean.  If someone cares about this case, we should have the\n-\t * caller notify us if we started with conflicts.\n-\t */\n-\treturn mfi.clean;\n-}\n-\n-static int handle_rename_add(struct merge_options *opt,\n-\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* a was renamed to c, and a separate c was added. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *c = ci->ren1->pair->two;\n-\tchar *path = c->path;\n-\tchar *prev_path_desc;\n-\tstruct merge_file_info mfi;\n-\n-\tconst char *rename_branch = ci->ren1->branch;\n-\tconst char *add_branch = (opt->branch1 == rename_branch ?\n-\t\t\t\t  opt->branch2 : opt->branch1);\n-\tint other_stage = (ci->ren1->branch == opt->branch1 ? 3 : 2);\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/add): \"\n-\t       \"Rename %s->%s in %s.  Added %s in %s\"),\n-\t       a->path, c->path, rename_branch,\n-\t       c->path, add_branch);\n-\n-\tprev_path_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tci->ren1->src_entry->stages[other_stage].path = a->path;\n-\tif (merge_mode_and_contents(opt, a, c,\n-\t\t\t\t    &ci->ren1->src_entry->stages[other_stage],\n-\t\t\t\t    prev_path_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(prev_path_desc);\n-\n-\tci->ren1->dst_entry->stages[other_stage].path = mfi.blob.path = c->path;\n-\treturn handle_file_collision(opt,\n-\t\t\t\t     c->path, a->path, NULL,\n-\t\t\t\t     rename_branch, add_branch,\n-\t\t\t\t     &mfi.blob,\n-\t\t\t\t     &ci->ren1->dst_entry->stages[other_stage]);\n-}\n-\n-static char *find_path_for_conflict(struct merge_options *opt,\n-\t\t\t\t    const char *path,\n-\t\t\t\t    const char *branch1,\n-\t\t\t\t    const char *branch2)\n-{\n-\tchar *new_path = NULL;\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"%s is a directory in %s adding \"\n-\t\t\t       \"as %s instead\"),\n-\t\t       path, branch2, new_path);\n-\t} else if (would_lose_untracked(opt, path)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file\"\n-\t\t\t       \" at %s; adding as %s instead\"),\n-\t\t       path, new_path);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * Toggle the stage number between \"ours\" and \"theirs\" (2 and 3).\n- */\n-static inline int flip_stage(int stage)\n-{\n-\treturn (2 + 3) - stage;\n-}\n-\n-static int handle_rename_rename_1to2(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* One file was renamed in both branches, but to different names. */\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec *add;\n-\tstruct diff_filespec *o = ci->ren1->pair->one;\n-\tstruct diff_filespec *a = ci->ren1->pair->two;\n-\tstruct diff_filespec *b = ci->ren2->pair->two;\n-\tchar *path_desc;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename \\\"%s\\\"->\\\"%s\\\" in branch \\\"%s\\\" \"\n-\t       \"rename \\\"%s\\\"->\\\"%s\\\" in \\\"%s\\\"%s\"),\n-\t       o->path, a->path, ci->ren1->branch,\n-\t       o->path, b->path, ci->ren2->branch,\n-\t       opt->priv->call_depth ? _(\" (left unresolved)\") : \"\");\n-\n-\tpath_desc = xstrfmt(\"%s and %s, both renamed from %s\",\n-\t\t\t    a->path, b->path, o->path);\n-\tif (merge_mode_and_contents(opt, o, a, b, path_desc,\n-\t\t\t\t    ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t    opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(path_desc);\n-\n-\tif (opt->priv->call_depth)\n-\t\tremove_file_from_index(opt->repo->index, o->path);\n-\n-\t/*\n-\t * For each destination path, we need to see if there is a\n-\t * rename/add collision.  If not, we can write the file out\n-\t * to the specified location.\n-\t */\n-\tadd = &ci->ren1->dst_entry->stages[flip_stage(2)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = a->path;\n-\t\tif (handle_file_collision(opt, a->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  &mfi.blob, add) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, a->path,\n-\t\t\t\t\t\t\tci->ren1->branch,\n-\t\t\t\t\t\t\tci->ren2->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : a->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, a->path, NULL, a, NULL))\n-\t\t\treturn -1;\n-\t}\n-\n-\tif (!mfi.clean && mfi.blob.mode == a->mode &&\n-\t    oideq(&mfi.blob.oid, &a->oid)) {\n-\t\t/*\n-\t\t * Getting here means we were attempting to merge a binary\n-\t\t * blob.  Since we can't merge binaries, the merge algorithm\n-\t\t * just takes one side.  But we don't want to copy the\n-\t\t * contents of one side to both paths; we'd rather use the\n-\t\t * original content at the given path for each path.\n-\t\t */\n-\t\toidcpy(&mfi.blob.oid, &b->oid);\n-\t\tmfi.blob.mode = b->mode;\n-\t}\n-\tadd = &ci->ren2->dst_entry->stages[flip_stage(3)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = b->path;\n-\t\tif (handle_file_collision(opt, b->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  add, &mfi.blob) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, b->path,\n-\t\t\t\t\t\t\tci->ren2->branch,\n-\t\t\t\t\t\t\tci->ren1->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : b->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, b->path, NULL, NULL, b))\n-\t\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_rename_2to1(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* Two files, a & b, were renamed to the same thing, c. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *b = ci->ren2->pair->one;\n-\tstruct diff_filespec *c1 = ci->ren1->pair->two;\n-\tstruct diff_filespec *c2 = ci->ren2->pair->two;\n-\tchar *path = c1->path; /* == c2->path */\n-\tchar *path_side_1_desc;\n-\tchar *path_side_2_desc;\n-\tstruct merge_file_info mfi_c1;\n-\tstruct merge_file_info mfi_c2;\n-\tint ostage1, ostage2;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename %s->%s in %s. \"\n-\t       \"Rename %s->%s in %s\"),\n-\t       a->path, c1->path, ci->ren1->branch,\n-\t       b->path, c2->path, ci->ren2->branch);\n-\n-\tpath_side_1_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tpath_side_2_desc = xstrfmt(\"version of %s from %s\", path, b->path);\n-\tostage1 = ci->ren1->branch == opt->branch1 ? 3 : 2;\n-\tostage2 = flip_stage(ostage1);\n-\tci->ren1->src_entry->stages[ostage1].path = a->path;\n-\tci->ren2->src_entry->stages[ostage2].path = b->path;\n-\tif (merge_mode_and_contents(opt, a, c1,\n-\t\t\t\t    &ci->ren1->src_entry->stages[ostage1],\n-\t\t\t\t    path_side_1_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c1) ||\n-\t    merge_mode_and_contents(opt, b,\n-\t\t\t\t    &ci->ren2->src_entry->stages[ostage2],\n-\t\t\t\t    c2, path_side_2_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c2))\n-\t\treturn -1;\n-\tfree(path_side_1_desc);\n-\tfree(path_side_2_desc);\n-\tmfi_c1.blob.path = path;\n-\tmfi_c2.blob.path = path;\n-\n-\treturn handle_file_collision(opt, path, a->path, b->path,\n-\t\t\t\t     ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t     &mfi_c1.blob, &mfi_c2.blob);\n-}\n-\n-/*\n- * Get the diff_filepairs changed between o_tree and tree.\n- */\n-static struct diff_queue_struct *get_diffpairs(struct merge_options *opt,\n-\t\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t\t       struct tree *tree)\n-{\n-\tstruct diff_queue_struct *ret;\n-\tstruct diff_options opts;\n-\n-\trepo_diff_setup(opt->repo, &opts);\n-\topts.flags.recursive = 1;\n-\topts.flags.rename_empty = 0;\n-\topts.detect_rename = merge_detect_rename(opt);\n-\t/*\n-\t * We do not have logic to handle the detection of copies.  In\n-\t * fact, it may not even make sense to add such logic: would we\n-\t * really want a change to a base file to be propagated through\n-\t * multiple other files by a merge?\n-\t */\n-\tif (opts.detect_rename > DIFF_DETECT_RENAME)\n-\t\topts.detect_rename = DIFF_DETECT_RENAME;\n-\topts.rename_limit = (opt->rename_limit >= 0) ? opt->rename_limit : 7000;\n-\topts.rename_score = opt->rename_score;\n-\topts.show_rename_progress = opt->show_rename_progress;\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_setup_done(&opts);\n-\tdiff_tree_oid(&o_tree->object.oid, &tree->object.oid, \"\", &opts);\n-\tdiffcore_std(&opts);\n-\tif (opts.needed_rename_limit > opt->priv->needed_rename_limit)\n-\t\topt->priv->needed_rename_limit = opts.needed_rename_limit;\n-\n-\tret = xmalloc(sizeof(*ret));\n-\t*ret = diff_queued_diff;\n-\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_queued_diff.nr = 0;\n-\tdiff_queued_diff.queue = NULL;\n-\tdiff_flush(&opts);\n-\treturn ret;\n-}\n-\n-static int tree_has_path(struct repository *r, struct tree *tree,\n-\t\t\t const char *path)\n-{\n-\tstruct object_id hashy;\n-\tunsigned short mode_o;\n-\n-\treturn !get_tree_entry(r,\n-\t\t\t       &tree->object.oid, path,\n-\t\t\t       &hashy, &mode_o);\n-}\n-\n-/*\n- * Return a new string that replaces the beginning portion (which matches\n- * entry->dir), with entry->new_dir.  In perl-speak:\n- *   new_path_name = (old_path =~ s/entry->dir/entry->new_dir/);\n- * NOTE:\n- *   Caller must ensure that old_path starts with entry->dir + '/'.\n- */\n-static char *apply_dir_rename(struct dir_rename_entry *entry,\n-\t\t\t      const char *old_path)\n-{\n-\tstruct strbuf new_path = STRBUF_INIT;\n-\tint oldlen, newlen;\n-\n-\tif (entry->non_unique_new_dir)\n-\t\treturn NULL;\n-\n-\toldlen = strlen(entry->dir);\n-\tif (entry->new_dir.len == 0)\n-\t\t/*\n-\t\t * If someone renamed/merged a subdirectory into the root\n-\t\t * directory (e.g. 'some/subdir' -> ''), then we want to\n-\t\t * avoid returning\n-\t\t *     '' + '/filename'\n-\t\t * as the rename; we need to make old_path + oldlen advance\n-\t\t * past the '/' character.\n-\t\t */\n-\t\toldlen++;\n-\tnewlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;\n-\tstrbuf_grow(&new_path, newlen);\n-\tstrbuf_addbuf(&new_path, &entry->new_dir);\n-\tstrbuf_addstr(&new_path, &old_path[oldlen]);\n-\n-\treturn strbuf_detach(&new_path, NULL);\n-}\n-\n-static void get_renamed_dir_portion(const char *old_path, const char *new_path,\n-\t\t\t\t    char **old_dir, char **new_dir)\n-{\n-\tchar *end_of_old, *end_of_new;\n-\n-\t/* Default return values: NULL, meaning no rename */\n-\t*old_dir = NULL;\n-\t*new_dir = NULL;\n-\n-\t/*\n-\t * For\n-\t *    \"a/b/c/d/e/foo.c\" -> \"a/b/some/thing/else/e/foo.c\"\n-\t * the \"e/foo.c\" part is the same, we just want to know that\n-\t *    \"a/b/c/d\" was renamed to \"a/b/some/thing/else\"\n-\t * so, for this example, this function returns \"a/b/c/d\" in\n-\t * *old_dir and \"a/b/some/thing/else\" in *new_dir.\n-\t */\n-\n-\t/*\n-\t * If the basename of the file changed, we don't care.  We want\n-\t * to know which portion of the directory, if any, changed.\n-\t */\n-\tend_of_old = strrchr(old_path, '/');\n-\tend_of_new = strrchr(new_path, '/');\n-\n-\t/*\n-\t * If end_of_old is NULL, old_path wasn't in a directory, so there\n-\t * could not be a directory rename (our rule elsewhere that a\n-\t * directory which still exists is not considered to have been\n-\t * renamed means the root directory can never be renamed -- because\n-\t * the root directory always exists).\n-\t */\n-\tif (!end_of_old)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If new_path contains no directory (end_of_new is NULL), then we\n-\t * have a rename of old_path's directory to the root directory.\n-\t */\n-\tif (!end_of_new) {\n-\t\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/* Find the first non-matching character traversing backwards */\n-\twhile (*--end_of_new == *--end_of_old &&\n-\t       end_of_old != old_path &&\n-\t       end_of_new != new_path)\n-\t\t; /* Do nothing; all in the while loop */\n-\n-\t/*\n-\t * If both got back to the beginning of their strings, then the\n-\t * directory didn't change at all, only the basename did.\n-\t */\n-\tif (end_of_old == old_path && end_of_new == new_path &&\n-\t    *end_of_old == *end_of_new)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If end_of_new got back to the beginning of its string, and\n-\t * end_of_old got back to the beginning of some subdirectory, then\n-\t * we have a rename/merge of a subdirectory into the root, which\n-\t * needs slightly special handling.\n-\t *\n-\t * Note: There is no need to consider the opposite case, with a\n-\t * rename/merge of the root directory into some subdirectory\n-\t * because as noted above the root directory always exists so it\n-\t * cannot be considered to be renamed.\n-\t */\n-\tif (end_of_new == new_path &&\n-\t    end_of_old != old_path && end_of_old[-1] == '/') {\n-\t\t*old_dir = xstrndup(old_path, --end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * We've found the first non-matching character in the directory\n-\t * paths.  That means the current characters we were looking at\n-\t * were part of the first non-matching subdir name going back from\n-\t * the end of the strings.  Get the whole name by advancing both\n-\t * end_of_old and end_of_new to the NEXT '/' character.  That will\n-\t * represent the entire directory rename.\n-\t *\n-\t * The reason for the increment is cases like\n-\t *    a/b/star/foo/whatever.c -> a/b/tar/foo/random.c\n-\t * After dropping the basename and going back to the first\n-\t * non-matching character, we're now comparing:\n-\t *    a/b/s          and         a/b/\n-\t * and we want to be comparing:\n-\t *    a/b/star/      and         a/b/tar/\n-\t * but without the pre-increment, the one on the right would stay\n-\t * a/b/.\n-\t */\n-\tend_of_old = strchr(++end_of_old, '/');\n-\tend_of_new = strchr(++end_of_new, '/');\n-\n-\t/* Copy the old and new directories into *old_dir and *new_dir. */\n-\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t*new_dir = xstrndup(new_path, end_of_new - new_path);\n-}\n-\n-static void remove_hashmap_entries(struct hashmap *dir_renames,\n-\t\t\t\t   struct string_list *items_to_remove)\n-{\n-\tint i;\n-\tstruct dir_rename_entry *entry;\n-\n-\tfor (i = 0; i < items_to_remove->nr; i++) {\n-\t\tentry = items_to_remove->items[i].util;\n-\t\thashmap_remove(dir_renames, &entry->ent, NULL);\n-\t}\n-\tstring_list_clear(items_to_remove, 0);\n-}\n-\n-/*\n- * See if there is a directory rename for path, and if there are any file\n- * level conflicts for the renamed location.  If there is a rename and\n- * there are no conflicts, return the new name.  Otherwise, return NULL.\n- */\n-static char *handle_path_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t const char *path,\n-\t\t\t\t\t struct dir_rename_entry *entry,\n-\t\t\t\t\t struct hashmap *collisions,\n-\t\t\t\t\t struct tree *tree)\n-{\n-\tchar *new_path = NULL;\n-\tstruct collision_entry *collision_ent;\n-\tint clean = 1;\n-\tstruct strbuf collision_paths = STRBUF_INIT;\n-\n-\t/*\n-\t * entry has the mapping of old directory name to new directory name\n-\t * that we want to apply to path.\n-\t */\n-\tnew_path = apply_dir_rename(entry, path);\n-\n-\tif (!new_path) {\n-\t\t/* This should only happen when entry->non_unique_new_dir set */\n-\t\tif (!entry->non_unique_new_dir)\n-\t\t\tBUG(\"entry->non_unique_new_dir not set and !new_path\");\n-\t\toutput(opt, 1, _(\"CONFLICT (directory rename split): \"\n-\t\t\t       \"Unclear where to place %s because directory \"\n-\t\t\t       \"%s was renamed to multiple other directories, \"\n-\t\t\t       \"with no destination getting a majority of the \"\n-\t\t\t       \"files.\"),\n-\t\t       path, entry->dir);\n-\t\tclean = 0;\n-\t\treturn NULL;\n-\t}\n-\n-\t/*\n-\t * The caller needs to have ensured that it has pre-populated\n-\t * collisions with all paths that map to new_path.  Do a quick check\n-\t * to ensure that's the case.\n-\t */\n-\tcollision_ent = collision_find_entry(collisions, new_path);\n-\tif (!collision_ent)\n-\t\tBUG(\"collision_ent is NULL\");\n-\n-\t/*\n-\t * Check for one-sided add/add/.../add conflicts, i.e.\n-\t * where implicit renames from the other side doing\n-\t * directory rename(s) can affect this side of history\n-\t * to put multiple paths into the same location.  Warn\n-\t * and bail on directory renames for such paths.\n-\t */\n-\tif (collision_ent->reported_already) {\n-\t\tclean = 0;\n-\t} else if (tree_has_path(opt->repo, tree, new_path)) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Existing \"\n-\t\t\t       \"file/dir at %s in the way of implicit \"\n-\t\t\t       \"directory rename(s) putting the following \"\n-\t\t\t       \"path(s) there: %s.\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t} else if (collision_ent->source_files.nr > 1) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Cannot map \"\n-\t\t\t       \"more than one path to %s; implicit directory \"\n-\t\t\t       \"renames tried to put these paths there: %s\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t}\n-\n-\t/* Free memory we no longer need */\n-\tstrbuf_release(&collision_paths);\n-\tif (!clean && new_path) {\n-\t\tfree(new_path);\n-\t\treturn NULL;\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * There are a couple things we want to do at the directory level:\n- *   1. Check for both sides renaming to the same thing, in order to avoid\n- *      implicit renaming of files that should be left in place.  (See\n- *      testcase 6b in t6043 for details.)\n- *   2. Prune directory renames if there are still files left in the\n- *      original directory.  These represent a partial directory rename,\n- *      i.e. a rename where only some of the files within the directory\n- *      were renamed elsewhere.  (Technically, this could be done earlier\n- *      in get_directory_renames(), except that would prevent us from\n- *      doing the previous check and thus failing testcase 6b.)\n- *   3. Check for rename/rename(1to2) conflicts (at the directory level).\n- *      In the future, we could potentially record this info as well and\n- *      omit reporting rename/rename(1to2) conflicts for each path within\n- *      the affected directories, thus cleaning up the merge output.\n- *   NOTE: We do NOT check for rename/rename(2to1) conflicts at the\n- *         directory level, because merging directories is fine.  If it\n- *         causes conflicts for files within those merged directories, then\n- *         that should be detected at the individual path level.\n- */\n-static void handle_directory_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t     struct hashmap *dir_re_head,\n-\t\t\t\t\t     struct tree *head,\n-\t\t\t\t\t     struct hashmap *dir_re_merge,\n-\t\t\t\t\t     struct tree *merge)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *head_ent;\n-\tstruct dir_rename_entry *merge_ent;\n-\n-\tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n-\tstruct string_list remove_from_merge = STRING_LIST_INIT_NODUP;\n-\n-\thashmap_for_each_entry(dir_re_head, &iter, head_ent,\n-\t\t\t\tent /* member name */) {\n-\t\tmerge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);\n-\t\tif (merge_ent &&\n-\t\t    !head_ent->non_unique_new_dir &&\n-\t\t    !merge_ent->non_unique_new_dir &&\n-\t\t    !strbuf_cmp(&head_ent->new_dir, &merge_ent->new_dir)) {\n-\t\t\t/* 1. Renamed identically; remove it from both sides */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t} else if (tree_has_path(opt->repo, head, head_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-\n-\thashmap_for_each_entry(dir_re_merge, &iter, merge_ent,\n-\t\t\t\tent /* member name */) {\n-\t\thead_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);\n-\t\tif (tree_has_path(opt->repo, merge, merge_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t} else if (head_ent &&\n-\t\t\t   !head_ent->non_unique_new_dir &&\n-\t\t\t   !merge_ent->non_unique_new_dir) {\n-\t\t\t/* 3. rename/rename(1to2) */\n-\t\t\t/*\n-\t\t\t * We can assume it's not rename/rename(1to1) because\n-\t\t\t * that was case (1), already checked above.  So we\n-\t\t\t * know that head_ent->new_dir and merge_ent->new_dir\n-\t\t\t * are different strings.\n-\t\t\t */\n-\t\t\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t\t\t\t       \"Rename directory %s->%s in %s. \"\n-\t\t\t\t       \"Rename directory %s->%s in %s\"),\n-\t\t\t       head_ent->dir, head_ent->new_dir.buf, opt->branch1,\n-\t\t\t       head_ent->dir, merge_ent->new_dir.buf, opt->branch2);\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-}\n-\n-static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n-{\n-\tstruct hashmap *dir_renames;\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *entry;\n-\tint i;\n-\n-\t/*\n-\t * Typically, we think of a directory rename as all files from a\n-\t * certain directory being moved to a target directory.  However,\n-\t * what if someone first moved two files from the original\n-\t * directory in one commit, and then renamed the directory\n-\t * somewhere else in a later commit?  At merge time, we just know\n-\t * that files from the original directory went to two different\n-\t * places, and that the bulk of them ended up in the same place.\n-\t * We want each directory rename to represent where the bulk of the\n-\t * files from that directory end up; this function exists to find\n-\t * where the bulk of the files went.\n-\t *\n-\t * The first loop below simply iterates through the list of file\n-\t * renames, finding out how often each directory rename pair\n-\t * possibility occurs.\n-\t */\n-\tdir_renames = xmalloc(sizeof(*dir_renames));\n-\tdir_rename_init(dir_renames);\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tint *count;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *old_dir, *new_dir;\n-\n-\t\t/* File not part of directory rename if it wasn't renamed */\n-\t\tif (pair->status != 'R')\n-\t\t\tcontinue;\n-\n-\t\tget_renamed_dir_portion(pair->one->path, pair->two->path,\n-\t\t\t\t\t&old_dir,        &new_dir);\n-\t\tif (!old_dir)\n-\t\t\t/* Directory didn't change at all; ignore this one. */\n-\t\t\tcontinue;\n-\n-\t\tentry = dir_rename_find_entry(dir_renames, old_dir);\n-\t\tif (!entry) {\n-\t\t\tentry = xmalloc(sizeof(*entry));\n-\t\t\tdir_rename_entry_init(entry, old_dir);\n-\t\t\thashmap_put(dir_renames, &entry->ent);\n-\t\t} else {\n-\t\t\tfree(old_dir);\n-\t\t}\n-\t\titem = string_list_lookup(&entry->possible_new_dirs, new_dir);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(&entry->possible_new_dirs,\n-\t\t\t\t\t\t  new_dir);\n-\t\t\titem->util = xcalloc(1, sizeof(int));\n-\t\t} else {\n-\t\t\tfree(new_dir);\n-\t\t}\n-\t\tcount = item->util;\n-\t\t*count += 1;\n-\t}\n-\n-\t/*\n-\t * For each directory with files moved out of it, we find out which\n-\t * target directory received the most files so we can declare it to\n-\t * be the \"winning\" target location for the directory rename.  This\n-\t * winner gets recorded in new_dir.  If there is no winner\n-\t * (multiple target directories received the same number of files),\n-\t * we set non_unique_new_dir.  Once we've determined the winner (or\n-\t * that there is no winner), we no longer need possible_new_dirs.\n-\t */\n-\thashmap_for_each_entry(dir_renames, &iter, entry,\n-\t\t\t\tent /* member name */) {\n-\t\tint max = 0;\n-\t\tint bad_max = 0;\n-\t\tchar *best = NULL;\n-\n-\t\tfor (i = 0; i < entry->possible_new_dirs.nr; i++) {\n-\t\t\tint *count = entry->possible_new_dirs.items[i].util;\n-\n-\t\t\tif (*count == max)\n-\t\t\t\tbad_max = max;\n-\t\t\telse if (*count > max) {\n-\t\t\t\tmax = *count;\n-\t\t\t\tbest = entry->possible_new_dirs.items[i].string;\n-\t\t\t}\n-\t\t}\n-\t\tif (bad_max == max)\n-\t\t\tentry->non_unique_new_dir = 1;\n-\t\telse {\n-\t\t\tassert(entry->new_dir.len == 0);\n-\t\t\tstrbuf_addstr(&entry->new_dir, best);\n-\t\t}\n-\t\t/*\n-\t\t * The relevant directory sub-portion of the original full\n-\t\t * filepaths were xstrndup'ed before inserting into\n-\t\t * possible_new_dirs, and instead of manually iterating the\n-\t\t * list and free'ing each, just lie and tell\n-\t\t * possible_new_dirs that it did the strdup'ing so that it\n-\t\t * will free them for us.\n-\t\t */\n-\t\tentry->possible_new_dirs.strdup_strings = 1;\n-\t\tstring_list_clear(&entry->possible_new_dirs, 1);\n-\t}\n-\n-\treturn dir_renames;\n-}\n-\n-static struct dir_rename_entry *check_dir_renamed(const char *path,\n-\t\t\t\t\t\t  struct hashmap *dir_renames)\n-{\n-\tchar *temp = xstrdup(path);\n-\tchar *end;\n-\tstruct dir_rename_entry *entry = NULL;\n-\n-\twhile ((end = strrchr(temp, '/'))) {\n-\t\t*end = '\\0';\n-\t\tentry = dir_rename_find_entry(dir_renames, temp);\n-\t\tif (entry)\n-\t\t\tbreak;\n-\t}\n-\tfree(temp);\n-\treturn entry;\n-}\n-\n-static void compute_collisions(struct hashmap *collisions,\n-\t\t\t       struct hashmap *dir_renames,\n-\t\t\t       struct diff_queue_struct *pairs)\n-{\n-\tint i;\n-\n-\t/*\n-\t * Multiple files can be mapped to the same path due to directory\n-\t * renames done by the other side of history.  Since that other\n-\t * side of history could have merged multiple directories into one,\n-\t * if our side of history added the same file basename to each of\n-\t * those directories, then all N of them would get implicitly\n-\t * renamed by the directory rename detection into the same path,\n-\t * and we'd get an add/add/.../add conflict, and all those adds\n-\t * from *this* side of history.  This is not representable in the\n-\t * index, and users aren't going to easily be able to make sense of\n-\t * it.  So we need to provide a good warning about what's\n-\t * happening, and fall back to no-directory-rename detection\n-\t * behavior for those paths.\n-\t *\n-\t * See testcases 9e and all of section 5 from t6043 for examples.\n-\t */\n-\tcollision_init(collisions);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct dir_rename_entry *dir_rename_ent;\n-\t\tstruct collision_entry *collision_ent;\n-\t\tchar *new_path;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R')\n-\t\t\tcontinue;\n-\t\tdir_rename_ent = check_dir_renamed(pair->two->path,\n-\t\t\t\t\t\t   dir_renames);\n-\t\tif (!dir_rename_ent)\n-\t\t\tcontinue;\n-\n-\t\tnew_path = apply_dir_rename(dir_rename_ent, pair->two->path);\n-\t\tif (!new_path)\n-\t\t\t/*\n-\t\t\t * dir_rename_ent->non_unique_new_path is true, which\n-\t\t\t * means there is no directory rename for us to use,\n-\t\t\t * which means it won't cause us any additional\n-\t\t\t * collisions.\n-\t\t\t */\n-\t\t\tcontinue;\n-\t\tcollision_ent = collision_find_entry(collisions, new_path);\n-\t\tif (!collision_ent) {\n-\t\t\tCALLOC_ARRAY(collision_ent, 1);\n-\t\t\thashmap_entry_init(&collision_ent->ent,\n-\t\t\t\t\t\tstrhash(new_path));\n-\t\t\thashmap_put(collisions, &collision_ent->ent);\n-\t\t\tcollision_ent->target_file = new_path;\n-\t\t} else {\n-\t\t\tfree(new_path);\n-\t\t}\n-\t\tstring_list_insert(&collision_ent->source_files,\n-\t\t\t\t   pair->two->path);\n-\t}\n-}\n-\n-static char *check_for_directory_rename(struct merge_options *opt,\n-\t\t\t\t\tconst char *path,\n-\t\t\t\t\tstruct tree *tree,\n-\t\t\t\t\tstruct hashmap *dir_renames,\n-\t\t\t\t\tstruct hashmap *dir_rename_exclusions,\n-\t\t\t\t\tstruct hashmap *collisions,\n-\t\t\t\t\tint *clean_merge)\n-{\n-\tchar *new_path = NULL;\n-\tstruct dir_rename_entry *entry = check_dir_renamed(path, dir_renames);\n-\tstruct dir_rename_entry *oentry = NULL;\n-\n-\tif (!entry)\n-\t\treturn new_path;\n-\n-\t/*\n-\t * This next part is a little weird.  We do not want to do an\n-\t * implicit rename into a directory we renamed on our side, because\n-\t * that will result in a spurious rename/rename(1to2) conflict.  An\n-\t * example:\n-\t *   Base commit: dumbdir/afile, otherdir/bfile\n-\t *   Side 1:      smrtdir/afile, otherdir/bfile\n-\t *   Side 2:      dumbdir/afile, dumbdir/bfile\n-\t * Here, while working on Side 1, we could notice that otherdir was\n-\t * renamed/merged to dumbdir, and change the diff_filepair for\n-\t * otherdir/bfile into a rename into dumbdir/bfile.  However, Side\n-\t * 2 will notice the rename from dumbdir to smrtdir, and do the\n-\t * transitive rename to move it from dumbdir/bfile to\n-\t * smrtdir/bfile.  That gives us bfile in dumbdir vs being in\n-\t * smrtdir, a rename/rename(1to2) conflict.  We really just want\n-\t * the file to end up in smrtdir.  And the way to achieve that is\n-\t * to not let Side1 do the rename to dumbdir, since we know that is\n-\t * the source of one of our directory renames.\n-\t *\n-\t * That's why oentry and dir_rename_exclusions is here.\n-\t *\n-\t * As it turns out, this also prevents N-way transient rename\n-\t * confusion; See testcases 9c and 9d of t6043.\n-\t */\n-\toentry = dir_rename_find_entry(dir_rename_exclusions, entry->new_dir.buf);\n-\tif (oentry) {\n-\t\toutput(opt, 1, _(\"WARNING: Avoiding applying %s -> %s rename \"\n-\t\t\t       \"to %s, because %s itself was renamed.\"),\n-\t\t       entry->dir, entry->new_dir.buf, path, entry->new_dir.buf);\n-\t} else {\n-\t\tnew_path = handle_path_level_conflicts(opt, path, entry,\n-\t\t\t\t\t\t       collisions, tree);\n-\t\t*clean_merge &= (new_path != NULL);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-static void apply_directory_rename_modifications(struct merge_options *opt,\n-\t\t\t\t\t\t struct diff_filepair *pair,\n-\t\t\t\t\t\t char *new_path,\n-\t\t\t\t\t\t struct rename *re,\n-\t\t\t\t\t\t struct tree *tree,\n-\t\t\t\t\t\t struct tree *o_tree,\n-\t\t\t\t\t\t struct tree *a_tree,\n-\t\t\t\t\t\t struct tree *b_tree,\n-\t\t\t\t\t\t struct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tint stage = (tree == a_tree ? 2 : 3);\n-\tint update_wd;\n-\n-\t/*\n-\t * In all cases where we can do directory rename detection,\n-\t * unpack_trees() will have read pair->two->path into the\n-\t * index and the working copy.  We need to remove it so that\n-\t * we can instead place it at new_path.  It is guaranteed to\n-\t * not be untracked (unpack_trees() would have errored out\n-\t * saying the file would have been overwritten), but it might\n-\t * be dirty, though.\n-\t */\n-\tupdate_wd = !was_dirty(opt, pair->two->path);\n-\tif (!update_wd)\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       pair->two->path);\n-\tremove_file(opt, 1, pair->two->path, !update_wd);\n-\n-\t/* Find or create a new re->dst_entry */\n-\titem = string_list_lookup(entries, new_path);\n-\tif (item) {\n-\t\t/*\n-\t\t * Since we're renaming on this side of history, and it's\n-\t\t * due to a directory rename on the other side of history\n-\t\t * (which we only allow when the directory in question no\n-\t\t * longer exists on the other side of history), the\n-\t\t * original entry for re->dst_entry is no longer\n-\t\t * necessary...\n-\t\t */\n-\t\tre->dst_entry->processed = 1;\n-\n-\t\t/*\n-\t\t * ...because we'll be using this new one.\n-\t\t */\n-\t\tre->dst_entry = item->util;\n-\t} else {\n-\t\t/*\n-\t\t * re->dst_entry is for the before-dir-rename path, and we\n-\t\t * need it to hold information for the after-dir-rename\n-\t\t * path.  Before creating a new entry, we need to mark the\n-\t\t * old one as unnecessary (...unless it is shared by\n-\t\t * src_entry, i.e. this didn't use to be a rename, in which\n-\t\t * case we can just allow the normal processing to happen\n-\t\t * for it).\n-\t\t */\n-\t\tif (pair->status == 'R')\n-\t\t\tre->dst_entry->processed = 1;\n-\n-\t\tre->dst_entry = insert_stage_data(opt->repo, new_path,\n-\t\t\t\t\t\t  o_tree, a_tree, b_tree,\n-\t\t\t\t\t\t  entries);\n-\t\titem = string_list_insert(entries, new_path);\n-\t\titem->util = re->dst_entry;\n-\t}\n-\n-\t/*\n-\t * Update the stage_data with the information about the path we are\n-\t * moving into place.  That slot will be empty and available for us\n-\t * to write to because of the collision checks in\n-\t * handle_path_level_conflicts().  In other words,\n-\t * re->dst_entry->stages[stage].oid will be the null_oid, so it's\n-\t * open for us to write to.\n-\t *\n-\t * It may be tempting to actually update the index at this point as\n-\t * well, using update_stages_for_stage_data(), but as per the big\n-\t * \"NOTE\" in update_stages(), doing so will modify the current\n-\t * in-memory index which will break calls to would_lose_untracked()\n-\t * that we need to make.  Instead, we need to just make sure that\n-\t * the various handle_rename_*() functions update the index\n-\t * explicitly rather than relying on unpack_trees() to have done it.\n-\t */\n-\tget_tree_entry(opt->repo,\n-\t\t       &tree->object.oid,\n-\t\t       pair->two->path,\n-\t\t       &re->dst_entry->stages[stage].oid,\n-\t\t       &re->dst_entry->stages[stage].mode);\n-\n-\t/*\n-\t * Record the original change status (or 'type' of change).  If it\n-\t * was originally an add ('A'), this lets us differentiate later\n-\t * between a RENAME_DELETE conflict and RENAME_VIA_DIR (they\n-\t * otherwise look the same).  If it was originally a rename ('R'),\n-\t * this lets us remember and report accurately about the transitive\n-\t * renaming that occurred via the directory rename detection.  Also,\n-\t * record the original destination name.\n-\t */\n-\tre->dir_rename_original_type = pair->status;\n-\tre->dir_rename_original_dest = pair->two->path;\n-\n-\t/*\n-\t * We don't actually look at pair->status again, but it seems\n-\t * pedagogically correct to adjust it.\n-\t */\n-\tpair->status = 'R';\n-\n-\t/*\n-\t * Finally, record the new location.\n-\t */\n-\tpair->two->path = new_path;\n-}\n-\n-/*\n- * Get information of all renames which occurred in 'pairs', making use of\n- * any implicit directory renames inferred from the other side of history.\n- * We need the three trees in the merge ('o_tree', 'a_tree' and 'b_tree')\n- * to be able to associate the correct cache entries with the rename\n- * information; tree is always equal to either a_tree or b_tree.\n- */\n-static struct string_list *get_renames(struct merge_options *opt,\n-\t\t\t\t       const char *branch,\n-\t\t\t\t       struct diff_queue_struct *pairs,\n-\t\t\t\t       struct hashmap *dir_renames,\n-\t\t\t\t       struct hashmap *dir_rename_exclusions,\n-\t\t\t\t       struct tree *tree,\n-\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t       struct tree *a_tree,\n-\t\t\t\t       struct tree *b_tree,\n-\t\t\t\t       struct string_list *entries,\n-\t\t\t\t       int *clean_merge)\n-{\n-\tint i;\n-\tstruct hashmap collisions;\n-\tstruct hashmap_iter iter;\n-\tstruct collision_entry *e;\n-\tstruct string_list *renames;\n-\n-\tcompute_collisions(&collisions, dir_renames, pairs);\n-\tCALLOC_ARRAY(renames, 1);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct rename *re;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *new_path; /* non-NULL only with directory renames */\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R') {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tnew_path = check_for_directory_rename(opt, pair->two->path, tree,\n-\t\t\t\t\t\t      dir_renames,\n-\t\t\t\t\t\t      dir_rename_exclusions,\n-\t\t\t\t\t\t      &collisions,\n-\t\t\t\t\t\t      clean_merge);\n-\t\tif (pair->status != 'R' && !new_path) {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tre = xmalloc(sizeof(*re));\n-\t\tre->processed = 0;\n-\t\tre->pair = pair;\n-\t\tre->branch = branch;\n-\t\tre->dir_rename_original_type = '\\0';\n-\t\tre->dir_rename_original_dest = NULL;\n-\t\titem = string_list_lookup(entries, re->pair->one->path);\n-\t\tif (!item)\n-\t\t\tre->src_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->one->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->src_entry = item->util;\n-\n-\t\titem = string_list_lookup(entries, re->pair->two->path);\n-\t\tif (!item)\n-\t\t\tre->dst_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->two->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->dst_entry = item->util;\n-\t\titem = string_list_insert(renames, pair->one->path);\n-\t\titem->util = re;\n-\t\tif (new_path)\n-\t\t\tapply_directory_rename_modifications(opt, pair, new_path,\n-\t\t\t\t\t\t\t     re, tree, o_tree,\n-\t\t\t\t\t\t\t     a_tree, b_tree,\n-\t\t\t\t\t\t\t     entries);\n-\t}\n-\n-\thashmap_for_each_entry(&collisions, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->target_file);\n-\t\tstring_list_clear(&e->source_files, 0);\n-\t}\n-\thashmap_clear_and_free(&collisions, struct collision_entry, ent);\n-\treturn renames;\n-}\n-\n-static int process_renames(struct merge_options *opt,\n-\t\t\t   struct string_list *a_renames,\n-\t\t\t   struct string_list *b_renames)\n-{\n-\tint clean_merge = 1, i, j;\n-\tstruct string_list a_by_dst = STRING_LIST_INIT_NODUP;\n-\tstruct string_list b_by_dst = STRING_LIST_INIT_NODUP;\n-\tconst struct rename *sre;\n-\n-\t/*\n-\t * Note that as we build the list, we do not need to check if the\n-\t * existing destination path is already in the list, because the\n-\t * structure of diffcore_rename guarantees we won't have duplicates.\n-\t */\n-\tfor (i = 0; i < a_renames->nr; i++) {\n-\t\tsre = a_renames->items[i].util;\n-\t\tstring_list_append(&a_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tfor (i = 0; i < b_renames->nr; i++) {\n-\t\tsre = b_renames->items[i].util;\n-\t\tstring_list_append(&b_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tstring_list_sort(&a_by_dst);\n-\tstring_list_sort(&b_by_dst);\n-\n-\tfor (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {\n-\t\tstruct string_list *renames1, *renames2Dst;\n-\t\tstruct rename *ren1 = NULL, *ren2 = NULL;\n-\t\tconst char *ren1_src, *ren1_dst;\n-\t\tstruct string_list_item *lookup;\n-\n-\t\tif (i >= a_renames->nr) {\n-\t\t\tren2 = b_renames->items[j++].util;\n-\t\t} else if (j >= b_renames->nr) {\n-\t\t\tren1 = a_renames->items[i++].util;\n-\t\t} else {\n-\t\t\tint compare = strcmp(a_renames->items[i].string,\n-\t\t\t\t\t     b_renames->items[j].string);\n-\t\t\tif (compare <= 0)\n-\t\t\t\tren1 = a_renames->items[i++].util;\n-\t\t\tif (compare >= 0)\n-\t\t\t\tren2 = b_renames->items[j++].util;\n-\t\t}\n-\n-\t\t/* TODO: refactor, so that 1/2 are not needed */\n-\t\tif (ren1) {\n-\t\t\trenames1 = a_renames;\n-\t\t\trenames2Dst = &b_by_dst;\n-\t\t} else {\n-\t\t\trenames1 = b_renames;\n-\t\t\trenames2Dst = &a_by_dst;\n-\t\t\tSWAP(ren2, ren1);\n-\t\t}\n-\n-\t\tif (ren1->processed)\n-\t\t\tcontinue;\n-\t\tren1->processed = 1;\n-\t\tren1->dst_entry->processed = 1;\n-\t\t/* BUG: We should only mark src_entry as processed if we\n-\t\t * are not dealing with a rename + add-source case.\n-\t\t */\n-\t\tren1->src_entry->processed = 1;\n-\n-\t\tren1_src = ren1->pair->one->path;\n-\t\tren1_dst = ren1->pair->two->path;\n-\n-\t\tif (ren2) {\n-\t\t\t/* One file renamed on both sides */\n-\t\t\tconst char *ren2_src = ren2->pair->one->path;\n-\t\t\tconst char *ren2_dst = ren2->pair->two->path;\n-\t\t\tenum rename_type rename_type;\n-\t\t\tif (strcmp(ren1_src, ren2_src) != 0)\n-\t\t\t\tBUG(\"ren1_src != ren2_src\");\n-\t\t\tren2->dst_entry->processed = 1;\n-\t\t\tren2->processed = 1;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0) {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_TWO;\n-\t\t\t\tclean_merge = 0;\n-\t\t\t} else {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_ONE;\n-\t\t\t\t/* BUG: We should only remove ren1_src in\n-\t\t\t\t * the base stage (think of rename +\n-\t\t\t\t * add-source cases).\n-\t\t\t\t */\n-\t\t\t\tremove_file(opt, 1, ren1_src, 1);\n-\t\t\t\tupdate_entry(ren1->dst_entry,\n-\t\t\t\t\t     ren1->pair->one,\n-\t\t\t\t\t     ren1->pair->two,\n-\t\t\t\t\t     ren2->pair->two);\n-\t\t\t}\n-\t\t\tsetup_rename_conflict_info(rename_type, opt, ren1, ren2);\n-\t\t} else if ((lookup = string_list_lookup(renames2Dst, ren1_dst))) {\n-\t\t\t/* Two different files renamed to the same thing */\n-\t\t\tchar *ren2_dst;\n-\t\t\tren2 = lookup->util;\n-\t\t\tren2_dst = ren2->pair->two->path;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0)\n-\t\t\t\tBUG(\"ren1_dst != ren2_dst\");\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tren2->processed = 1;\n-\t\t\t/*\n-\t\t\t * BUG: We should only mark src_entry as processed\n-\t\t\t * if we are not dealing with a rename + add-source\n-\t\t\t * case.\n-\t\t\t */\n-\t\t\tren2->src_entry->processed = 1;\n-\n-\t\t\tsetup_rename_conflict_info(RENAME_TWO_FILES_TO_ONE,\n-\t\t\t\t\t\t   opt, ren1, ren2);\n-\t\t} else {\n-\t\t\t/* Renamed in 1, maybe changed in 2 */\n-\t\t\t/* we only use sha1 and mode of these */\n-\t\t\tstruct diff_filespec src_other, dst_other;\n-\t\t\tint try_merge;\n-\n-\t\t\t/*\n-\t\t\t * unpack_trees loads entries from common-commit\n-\t\t\t * into stage 1, from head-commit into stage 2, and\n-\t\t\t * from merge-commit into stage 3.  We keep track\n-\t\t\t * of which side corresponds to the rename.\n-\t\t\t */\n-\t\t\tint renamed_stage = a_renames == renames1 ? 2 : 3;\n-\t\t\tint other_stage =   a_renames == renames1 ? 3 : 2;\n-\n-\t\t\t/*\n-\t\t\t * Directory renames have a funny corner case...\n-\t\t\t */\n-\t\t\tint renamed_to_self = !strcmp(ren1_src, ren1_dst);\n-\n-\t\t\t/* BUG: We should only remove ren1_src in the base\n-\t\t\t * stage and in other_stage (think of rename +\n-\t\t\t * add-source case).\n-\t\t\t */\n-\t\t\tif (!renamed_to_self)\n-\t\t\t\tremove_file(opt, 1, ren1_src,\n-\t\t\t\t\t    renamed_stage == 2 ||\n-\t\t\t\t\t    !was_tracked(opt, ren1_src));\n-\n-\t\t\toidcpy(&src_other.oid,\n-\t\t\t       &ren1->src_entry->stages[other_stage].oid);\n-\t\t\tsrc_other.mode = ren1->src_entry->stages[other_stage].mode;\n-\t\t\toidcpy(&dst_other.oid,\n-\t\t\t       &ren1->dst_entry->stages[other_stage].oid);\n-\t\t\tdst_other.mode = ren1->dst_entry->stages[other_stage].mode;\n-\t\t\ttry_merge = 0;\n-\n-\t\t\tif (oideq(&src_other.oid, null_oid()) &&\n-\t\t\t    ren1->dir_rename_original_type == 'A') {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_VIA_DIR,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (renamed_to_self) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (oideq(&src_other.oid, null_oid())) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_DELETE,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if ((dst_other.mode == ren1->pair->two->mode) &&\n-\t\t\t\t   oideq(&dst_other.oid, &ren1->pair->two->oid)) {\n-\t\t\t\t/*\n-\t\t\t\t * Added file on the other side identical to\n-\t\t\t\t * the file being renamed: clean merge.\n-\t\t\t\t * Also, there is no need to overwrite the\n-\t\t\t\t * file already in the working copy, so call\n-\t\t\t\t * update_file_flags() instead of\n-\t\t\t\t * update_file().\n-\t\t\t\t */\n-\t\t\t\tif (update_file_flags(opt,\n-\t\t\t\t\t\t      ren1->pair->two,\n-\t\t\t\t\t\t      ren1_dst,\n-\t\t\t\t\t\t      1, /* update_cache */\n-\t\t\t\t\t\t      0  /* update_wd    */))\n-\t\t\t\t\tclean_merge = -1;\n-\t\t\t} else if (!oideq(&dst_other.oid, null_oid())) {\n-\t\t\t\t/*\n-\t\t\t\t * Probably not a clean merge, but it's\n-\t\t\t\t * premature to set clean_merge to 0 here,\n-\t\t\t\t * because if the rename merges cleanly and\n-\t\t\t\t * the merge exactly matches the newly added\n-\t\t\t\t * file, then the merge will be clean.\n-\t\t\t\t */\n-\t\t\t\tsetup_rename_conflict_info(RENAME_ADD,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else\n-\t\t\t\ttry_merge = 1;\n-\n-\t\t\tif (clean_merge < 0)\n-\t\t\t\tgoto cleanup_and_return;\n-\t\t\tif (try_merge) {\n-\t\t\t\tstruct diff_filespec *o, *a, *b;\n-\t\t\t\tsrc_other.path = (char *)ren1_src;\n-\n-\t\t\t\to = ren1->pair->one;\n-\t\t\t\tif (a_renames == renames1) {\n-\t\t\t\t\ta = ren1->pair->two;\n-\t\t\t\t\tb = &src_other;\n-\t\t\t\t} else {\n-\t\t\t\t\tb = ren1->pair->two;\n-\t\t\t\t\ta = &src_other;\n-\t\t\t\t}\n-\t\t\t\tupdate_entry(ren1->dst_entry, o, a, b);\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t}\n-\t\t}\n-\t}\n-cleanup_and_return:\n-\tstring_list_clear(&a_by_dst, 0);\n-\tstring_list_clear(&b_by_dst, 0);\n-\n-\treturn clean_merge;\n-}\n-\n-struct rename_info {\n-\tstruct string_list *head_renames;\n-\tstruct string_list *merge_renames;\n-};\n-\n-static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n-\t\t\t\t   struct hashmap *dir_renames)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *e;\n-\n-\thashmap_for_each_entry(dir_renames, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->dir);\n-\t\tstrbuf_release(&e->new_dir);\n-\t\t/* possible_new_dirs already cleared in get_directory_renames */\n-\t}\n-\thashmap_clear_and_free(dir_renames, struct dir_rename_entry, ent);\n-\tfree(dir_renames);\n-\n-\tfree(pairs->queue);\n-\tfree(pairs);\n-}\n-\n-static int detect_and_process_renames(struct merge_options *opt,\n-\t\t\t\t      struct tree *common,\n-\t\t\t\t      struct tree *head,\n-\t\t\t\t      struct tree *merge,\n-\t\t\t\t      struct string_list *entries,\n-\t\t\t\t      struct rename_info *ri)\n-{\n-\tstruct diff_queue_struct *head_pairs, *merge_pairs;\n-\tstruct hashmap *dir_re_head, *dir_re_merge;\n-\tint clean = 1;\n-\n-\tri->head_renames = NULL;\n-\tri->merge_renames = NULL;\n-\n-\tif (!merge_detect_rename(opt))\n-\t\treturn 1;\n-\n-\thead_pairs = get_diffpairs(opt, common, head);\n-\tmerge_pairs = get_diffpairs(opt, common, merge);\n-\n-\tif ((opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) ||\n-\t    (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t     !opt->priv->call_depth)) {\n-\t\tdir_re_head = get_directory_renames(head_pairs);\n-\t\tdir_re_merge = get_directory_renames(merge_pairs);\n-\n-\t\thandle_directory_level_conflicts(opt,\n-\t\t\t\t\t\t dir_re_head, head,\n-\t\t\t\t\t\t dir_re_merge, merge);\n-\t} else {\n-\t\tdir_re_head  = xmalloc(sizeof(*dir_re_head));\n-\t\tdir_re_merge = xmalloc(sizeof(*dir_re_merge));\n-\t\tdir_rename_init(dir_re_head);\n-\t\tdir_rename_init(dir_re_merge);\n-\t}\n-\n-\tri->head_renames  = get_renames(opt, opt->branch1, head_pairs,\n-\t\t\t\t\tdir_re_merge, dir_re_head, head,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tri->merge_renames = get_renames(opt, opt->branch2, merge_pairs,\n-\t\t\t\t\tdir_re_head, dir_re_merge, merge,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tclean &= process_renames(opt, ri->head_renames, ri->merge_renames);\n-\n-cleanup:\n-\t/*\n-\t * Some cleanup is deferred until cleanup_renames() because the\n-\t * data structures are still needed and referenced in\n-\t * process_entry().  But there are a few things we can free now.\n-\t */\n-\tinitial_cleanup_rename(head_pairs, dir_re_head);\n-\tinitial_cleanup_rename(merge_pairs, dir_re_merge);\n-\n-\treturn clean;\n-}\n-\n-static void final_cleanup_rename(struct string_list *rename)\n-{\n-\tconst struct rename *re;\n-\tint i;\n-\n-\tif (!rename)\n-\t\treturn;\n-\n-\tfor (i = 0; i < rename->nr; i++) {\n-\t\tre = rename->items[i].util;\n-\t\tdiff_free_filepair(re->pair);\n-\t\tif (re->src_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->src_entry->rename_conflict_info);\n-\t\tif (re->dst_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->dst_entry->rename_conflict_info);\n-\t}\n-\tstring_list_clear(rename, 1);\n-\tfree(rename);\n-}\n-\n-static void final_cleanup_renames(struct rename_info *re_info)\n-{\n-\tfinal_cleanup_rename(re_info->head_renames);\n-\tfinal_cleanup_rename(re_info->merge_renames);\n-}\n-\n-static int read_oid_strbuf(struct merge_options *opt,\n-\t\t\t   const struct object_id *oid,\n-\t\t\t   struct strbuf *dst)\n-{\n-\tvoid *buf;\n-\tenum object_type type;\n-\tunsigned long size;\n-\tbuf = repo_read_object_file(the_repository, oid, &type, &size);\n-\tif (!buf)\n-\t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n-\tif (type != OBJ_BLOB) {\n-\t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n-\t}\n-\tstrbuf_attach(dst, buf, size, size + 1);\n-\treturn 0;\n-}\n-\n-static int blob_unchanged(struct merge_options *opt,\n-\t\t\t  const struct diff_filespec *o,\n-\t\t\t  const struct diff_filespec *a,\n-\t\t\t  int renormalize, const char *path)\n-{\n-\tstruct strbuf obuf = STRBUF_INIT;\n-\tstruct strbuf abuf = STRBUF_INIT;\n-\tint ret = 0; /* assume changed for safety */\n-\tstruct index_state *idx = opt->repo->index;\n-\n-\tif (a->mode != o->mode)\n-\t\treturn 0;\n-\tif (oideq(&o->oid, &a->oid))\n-\t\treturn 1;\n-\tif (!renormalize)\n-\t\treturn 0;\n-\n-\tif (read_oid_strbuf(opt, &o->oid, &obuf) ||\n-\t    read_oid_strbuf(opt, &a->oid, &abuf))\n-\t\tgoto error_return;\n-\t/*\n-\t * Note: binary | is used so that both renormalizations are\n-\t * performed.  Comparison can be skipped if both files are\n-\t * unchanged since their sha1s have already been compared.\n-\t */\n-\tif (renormalize_buffer(idx, path, obuf.buf, obuf.len, &obuf) |\n-\t    renormalize_buffer(idx, path, abuf.buf, abuf.len, &abuf))\n-\t\tret = (obuf.len == abuf.len && !memcmp(obuf.buf, abuf.buf, obuf.len));\n-\n-error_return:\n-\tstrbuf_release(&obuf);\n-\tstrbuf_release(&abuf);\n-\treturn ret;\n-}\n-\n-static int handle_modify_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b)\n-{\n-\tconst char *modify_branch, *delete_branch;\n-\tconst struct diff_filespec *changed;\n-\n-\tif (is_valid(a)) {\n-\t\tmodify_branch = opt->branch1;\n-\t\tdelete_branch = opt->branch2;\n-\t\tchanged = a;\n-\t} else {\n-\t\tmodify_branch = opt->branch2;\n-\t\tdelete_branch = opt->branch1;\n-\t\tchanged = b;\n-\t}\n-\n-\treturn handle_change_delete(opt,\n-\t\t\t\t    path, NULL,\n-\t\t\t\t    o, changed,\n-\t\t\t\t    modify_branch, delete_branch,\n-\t\t\t\t    _(\"modify\"), _(\"modified\"));\n-}\n-\n-static int handle_content_merge(struct merge_file_info *mfi,\n-\t\t\t\tstruct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tint is_dirty,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst char *reason = _(\"content\");\n-\tunsigned df_conflict_remains = 0;\n-\n-\tif (!is_valid(o))\n-\t\treason = _(\"add/add\");\n-\n-\tassert(o->path && a->path && b->path);\n-\tif (ci && dir_in_way(opt->repo->index, path, !opt->priv->call_depth,\n-\t\t\t     S_ISGITLINK(ci->ren1->pair->two->mode)))\n-\t\tdf_conflict_remains = 1;\n-\n-\tif (merge_mode_and_contents(opt, o, a, b, path,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    opt->priv->call_depth * 2, mfi))\n-\t\treturn -1;\n-\n-\t/*\n-\t * We can skip updating the working tree file iff:\n-\t *   a) The merge is clean\n-\t *   b) The merge matches what was in HEAD (content, mode, pathname)\n-\t *   c) The target path is usable (i.e. not involved in D/F conflict)\n-\t */\n-\tif (mfi->clean && was_tracked_and_matches(opt, path, &mfi->blob) &&\n-\t    !df_conflict_remains) {\n-\t\tint pos;\n-\t\tstruct cache_entry *ce;\n-\n-\t\toutput(opt, 3, _(\"Skipped %s (merged same as existing)\"), path);\n-\t\tif (add_cacheinfo(opt, &mfi->blob, path,\n-\t\t\t\t  0, (!opt->priv->call_depth && !is_dirty), 0))\n-\t\t\treturn -1;\n-\t\t/*\n-\t\t * However, add_cacheinfo() will delete the old cache entry\n-\t\t * and add a new one.  We need to copy over any skip_worktree\n-\t\t * flag to avoid making the file appear as if it were\n-\t\t * deleted by the user.\n-\t\t */\n-\t\tpos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\t\tce = opt->priv->orig_index.cache[pos];\n-\t\tif (ce_skip_worktree(ce)) {\n-\t\t\tpos = index_name_pos(opt->repo->index, path, strlen(path));\n-\t\t\tce = opt->repo->index->cache[pos];\n-\t\t\tce->ce_flags |= CE_SKIP_WORKTREE;\n-\t\t}\n-\t\treturn mfi->clean;\n-\t}\n-\n-\tif (!mfi->clean) {\n-\t\tif (S_ISGITLINK(mfi->blob.mode))\n-\t\t\treason = _(\"submodule\");\n-\t\toutput(opt, 1, _(\"CONFLICT (%s): Merge conflict in %s\"),\n-\t\t\t\treason, path);\n-\t\tif (ci && !df_conflict_remains)\n-\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\treturn -1;\n-\t}\n-\n-\tif (df_conflict_remains || is_dirty) {\n-\t\tchar *new_path;\n-\t\tif (opt->priv->call_depth) {\n-\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t} else {\n-\t\t\tif (!mfi->clean) {\n-\t\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\t\treturn -1;\n-\t\t\t} else {\n-\t\t\t\tint file_from_stage2 = was_tracked(opt, path);\n-\n-\t\t\t\tif (update_stages(opt, path, NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? &mfi->blob : NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? NULL : &mfi->blob))\n-\t\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t}\n-\t\tnew_path = unique_path(opt, path, ci->ren1->branch);\n-\t\tif (is_dirty) {\n-\t\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t\t       path);\n-\t\t}\n-\t\toutput(opt, 1, _(\"Adding as %s instead\"), new_path);\n-\t\tif (update_file(opt, 0, &mfi->blob, new_path)) {\n-\t\t\tfree(new_path);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tfree(new_path);\n-\t\tmfi->clean = 0;\n-\t} else if (update_file(opt, mfi->clean, &mfi->blob, path))\n-\t\treturn -1;\n-\treturn !is_dirty && mfi->clean;\n-}\n-\n-static int handle_rename_normal(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tstruct rename *ren = ci->ren1;\n-\tstruct merge_file_info mfi;\n-\tint clean;\n-\n-\t/* Merge the content and write it out */\n-\tclean = handle_content_merge(&mfi, opt, path, was_dirty(opt, path),\n-\t\t\t\t     o, a, b, ci);\n-\n-\tif (clean &&\n-\t    opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t    ren->dir_rename_original_dest) {\n-\t\tif (update_stages(opt, path,\n-\t\t\t\t  &mfi.blob, &mfi.blob, &mfi.blob))\n-\t\t\treturn -1;\n-\t\tclean = 0; /* not clean, but conflicted */\n-\t}\n-\treturn clean;\n-}\n-\n-static void dir_rename_warning(const char *msg,\n-\t\t\t       int is_add,\n-\t\t\t       int clean,\n-\t\t\t       struct merge_options *opt,\n-\t\t\t       struct rename *ren)\n-{\n-\tconst char *other_branch;\n-\tother_branch = (ren->branch == opt->branch1 ?\n-\t\t\topt->branch2 : opt->branch1);\n-\tif (is_add) {\n-\t\toutput(opt, clean ? 2 : 1, msg,\n-\t\t       ren->pair->one->path, ren->branch,\n-\t\t       other_branch, ren->pair->two->path);\n-\t\treturn;\n-\t}\n-\toutput(opt, clean ? 2 : 1, msg,\n-\t       ren->pair->one->path, ren->dir_rename_original_dest, ren->branch,\n-\t       other_branch, ren->pair->two->path);\n-}\n-static int warn_about_dir_renamed_entries(struct merge_options *opt,\n-\t\t\t\t\t  struct rename *ren)\n-{\n-\tconst char *msg;\n-\tint clean = 1, is_add;\n-\n-\tif (!ren)\n-\t\treturn clean;\n-\n-\t/* Return early if ren was not affected/created by a directory rename */\n-\tif (!ren->dir_rename_original_dest)\n-\t\treturn clean;\n-\n-\t/* Sanity checks */\n-\tassert(opt->detect_directory_renames > MERGE_DIRECTORY_RENAMES_NONE);\n-\tassert(ren->dir_rename_original_type == 'A' ||\n-\t       ren->dir_rename_original_type == 'R');\n-\n-\t/* Check whether to treat directory renames as a conflict */\n-\tclean = (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE);\n-\n-\tis_add = (ren->dir_rename_original_type == 'A');\n-\tif (ren->dir_rename_original_type == 'A' && clean) {\n-\t\tmsg = _(\"Path updated: %s added in %s inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'A' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s added in %s \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && clean) {\n-\t\tmsg = _(\"Path updated: %s renamed to %s in %s, inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s renamed to %s in %s, \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else {\n-\t\tBUG(\"Impossible dir_rename_original_type/clean combination\");\n-\t}\n-\tdir_rename_warning(msg, is_add, clean, opt, ren);\n-\n-\treturn clean;\n-}\n-\n-/* Per entry merge function */\n-static int process_entry(struct merge_options *opt,\n-\t\t\t const char *path, struct stage_data *entry)\n-{\n-\tint clean_merge = 1;\n-\tint normalize = opt->renormalize;\n-\n-\tstruct diff_filespec *o = &entry->stages[1];\n-\tstruct diff_filespec *a = &entry->stages[2];\n-\tstruct diff_filespec *b = &entry->stages[3];\n-\tint o_valid = is_valid(o);\n-\tint a_valid = is_valid(a);\n-\tint b_valid = is_valid(b);\n-\to->path = a->path = b->path = (char*)path;\n-\n-\tentry->processed = 1;\n-\tif (entry->rename_conflict_info) {\n-\t\tstruct rename_conflict_info *ci = entry->rename_conflict_info;\n-\t\tstruct diff_filespec *temp;\n-\t\tint path_clean;\n-\n-\t\tpath_clean = warn_about_dir_renamed_entries(opt, ci->ren1);\n-\t\tpath_clean &= warn_about_dir_renamed_entries(opt, ci->ren2);\n-\n-\t\t/*\n-\t\t * For cases with a single rename, {o,a,b}->path have all been\n-\t\t * set to the rename target path; we need to set two of these\n-\t\t * back to the rename source.\n-\t\t * For rename/rename conflicts, we'll manually fix paths below.\n-\t\t */\n-\t\ttemp = (opt->branch1 == ci->ren1->branch) ? b : a;\n-\t\to->path = temp->path = ci->ren1->pair->one->path;\n-\t\tif (ci->ren2) {\n-\t\t\tassert(opt->branch1 == ci->ren1->branch);\n-\t\t}\n-\n-\t\tswitch (ci->rename_type) {\n-\t\tcase RENAME_NORMAL:\n-\t\tcase RENAME_ONE_FILE_TO_ONE:\n-\t\t\tclean_merge = handle_rename_normal(opt, path, o, a, b,\n-\t\t\t\t\t\t\t   ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_VIA_DIR:\n-\t\t\tclean_merge = handle_rename_via_dir(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_ADD:\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the renamed file\n-\t\t\t * merges cleanly and the result can then be\n-\t\t\t * two-way merged cleanly with the added file, I\n-\t\t\t * guess it's a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_add(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_DELETE:\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_delete(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_ONE_FILE_TO_TWO:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note:\n-\t\t\t * ren[12]->pair->one->path are equal.\n-\t\t\t */\n-\t\t\to->path = ci->ren1->pair->one->path;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_rename_1to2(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_TWO_FILES_TO_ONE:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note,\n-\t\t\t * ren[12]->pair->two->path are actually equal.\n-\t\t\t */\n-\t\t\to->path = NULL;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the two renamed\n-\t\t\t * files merge cleanly and the two resulting files\n-\t\t\t * can then be two-way merged cleanly, I guess it's\n-\t\t\t * a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_rename_2to1(opt, ci);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tentry->processed = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (path_clean < clean_merge)\n-\t\t\tclean_merge = path_clean;\n-\t} else if (o_valid && (!a_valid || !b_valid)) {\n-\t\t/* Case A: Deleted in one */\n-\t\tif ((!a_valid && !b_valid) ||\n-\t\t    (!b_valid && blob_unchanged(opt, o, a, normalize, path)) ||\n-\t\t    (!a_valid && blob_unchanged(opt, o, b, normalize, path))) {\n-\t\t\t/* Deleted in both or deleted in one and\n-\t\t\t * unchanged in the other */\n-\t\t\tif (a_valid)\n-\t\t\t\toutput(opt, 2, _(\"Removing %s\"), path);\n-\t\t\t/* do not touch working file if it did not exist */\n-\t\t\tremove_file(opt, 1, path, !a_valid);\n-\t\t} else {\n-\t\t\t/* Modify/delete; deleted side may have put a directory in the way */\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_modify_delete(opt, path, o, a, b))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if ((!o_valid && a_valid && !b_valid) ||\n-\t\t   (!o_valid && !a_valid && b_valid)) {\n-\t\t/* Case B: Added in one. */\n-\t\t/* [nothing|directory] -> ([nothing|directory], file) */\n-\n-\t\tconst char *add_branch;\n-\t\tconst char *other_branch;\n-\t\tconst char *conf;\n-\t\tconst struct diff_filespec *contents;\n-\n-\t\tif (a_valid) {\n-\t\t\tadd_branch = opt->branch1;\n-\t\t\tother_branch = opt->branch2;\n-\t\t\tcontents = a;\n-\t\t\tconf = _(\"file/directory\");\n-\t\t} else {\n-\t\t\tadd_branch = opt->branch2;\n-\t\t\tother_branch = opt->branch1;\n-\t\t\tcontents = b;\n-\t\t\tconf = _(\"directory/file\");\n-\t\t}\n-\t\tif (dir_in_way(opt->repo->index, path,\n-\t\t\t       !opt->priv->call_depth && !S_ISGITLINK(a->mode),\n-\t\t\t       0)) {\n-\t\t\tchar *new_path = unique_path(opt, path, add_branch);\n-\t\t\tclean_merge = 0;\n-\t\t\toutput(opt, 1, _(\"CONFLICT (%s): There is a directory with name %s in %s. \"\n-\t\t\t       \"Adding %s as %s\"),\n-\t\t\t       conf, path, other_branch, path, new_path);\n-\t\t\tif (update_file(opt, 0, contents, new_path))\n-\t\t\t\tclean_merge = -1;\n-\t\t\telse if (opt->priv->call_depth)\n-\t\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t\tfree(new_path);\n-\t\t} else {\n-\t\t\toutput(opt, 2, _(\"Adding %s\"), path);\n-\t\t\t/* do not overwrite file if already present */\n-\t\t\tif (update_file_flags(opt, contents, path, 1, !a_valid))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if (a_valid && b_valid) {\n-\t\tif (!o_valid) {\n-\t\t\t/* Case C: Added in both (check for same permissions) */\n-\t\t\toutput(opt, 1,\n-\t\t\t       _(\"CONFLICT (add/add): Merge conflict in %s\"),\n-\t\t\t       path);\n-\t\t\tclean_merge = handle_file_collision(opt,\n-\t\t\t\t\t\t\t    path, NULL, NULL,\n-\t\t\t\t\t\t\t    opt->branch1,\n-\t\t\t\t\t\t\t    opt->branch2,\n-\t\t\t\t\t\t\t    a, b);\n-\t\t} else {\n-\t\t\t/* case D: Modified in both, but differently. */\n-\t\t\tstruct merge_file_info mfi;\n-\t\t\tint is_dirty = 0; /* unpack_trees would have bailed if dirty */\n-\t\t\tclean_merge = handle_content_merge(&mfi, opt, path,\n-\t\t\t\t\t\t\t   is_dirty,\n-\t\t\t\t\t\t\t   o, a, b, NULL);\n-\t\t}\n-\t} else if (!o_valid && !a_valid && !b_valid) {\n-\t\t/*\n-\t\t * this entry was deleted altogether. a_mode == 0 means\n-\t\t * we had that path and want to actively remove it.\n-\t\t */\n-\t\tremove_file(opt, 1, path, !a->mode);\n-\t} else\n-\t\tBUG(\"fatal merge failure, shouldn't happen.\");\n-\n-\treturn clean_merge;\n-}\n-\n-static int merge_trees_internal(struct merge_options *opt,\n-\t\t\t\tstruct tree *head,\n-\t\t\t\tstruct tree *merge,\n-\t\t\t\tstruct tree *merge_base,\n-\t\t\t\tstruct tree **result)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tint code, clean;\n-\n-\tif (opt->subtree_shift) {\n-\t\tmerge = shift_tree_object(opt->repo, head, merge,\n-\t\t\t\t\t  opt->subtree_shift);\n-\t\tmerge_base = shift_tree_object(opt->repo, head, merge_base,\n-\t\t\t\t\t       opt->subtree_shift);\n-\t}\n-\n-\tif (oideq(&merge_base->object.oid, &merge->object.oid)) {\n-\t\toutput(opt, 0, _(\"Already up to date.\"));\n-\t\t*result = head;\n-\t\treturn 1;\n-\t}\n-\n-\tcode = unpack_trees_start(opt, merge_base, head, merge);\n-\n-\tif (code != 0) {\n-\t\tif (show(opt, 4) || opt->priv->call_depth)\n-\t\t\terr(opt, _(\"merging of trees %s and %s failed\"),\n-\t\t\t    oid_to_hex(&head->object.oid),\n-\t\t\t    oid_to_hex(&merge->object.oid));\n-\t\tunpack_trees_finish(opt);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unmerged_index(istate)) {\n-\t\tstruct string_list *entries;\n-\t\tstruct rename_info re_info;\n-\t\tint i;\n-\t\t/*\n-\t\t * Only need the hashmap while processing entries, so\n-\t\t * initialize it here and free it when we are done running\n-\t\t * through the entries. Keeping it in the merge_options as\n-\t\t * opposed to decaring a local hashmap is for convenience\n-\t\t * so that we don't have to pass it to around.\n-\t\t */\n-\t\thashmap_init(&opt->priv->current_file_dir_set, path_hashmap_cmp,\n-\t\t\t     NULL, 512);\n-\t\tget_files_dirs(opt, head);\n-\t\tget_files_dirs(opt, merge);\n-\n-\t\tentries = get_unmerged(opt->repo->index);\n-\t\tclean = detect_and_process_renames(opt, merge_base, head, merge,\n-\t\t\t\t\t\t   entries, &re_info);\n-\t\trecord_df_conflict_files(opt, entries);\n-\t\tif (clean < 0)\n-\t\t\tgoto cleanup;\n-\t\tfor (i = entries->nr-1; 0 <= i; i--) {\n-\t\t\tconst char *path = entries->items[i].string;\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed) {\n-\t\t\t\tint ret = process_entry(opt, path, e);\n-\t\t\t\tif (!ret)\n-\t\t\t\t\tclean = 0;\n-\t\t\t\telse if (ret < 0) {\n-\t\t\t\t\tclean = ret;\n-\t\t\t\t\tgoto cleanup;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t\tfor (i = 0; i < entries->nr; i++) {\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed)\n-\t\t\t\tBUG(\"unprocessed path??? %s\",\n-\t\t\t\t    entries->items[i].string);\n-\t\t}\n-\n-\tcleanup:\n-\t\tfinal_cleanup_renames(&re_info);\n-\n-\t\tstring_list_clear(entries, 1);\n-\t\tfree(entries);\n-\n-\t\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t\t\tstruct path_hashmap_entry, e);\n-\n-\t\tif (clean < 0) {\n-\t\t\tunpack_trees_finish(opt);\n-\t\t\treturn clean;\n-\t\t}\n-\t}\n-\telse\n-\t\tclean = 1;\n-\n-\tunpack_trees_finish(opt);\n-\n-\tif (opt->priv->call_depth &&\n-\t    !(*result = write_in_core_index_as_tree(opt->repo)))\n-\t\treturn -1;\n-\n-\treturn clean;\n-}\n-\n-/*\n- * Merge the commits h1 and h2, returning a flag (int) indicating the\n- * cleanness of the merge.  Also, if opt->priv->call_depth, create a\n- * virtual commit and write its location to *result.\n- */\n-static int merge_recursive_internal(struct merge_options *opt,\n-\t\t\t\t    struct commit *h1,\n-\t\t\t\t    struct commit *h2,\n-\t\t\t\t    const struct commit_list *_merge_bases,\n-\t\t\t\t    struct commit **result)\n-{\n-\tstruct commit_list *merge_bases = copy_commit_list(_merge_bases);\n-\tstruct commit_list *iter;\n-\tstruct commit *merged_merge_bases;\n-\tstruct tree *result_tree;\n-\tconst char *ancestor_name;\n-\tstruct strbuf merge_base_abbrev = STRBUF_INIT;\n-\tint ret;\n-\n-\tif (show(opt, 4)) {\n-\t\toutput(opt, 4, _(\"Merging:\"));\n-\t\toutput_commit_title(opt, h1);\n-\t\toutput_commit_title(opt, h2);\n-\t}\n-\n-\tif (!merge_bases) {\n-\t\tif (repo_get_merge_bases(the_repository, h1, h2,\n-\t\t\t\t\t &merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tmerge_bases = reverse_commit_list(merge_bases);\n-\t}\n-\n-\tif (show(opt, 5)) {\n-\t\tunsigned cnt = commit_list_count(merge_bases);\n-\n-\t\toutput(opt, 5, Q_(\"found %u common ancestor:\",\n-\t\t\t\t\"found %u common ancestors:\", cnt), cnt);\n-\t\tfor (iter = merge_bases; iter; iter = iter->next)\n-\t\t\toutput_commit_title(opt, iter->item);\n-\t}\n-\n-\tmerged_merge_bases = pop_commit(&merge_bases);\n-\tif (!merged_merge_bases) {\n-\t\t/* if there is no common ancestor, use an empty tree */\n-\t\tstruct tree *tree;\n-\n-\t\ttree = lookup_tree(opt->repo, opt->repo->hash_algo->empty_tree);\n-\t\tmerged_merge_bases = make_virtual_commit(opt->repo, tree,\n-\t\t\t\t\t\t\t \"ancestor\");\n-\t\tancestor_name = \"empty tree\";\n-\t} else if (opt->ancestor && !opt->priv->call_depth) {\n-\t\tancestor_name = opt->ancestor;\n-\t} else if (merge_bases) {\n-\t\tancestor_name = \"merged common ancestors\";\n-\t} else {\n-\t\tstrbuf_add_unique_abbrev(&merge_base_abbrev,\n-\t\t\t\t\t &merged_merge_bases->object.oid,\n-\t\t\t\t\t DEFAULT_ABBREV);\n-\t\tancestor_name = merge_base_abbrev.buf;\n-\t}\n-\n-\tfor (iter = merge_bases; iter; iter = iter->next) {\n-\t\tconst char *saved_b1, *saved_b2;\n-\t\topt->priv->call_depth++;\n-\t\t/*\n-\t\t * When the merge fails, the result contains files\n-\t\t * with conflict markers. The cleanness flag is\n-\t\t * ignored (unless indicating an error), it was never\n-\t\t * actually used, as result of merge_trees has always\n-\t\t * overwritten it: the committed \"conflicts\" were\n-\t\t * already resolved.\n-\t\t */\n-\t\tdiscard_index(opt->repo->index);\n-\t\tsaved_b1 = opt->branch1;\n-\t\tsaved_b2 = opt->branch2;\n-\t\topt->branch1 = \"Temporary merge branch 1\";\n-\t\topt->branch2 = \"Temporary merge branch 2\";\n-\t\tif (merge_recursive_internal(opt, merged_merge_bases, iter->item,\n-\t\t\t\t\t     NULL, &merged_merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\topt->branch1 = saved_b1;\n-\t\topt->branch2 = saved_b2;\n-\t\topt->priv->call_depth--;\n-\n-\t\tif (!merged_merge_bases) {\n-\t\t\tret = err(opt, _(\"merge returned no commit\"));\n-\t\t\tgoto out;\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * FIXME: Since merge_recursive_internal() is only ever called by\n-\t * places that ensure the index is loaded first\n-\t * (e.g. builtin/merge.c, rebase/sequencer, etc.), in the common\n-\t * case where the merge base was unique that means when we get here\n-\t * we immediately discard the index and re-read it, which is a\n-\t * complete waste of time.  We should only be discarding and\n-\t * re-reading if we were forced to recurse.\n-\t */\n-\tdiscard_index(opt->repo->index);\n-\tif (!opt->priv->call_depth)\n-\t\trepo_read_index(opt->repo);\n-\n-\topt->ancestor = ancestor_name;\n-\tret = merge_trees_internal(opt,\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h1),\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h2),\n-\t\t\t\t   repo_get_commit_tree(opt->repo,\n-\t\t\t\t\t\t\tmerged_merge_bases),\n-\t\t\t\t   &result_tree);\n-\topt->ancestor = NULL;  /* avoid accidental re-use of opt->ancestor */\n-\tif (ret < 0) {\n-\t\tflush_output(opt);\n-\t\tgoto out;\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t*result = make_virtual_commit(opt->repo, result_tree,\n-\t\t\t\t\t      \"merged tree\");\n-\t\tcommit_list_insert(h1, &(*result)->parents);\n-\t\tcommit_list_insert(h2, &(*result)->parents->next);\n-\t}\n-\n-out:\n-\tstrbuf_release(&merge_base_abbrev);\n-\tfree_commit_list(merge_bases);\n-\treturn ret;\n-}\n-\n-static int merge_start(struct merge_options *opt, struct tree *head)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* Sanity checks on opt */\n-\tassert(opt->repo);\n-\n-\tassert(opt->branch1 && opt->branch2);\n-\n-\tassert(opt->detect_renames >= -1 &&\n-\t       opt->detect_renames <= DIFF_DETECT_COPY);\n-\tassert(opt->detect_directory_renames >= MERGE_DIRECTORY_RENAMES_NONE &&\n-\t       opt->detect_directory_renames <= MERGE_DIRECTORY_RENAMES_TRUE);\n-\tassert(opt->rename_limit >= -1);\n-\tassert(opt->rename_score >= 0 && opt->rename_score <= MAX_SCORE);\n-\tassert(opt->show_rename_progress >= 0 && opt->show_rename_progress <= 1);\n-\n-\tassert(opt->xdl_opts >= 0);\n-\tassert(opt->recursive_variant >= MERGE_VARIANT_NORMAL &&\n-\t       opt->recursive_variant <= MERGE_VARIANT_THEIRS);\n-\n-\tassert(opt->verbosity >= 0 && opt->verbosity <= 5);\n-\tassert(opt->buffer_output <= 2);\n-\tassert(opt->obuf.len == 0);\n-\n-\tassert(opt->priv == NULL);\n-\n-\t/* Not supported; option specific to merge-ort */\n-\tassert(!opt->record_conflict_msgs_as_headers);\n-\tassert(!opt->msg_header_prefix);\n-\n-\t/* Sanity check on repo state; index must match head */\n-\tif (repo_index_has_changes(opt->repo, head, &sb)) {\n-\t\terr(opt, _(\"Your local changes to the following files would be overwritten by merge:\\n  %s\"),\n-\t\t    sb.buf);\n-\t\tstrbuf_release(&sb);\n-\t\treturn -1;\n-\t}\n-\n-\tCALLOC_ARRAY(opt->priv, 1);\n-\tstring_list_init_dup(&opt->priv->df_conflict_file_set);\n-\treturn 0;\n-}\n-\n-static void merge_finalize(struct merge_options *opt)\n-{\n-\tflush_output(opt);\n-\tif (!opt->priv->call_depth && opt->buffer_output < 2)\n-\t\tstrbuf_release(&opt->obuf);\n-\tif (show(opt, 2))\n-\t\tdiff_warn_rename_limit(\"merge.renamelimit\",\n-\t\t\t\t       opt->priv->needed_rename_limit, 0);\n-\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t       struct path_hashmap_entry, e);\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 0);\n-\tFREE_AND_NULL(opt->priv);\n-}\n-\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base)\n-{\n-\tint clean;\n-\tstruct tree *ignored;\n-\n-\tassert(opt->ancestor != NULL);\n-\n-\tif (merge_start(opt, head))\n-\t\treturn -1;\n-\tclean = merge_trees_internal(opt, head, merge, merge_base, &ignored);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result)\n-{\n-\tint clean;\n-\n-\tassert(opt->ancestor == NULL ||\n-\t       !strcmp(opt->ancestor, \"constructed merge base\"));\n-\n-\tprepare_repo_settings(opt->repo);\n-\topt->repo->settings.command_requires_full_index = 1;\n-\n-\tif (merge_start(opt, repo_get_commit_tree(opt->repo, h1)))\n-\t\treturn -1;\n-\tclean = merge_recursive_internal(opt, h1, h2, merge_bases, result);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-static struct commit *get_ref(struct repository *repo,\n-\t\t\t      const struct object_id *oid,\n-\t\t\t      const char *name)\n-{\n-\tstruct object *object;\n-\n-\tobject = deref_tag(repo, parse_object(repo, oid),\n-\t\t\t   name, strlen(name));\n-\tif (!object)\n-\t\treturn NULL;\n-\tif (object->type == OBJ_TREE)\n-\t\treturn make_virtual_commit(repo, (struct tree*)object, name);\n-\tif (object->type != OBJ_COMMIT)\n-\t\treturn NULL;\n-\tif (repo_parse_commit(repo, (struct commit *)object))\n-\t\treturn NULL;\n-\treturn (struct commit *)object;\n-}\n-\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result)\n-{\n-\tint clean;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct commit *head_commit = get_ref(opt->repo, head, opt->branch1);\n-\tstruct commit *next_commit = get_ref(opt->repo, merge, opt->branch2);\n-\tstruct commit_list *ca = NULL;\n-\n-\tif (merge_bases) {\n-\t\tint i;\n-\t\tfor (i = 0; i < num_merge_bases; ++i) {\n-\t\t\tstruct commit *base;\n-\t\t\tif (!(base = get_ref(opt->repo, &merge_bases[i],\n-\t\t\t\t\t     oid_to_hex(&merge_bases[i]))))\n-\t\t\t\treturn err(opt, _(\"Could not parse object '%s'\"),\n-\t\t\t\t\t   oid_to_hex(&merge_bases[i]));\n-\t\t\tcommit_list_insert(base, &ca);\n-\t\t}\n-\t\tif (num_merge_bases == 1)\n-\t\t\topt->ancestor = \"constructed merge base\";\n-\t}\n-\n-\trepo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);\n-\tclean = merge_recursive(opt, head_commit, next_commit, ca,\n-\t\t\t\tresult);\n-\tfree_commit_list(ca);\n-\tif (clean < 0) {\n-\t\trollback_lock_file(&lock);\n-\t\treturn clean;\n-\t}\n-\n-\tif (write_locked_index(opt->repo->index, &lock,\n-\t\t\t       COMMIT_LOCK | SKIP_IF_UNCHANGED))\n-\t\treturn err(opt, _(\"Unable to write index.\"));\n-\n-\treturn clean ? 0 : 1;\n-}\n-\n-static void merge_recursive_config(struct merge_options *opt, int ui)\n-{\n-\tchar *value = NULL;\n-\tint renormalize = 0;\n-\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n-\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n-\topt->renormalize = renormalize;\n-\tif (!git_config_get_string(\"diff.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n-\t\tint boolval = git_parse_maybe_bool(value);\n-\t\tif (0 <= boolval) {\n-\t\t\topt->detect_directory_renames = boolval ?\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n-\t\t} else if (!strcasecmp(value, \"conflict\")) {\n-\t\t\topt->detect_directory_renames =\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n-\t\t} /* avoid erroring on values from future versions of git */\n-\t\tfree(value);\n-\t}\n-\tif (ui) {\n-\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n-\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n-\t\t\tif (diff_algorithm < 0)\n-\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n-\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n-\t\t\tfree(value);\n-\t\t}\n-\t}\n-\tgit_config(git_xmerge_config, NULL);\n-}\n-\n-static void init_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo, int ui)\n-{\n-\tconst char *merge_verbosity;\n-\tmemset(opt, 0, sizeof(struct merge_options));\n-\n-\topt->repo = repo;\n-\n-\topt->detect_renames = -1;\n-\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n-\topt->rename_limit = -1;\n-\n-\topt->verbosity = 2;\n-\topt->buffer_output = 1;\n-\tstrbuf_init(&opt->obuf, 0);\n-\n-\topt->renormalize = 0;\n-\n-\topt->conflict_style = -1;\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n-\tmerge_recursive_config(opt, ui);\n-\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-\tif (merge_verbosity)\n-\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n-\tif (opt->verbosity >= 5)\n-\t\topt->buffer_output = 0;\n-}\n-\n-void init_ui_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 1);\n-}\n-\n-void init_basic_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 0);\n-}\n-\n-/*\n- * For now, members of merge_options do not need deep copying, but\n- * it may change in the future, in which case we would need to update\n- * this, and also make a matching change to clear_merge_options() to\n- * release the resources held by a copied instance.\n- */\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n-{\n-\t*dst = *src;\n-}\n-\n-void clear_merge_options(struct merge_options *opt UNUSED)\n-{\n-\t; /* no-op as our copy is shallow right now */\n-}\n-\n-int parse_merge_opt(struct merge_options *opt, const char *s)\n-{\n-\tconst char *arg;\n-\n-\tif (!s || !*s)\n-\t\treturn -1;\n-\tif (!strcmp(s, \"ours\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n-\telse if (!strcmp(s, \"theirs\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n-\telse if (!strcmp(s, \"subtree\"))\n-\t\topt->subtree_shift = \"\";\n-\telse if (skip_prefix(s, \"subtree=\", &arg))\n-\t\topt->subtree_shift = arg;\n-\telse if (!strcmp(s, \"patience\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n-\telse if (!strcmp(s, \"histogram\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n-\t\tlong value = parse_algorithm_value(arg);\n-\t\tif (value < 0)\n-\t\t\treturn -1;\n-\t\t/* clear out previous settings */\n-\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n-\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n-\t\topt->xdl_opts |= value;\n-\t}\n-\telse if (!strcmp(s, \"ignore-space-change\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n-\telse if (!strcmp(s, \"ignore-all-space\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n-\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n-\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n-\telse if (!strcmp(s, \"renormalize\"))\n-\t\topt->renormalize = 1;\n-\telse if (!strcmp(s, \"no-renormalize\"))\n-\t\topt->renormalize = 0;\n-\telse if (!strcmp(s, \"no-renames\"))\n-\t\topt->detect_renames = 0;\n-\telse if (!strcmp(s, \"find-renames\")) {\n-\t\topt->detect_renames = 1;\n-\t\topt->rename_score = 0;\n-\t}\n-\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n-\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n-\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n-\t\t\treturn -1;\n-\t\topt->detect_renames = 1;\n-\t}\n-\t/*\n-\t * Please update $__git_merge_strategy_options in\n-\t * git-completion.bash when you add new options\n-\t */\n-\telse\n-\t\treturn -1;\n-\treturn 0;\n-}\ndiff --git a/merge-recursive.h b/merge-recursive.h\ndeleted file mode 100644\nindex 0b91f28f902..00000000000\n--- a/merge-recursive.h\n+++ /dev/null\n@@ -1,132 +0,0 @@\n-#ifndef MERGE_RECURSIVE_H\n-#define MERGE_RECURSIVE_H\n-\n-#include \"strbuf.h\"\n-\n-struct commit;\n-struct commit_list;\n-struct object_id;\n-struct repository;\n-struct tree;\n-\n-struct merge_options_internal;\n-struct merge_options {\n-\tstruct repository *repo;\n-\n-\t/* ref names used in console messages and conflict markers */\n-\tconst char *ancestor;\n-\tconst char *branch1;\n-\tconst char *branch2;\n-\n-\t/* rename related options */\n-\tint detect_renames;\n-\tenum {\n-\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n-\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n-\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n-\t} detect_directory_renames;\n-\tint rename_limit;\n-\tint rename_score;\n-\tint show_rename_progress;\n-\n-\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n-\tlong xdl_opts;\n-\tint conflict_style;\n-\tenum {\n-\t\tMERGE_VARIANT_NORMAL = 0,\n-\t\tMERGE_VARIANT_OURS,\n-\t\tMERGE_VARIANT_THEIRS\n-\t} recursive_variant;\n-\n-\t/* console output related options */\n-\tint verbosity;\n-\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n-\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n-\t\t\t\t * must handle and call strbuf_release */\n-\n-\t/* miscellaneous control options */\n-\tconst char *subtree_shift;\n-\tunsigned renormalize : 1;\n-\tunsigned record_conflict_msgs_as_headers : 1;\n-\tconst char *msg_header_prefix;\n-\n-\t/* internal fields used by the implementation */\n-\tstruct merge_options_internal *priv;\n-};\n-\n-/* for use by porcelain commands */\n-void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n-/* for use by plumbing commands */\n-void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n-\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n-void clear_merge_options(struct merge_options *opt);\n-\n-/* parse the option in s and update the relevant field of opt */\n-int parse_merge_opt(struct merge_options *opt, const char *s);\n-\n-/*\n- * RETURN VALUES: All the merge_* functions below return a value as follows:\n- *   > 0     Merge was clean\n- *   = 0     Merge had conflicts\n- *   < 0     Merge hit an unexpected and unrecoverable problem (e.g. disk\n- *             full) and aborted merge part-way through.\n- */\n-\n-/*\n- * rename-detecting three-way merge, no recursion.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base);\n-\n-/*\n- * merge_recursive is like merge_trees() but with recursive ancestor\n- * consolidation.\n- *\n- * NOTE: empirically, about a decade ago it was determined that with more\n- *       than two merge bases, optimal behavior was found when the\n- *       merge_bases were passed in the order of oldest commit to newest\n- *       commit.  Also, merge_bases will be consumed (emptied) so make a\n- *       copy if you need it.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result);\n-\n-/*\n- * merge_recursive_generic can operate on trees instead of commits, by\n- * wrapping the trees into virtual commits, and calling merge_recursive().\n- * It also writes out the in-memory index to disk if the merge is successful.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index also written to $GIT_INDEX_FILE on disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result);\n-\n-#endif\ndiff --git a/meson.build b/meson.build\nindex e98cfa4909f..8448df9d15e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -338,7 +338,6 @@ libgit_sources = [\n   'merge-ll.c',\n   'merge-ort.c',\n   'merge-ort-wrappers.c',\n-  'merge-recursive.c',\n   'merge.c',\n   'midx.c',\n   'midx-write.c',\n-- \ngitgitgadget\n\n"},{"id":"515384","messageId":"3abcfe6faf0759592d04d191c7cd4cdf93127965.1743436280.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH 8/8] builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-03-31T15:51:19Z","receivedAt":"2025-03-31T15:51:32Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThis environment variable existed to allow the testsuite to reuse all\nthe merge-related tests in the testsuite while easily flipping between\nthe 'recursive' and the 'ort' backends.  Now that we have removed\nmerge-recursive and remapped 'recursive' to mean 'ort', we don't need\nthis scaffolding anymore.  Remove it from these three builtins.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c  | 14 +-------------\n builtin/rebase.c |  5 -----\n builtin/revert.c |  2 --\n 3 files changed, 1 insertion(+), 20 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex c0bbdab7104..9efd585842f 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -170,7 +170,7 @@ static struct strategy *get_strategy(const char *name)\n \tstruct strategy *ret;\n \tstatic struct cmdnames main_cmds = {0}, other_cmds = {0};\n \tstatic int loaded;\n-\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n+\tchar *default_strategy = NULL;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -1311,12 +1311,6 @@ int cmd_merge(int argc,\n \tif (branch)\n \t\tskip_prefix(branch, \"refs/heads/\", &branch);\n \n-\tif (!pull_twohead) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy && !strcmp(default_strategy, \"ort\"))\n-\t\t\tpull_twohead = xstrdup(\"ort\");\n-\t}\n-\n \tinit_diff_ui_defaults();\n \tgit_config(git_merge_config, NULL);\n \n@@ -1517,12 +1511,6 @@ int cmd_merge(int argc,\n \t\t\tfast_forward = FF_NO;\n \t}\n \n-\tif (!use_strategies && !pull_twohead &&\n-\t    remoteheads && !remoteheads->next) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy)\n-\t\t\tappend_strategy(get_strategy(default_strategy));\n-\t}\n \tif (!use_strategies) {\n \t\tif (!remoteheads)\n \t\t\t; /* already up-to-date */\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex d4715ed35d7..e83193ac73e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1575,11 +1575,6 @@ int cmd_rebase(int argc,\n \t\t\t    options.default_backend);\n \t}\n \n-\tif (options.type == REBASE_MERGE &&\n-\t    !options.strategy &&\n-\t    getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\toptions.strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n-\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \t\toptions.state_dir = merge_dir();\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex aca6c293cdf..2654f769a88 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -252,8 +252,6 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,\n \t\tfree(opts->strategy);\n \t\topts->strategy = xstrdup_or_null(strategy);\n \t}\n-\tif (!opts->strategy && getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\topts->strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n \tfree(options);\n \n \tif (cmd == 'q') {\n-- \ngitgitgadget\n"},{"id":"515390","messageId":"CAPig+cSJ-3CXLV3dEhN+B8k7COQNW1Zm2ynuZtmmspzXsjp_PA@mail.gmail.com","threadId":"63226","inReplyTo":"0b6bcd225dc1444f4debe5fb8c499c6cad0a4ab2.1743436280.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 7/8] tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-31T17:34:09Z","receivedAt":"2025-03-31T17:34:21Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 31, 2025 at 11:55 AM Elijah Newren via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> Both of these existed to allow use to reuse all the merge-related tests\n\ns/use/us/\n\n> in the testsuite while easily flipping between the 'recursive' and the\n> 'ort' backends.  Now that we have removed merge-recursive and remapped\n> 'recursive' to mean 'ort', we don't need this scaffolding anymore.\n>\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n"},{"id":"515393","messageId":"CABPp-BEm-RH0N0bxtfp0yvaqbuiqFPBEQEuzWYov2Qv7+8X7qA@mail.gmail.com","threadId":"63226","inReplyTo":"CAPig+cSJ-3CXLV3dEhN+B8k7COQNW1Zm2ynuZtmmspzXsjp_PA@mail.gmail.com","subject":"Re: [PATCH 7/8] tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-03-31T18:14:43Z","receivedAt":"2025-03-31T18:14:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Mar 31, 2025 at 10:34 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Mon, Mar 31, 2025 at 11:55 AM Elijah Newren via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> > Both of these existed to allow use to reuse all the merge-related tests\n>\n> s/use/us/\n\nIndeed, thanks!\n\n> > in the testsuite while easily flipping between the 'recursive' and the\n> > 'ort' backends.  Now that we have removed merge-recursive and remapped\n> > 'recursive' to mean 'ort', we don't need this scaffolding anymore.\n> >\n> > Signed-off-by: Elijah Newren <newren@gmail.com>\n"},{"id":"515705","messageId":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.git.1743436279.gitgitgadget@gmail.com","subject":"[PATCH v2 0/8] Debug merge-recursive.[ch]","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:06Z","receivedAt":"2025-04-05T22:16:19Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Changes since v1:\n\n * fixed a couple of typos in commit messages\n\nOriginal cover letter:\n\nAs a wise man once told me, \"Deleted code is debugged code!\"\n\nThis series does some preparation, then moves the code shared between\nmerge-recursive and merge-ort from the former to the latter, and then debugs\nthe remainder of merge-recursive.[ch].\n\nSeries overview:\n\n * Patches 1-5: Preparation; switch remaining callers of\n   merge-recursive.[ch] functions to merge-ort equivalents, and add sole\n   remaining missing feature (diff-algorithm selection)\n * Patch 6: Nuke merge-recursive.[ch]\n * Patch 7-8: Cleanup testsuite; we don't need GIT_TEST_MERGE_ALGORITHM\n   anymore\n\nWhile the diffstat might look large, the non-test code changes are actually\npretty small. The drivers of the big diffstat are:\n\n * We move a significant chunk of shared code from merge-recursive.[ch] to\n   merge-ort.[ch], without modifying it\n * We delete (the remainder of) merge-recursive.[ch]\n * We rip out all the temporary GIT_TEST_MERGE_ALGORITHM stuff designed to\n   let us reuse tests between recursive and ort\n\nElijah Newren (8):\n  checkout: replace merge_trees() with merge_ort_nonrecursive()\n  builtin/merge-recursive: switch to using merge_ort_generic()\n  merge-ort: enable diff-algorithms other than histogram\n  sequencer: switch non-recursive merges over to ort\n  merge, sequencer: switch recursive merges over to ort\n  merge-recursive.[ch]: thoroughly debug these\n  tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n  builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM\n\n Documentation/merge-strategies.adoc           |   51 +-\n Documentation/technical/sparse-checkout.adoc  |    2 -\n Makefile                                      |    1 -\n builtin/checkout.c                            |   10 +-\n builtin/merge-recursive.c                     |    4 +-\n builtin/merge.c                               |   23 +-\n builtin/rebase.c                              |    5 -\n builtin/revert.c                              |    2 -\n ci/run-build-and-tests.sh                     |    1 -\n merge-ort-wrappers.h                          |    2 +-\n merge-ort.c                                   |  162 +-\n merge-ort.h                                   |   60 +-\n merge-recursive.c                             | 4079 -----------------\n merge-recursive.h                             |  132 -\n meson.build                                   |    1 -\n sequencer.c                                   |   58 +-\n t/lib-merge.sh                                |   13 -\n t/t1092-sparse-checkout-compatibility.sh      |    2 -\n t/t2501-cwd-empty.sh                          |    2 -\n t/t3512-cherry-pick-submodule.sh              |    5 -\n t/t3513-revert-submodule.sh                   |    4 -\n t/t4069-remerge-diff.sh                       |    7 -\n t/t4301-merge-tree-write-tree.sh              |    7 -\n t/t5572-pull-submodule.sh                     |    5 -\n t/t6400-merge-df.sh                           |   14 +-\n t/t6402-merge-rename.sh                       |  125 +-\n t/t6404-recursive-merge.sh                    |   21 +-\n t/t6406-merge-attr.sh                         |    7 +-\n t/t6416-recursive-corner-cases.sh             |  194 +-\n t/t6421-merge-partial-clone.sh                |    7 +-\n t/t6422-merge-rename-corner-cases.sh          |   31 +-\n t/t6423-merge-rename-directories.sh           |  517 +--\n t/t6424-merge-unrelated-index-changes.sh      |    8 +-\n t/t6426-merge-skip-unneeded-updates.sh        |    4 +-\n t/t6428-merge-conflicts-sparse.sh             |    2 -\n t/t6430-merge-recursive.sh                    |   46 +-\n t/t6434-merge-recursive-rename-options.sh     |   16 +-\n t/t6436-merge-overwrite.sh                    |   17 +-\n t/t6437-submodule-merge.sh                    |   65 +-\n t/t6438-submodule-directory-file-conflicts.sh |    5 -\n t/t6439-merge-co-error-msgs.sh                |    2 +-\n t/t7402-submodule-rebase.sh                   |    7 +-\n t/t7602-merge-octopus-many.sh                 |    9 +-\n t/t7610-mergetool.sh                          |   40 +-\n t/t7615-diff-algo-with-mergy-operations.sh    |    2 -\n t/test-lib.sh                                 |    2 -\n 46 files changed, 538 insertions(+), 5241 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n delete mode 100644 t/lib-merge.sh\n\n\nbase-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1898%2Fnewren%2Fendit-quote-debugging-unquote-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1898/newren/endit-quote-debugging-unquote-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1898\n\nRange-diff vs v1:\n\n 1:  0e150ee9065 = 1:  0e150ee9065 checkout: replace merge_trees() with merge_ort_nonrecursive()\n 2:  44be41da6c5 ! 2:  b093d74968b builtin/merge-recursive: switch to using merge_ort_generic()\n     @@ Commit message\n            adaptation from merge_recursive_internal(); see 8119214f4e70\n            (merge-ort: implement merge_incore_recursive(), 2020-12-16).\n      \n     -    * t6436: This test is built entirely around rename/delete conflicts,\n     +    * t6434: This test is built entirely around rename/delete conflicts,\n            which had a suboptimal handling under merge-recursive.  As explained\n            in more detail in commits 1f3c9ba707 (\"t6425: be more flexible with\n            rename/delete conflict messages\", 2020-08-10) and 727c75b23f (\"t6404,\n 3:  3945c471b0c = 3:  cf774437123 merge-ort: enable diff-algorithms other than histogram\n 4:  39ff4860fcd = 4:  6203589ac17 sequencer: switch non-recursive merges over to ort\n 5:  91398ffd1e1 = 5:  8821f22d5ea merge, sequencer: switch recursive merges over to ort\n 6:  6ef536cdbcd = 6:  770f611c2b6 merge-recursive.[ch]: thoroughly debug these\n 7:  0b6bcd225dc ! 7:  a6501ee85fa tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n     @@ Metadata\n       ## Commit message ##\n          tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n      \n     -    Both of these existed to allow use to reuse all the merge-related tests\n     +    Both of these existed to allow us to reuse all the merge-related tests\n          in the testsuite while easily flipping between the 'recursive' and the\n          'ort' backends.  Now that we have removed merge-recursive and remapped\n          'recursive' to mean 'ort', we don't need this scaffolding anymore.\n 8:  3abcfe6faf0 = 8:  d1dea986646 builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM\n\n-- \ngitgitgadget\n"},{"id":"515706","messageId":"0e150ee90659c89399bec614902077729cb2c917.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 1/8] checkout: replace merge_trees() with merge_ort_nonrecursive()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:07Z","receivedAt":"2025-04-05T22:16:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nReplace the use of merge_trees() from merge-recursive.[ch] with the\nmerge-ort equivalent.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/checkout.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 01ea9ff8b28..67879e72362 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -17,7 +17,7 @@\n #include \"merge-ll.h\"\n #include \"lockfile.h\"\n #include \"mem-pool.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n #include \"object-store-ll.h\"\n #include \"parse-options.h\"\n@@ -907,10 +907,10 @@ static int merge_working_tree(const struct checkout_opts *opts,\n \t\t\to.branch1 = new_branch_info->name;\n \t\t\to.branch2 = \"local\";\n \t\t\to.conflict_style = opts->conflict_style;\n-\t\t\tret = merge_trees(&o,\n-\t\t\t\t\t  new_tree,\n-\t\t\t\t\t  work,\n-\t\t\t\t\t  old_tree);\n+\t\t\tret = merge_ort_nonrecursive(&o,\n+\t\t\t\t\t\t     new_tree,\n+\t\t\t\t\t\t     work,\n+\t\t\t\t\t\t     old_tree);\n \t\t\tif (ret < 0)\n \t\t\t\texit(128);\n \t\t\tret = reset_tree(new_tree,\n-- \ngitgitgadget\n\n"},{"id":"515707","messageId":"b093d74968b146987fd7ea2373c3879d69fdf448.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 2/8] builtin/merge-recursive: switch to using merge_ort_generic()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:08Z","receivedAt":"2025-04-05T22:16:21Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nSwitch from merge-recursive to merge-ort.  Adjust the following\ntestcases due to the switch:\n\n* t6430: most of the test differences here were due to improved D/F\n  conflict handling explained in more detail in ef527787089c (merge\n  tests: expect improved directory/file conflict handling in ort,\n  2020-10-26).  These changes weren't made to this test back in that\n  commit simply because I had been looking at `git merge` rather than\n  `git merge-recursive`.  The final test in this testsuite, though, was\n  expunged because it was looking for specific output, and the calls to\n  output_commit_title() were discarded from merge_ort_internal() in its\n  adaptation from merge_recursive_internal(); see 8119214f4e70\n  (merge-ort: implement merge_incore_recursive(), 2020-12-16).\n\n* t6434: This test is built entirely around rename/delete conflicts,\n  which had a suboptimal handling under merge-recursive.  As explained\n  in more detail in commits 1f3c9ba707 (\"t6425: be more flexible with\n  rename/delete conflict messages\", 2020-08-10) and 727c75b23f (\"t6404,\n  t6423: expect improved rename/delete handling in ort backend\",\n  2020-10-26), rename/delete conflicts should each have two entries in\n  the index rather than just one.  Adjust the expectations for all the\n  tests in this testcase to see the two entries per rename/delete\n  conflict.\n\n* t6424: merge-recursive had a special check-if-toplevel-trees-match\n  check that it ran at the beginning on both the merge-base and the\n  other side being merged in.  In such a case, it exited early and\n  printed an \"Already up to date.\" message.  merge-ort got rid of\n  this, and instead checks the merge base tree matching the other\n  side throughout the tree instead of just at the toplevel, allowing\n  it to avoid recursing into various subtrees.  As part of that, it\n  got rid of the specialty toplevel message.  That message hasn't\n  been missed for years from `git merge`, so I don't think it is\n  necessary to keep it just for `git merge-recursive`, especially\n  since the latter is rarely used.  (git itself only references it\n  in the testsuite, whereas it used to power one of the three\n  rebase backends that existed once upon a time.)\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge-recursive.c                 |  4 +--\n t/t6424-merge-unrelated-index-changes.sh  |  4 ++-\n t/t6430-merge-recursive.sh                | 43 +++++------------------\n t/t6434-merge-recursive-rename-options.sh | 16 +++++----\n 4 files changed, 22 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c\nindex abfc060e28a..03b5100cfae 100644\n--- a/builtin/merge-recursive.c\n+++ b/builtin/merge-recursive.c\n@@ -3,7 +3,7 @@\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hash.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n \n static const char builtin_merge_recursive_usage[] =\n@@ -89,7 +89,7 @@ int cmd_merge_recursive(int argc,\n \tif (o.verbosity >= 3)\n \t\tprintf(_(\"Merging %s with %s\\n\"), o.branch1, o.branch2);\n \n-\tfailed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);\n+\tfailed = merge_ort_generic(&o, &h1, &h2, bases_count, bases, &result);\n \n \tfree(better1);\n \tfree(better2);\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 7677c5f08d0..084bfe7e6ce 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -176,9 +176,11 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' '\n \t# Make index match B\n \tgit diff C B -- | git apply --cached &&\n \ttest_when_finished \"git clean -fd\" &&  # Do not leave untracked around\n+\tgit write-tree >index-before &&\n \t# Merge B & F, with B as \"head\"\n \tgit merge-recursive A -- B F > out &&\n-\ttest_grep \"Already up to date\" out\n+\tgit write-tree >index-after &&\n+\ttest_cmp index-before index-after\n '\n \n test_expect_success 'recursive, when file has staged changes not matching HEAD nor what a merge would give' '\ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex ca15e6dd6da..c539a68fd07 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -373,9 +373,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 2\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 2\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -397,9 +397,9 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 3\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 3\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -424,9 +424,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 3\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 2\td/e\"\n+\t\techo \"100644 $o1 2\td/e\" &&\n+\t\techo \"100644 $o6 3\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -448,9 +448,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 2\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 3\td/e\"\n+\t\techo \"100644 $o1 3\td/e\" &&\n+\t\techo \"100644 $o6 2\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -696,33 +696,6 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n \tgit merge other\n '\n \n-test_expect_success 'merge-recursive remembers the names of all base trees' '\n-\tgit reset --hard HEAD &&\n-\n-\t# make the index match $c1 so that merge-recursive below does not\n-\t# fail early\n-\tgit diff --binary HEAD $c1 -- | git apply --cached &&\n-\n-\t# more trees than static slots used by oid_to_hex()\n-\tfor commit in $c0 $c2 $c4 $c5 $c6 $c7\n-\tdo\n-\t\tgit rev-parse \"$commit^{tree}\" || return 1\n-\tdone >trees &&\n-\n-\t# ignore the return code; it only fails because the input is weird...\n-\ttest_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&\n-\n-\t# ...but make sure it fails in the expected way\n-\ttest_grep CONFLICT.*rename/rename out &&\n-\n-\t# merge-recursive prints in reverse order, but we do not care\n-\tsort <trees >expect &&\n-\tsed -n \"s/^virtual //p\" out | sort >actual &&\n-\ttest_cmp expect actual &&\n-\n-\tgit clean -fd\n-'\n-\n test_expect_success 'merge-recursive internal merge resolves to the sameness' '\n \tgit reset --hard HEAD &&\n \ndiff --git a/t/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh\nindex 6e913c30a13..5a6f74839cb 100755\n--- a/t/t6434-merge-recursive-rename-options.sh\n+++ b/t/t6434-merge-recursive-rename-options.sh\n@@ -34,7 +34,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n get_expected_stages () {\n \tgit checkout rename -- $1-new &&\n \tgit ls-files --stage $1-new >expected-stages-undetected-$1 &&\n-\tsed \"s/ 0\t/ 2\t/\" <expected-stages-undetected-$1 \\\n+\tgit ls-tree HEAD^ $1-old >tmp &&\n+\tgit ls-tree HEAD  $1-new >>tmp &&\n+\tcat tmp | awk '{print $1 \" \" $3 \" \" NR \"\\t\" '$1'\"-new\"}' \\\n \t\t>expected-stages-detected-$1 &&\n \tgit read-tree -u --reset HEAD\n }\n@@ -51,11 +53,11 @@ rename_undetected () {\n \n check_common () {\n \tgit ls-files --stage >stages-actual &&\n-\ttest_line_count = 4 stages-actual\n+\ttest_line_count = $1 stages-actual\n }\n \n check_threshold_0 () {\n-\tcheck_common &&\n+\tcheck_common 8 &&\n \trename_detected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -63,7 +65,7 @@ check_threshold_0 () {\n }\n \n check_threshold_1 () {\n-\tcheck_common &&\n+\tcheck_common 7 &&\n \trename_undetected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -71,7 +73,7 @@ check_threshold_1 () {\n }\n \n check_threshold_2 () {\n-\tcheck_common &&\n+\tcheck_common 6 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_detected 2 &&\n@@ -79,7 +81,7 @@ check_threshold_2 () {\n }\n \n check_exact_renames () {\n-\tcheck_common &&\n+\tcheck_common 5 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n@@ -87,7 +89,7 @@ check_exact_renames () {\n }\n \n check_no_renames () {\n-\tcheck_common &&\n+\tcheck_common 4 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n-- \ngitgitgadget\n\n"},{"id":"515708","messageId":"cf774437123722d6065139573b49c3e09c6c135a.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 3/8] merge-ort: enable diff-algorithms other than histogram","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:09Z","receivedAt":"2025-04-05T22:16:22Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe ort merge strategy has always used the histogram diff algorithm.\nThe recursive merge strategy, in contrast, defaults to the myers\ndiff algorithm, while allowing it to be changed.\n\nChange the ort merge strategy to allow different diff algorithms, by\nremoving the hard coded value in merge_start() and instead just making\nit a default in init_merge_options().  Technically, this also changes\nthe default diff algorithm for the recursive backend too, but we're\ngoing to remove the final callers of the recursive backend in the next\ntwo commits.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc | 29 +++++++++++++++--------------\n merge-ort.c                         |  3 ---\n merge-recursive.c                   |  1 +\n 3 files changed, 16 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 59f5ae36ccb..8c87dd70210 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -87,6 +87,20 @@ no-renames;;\n \tconfiguration variable.\n \tSee also linkgit:git-diff[1] `--no-renames`.\n \n+histogram;;\n+\tDeprecated synonym for `diff-algorithm=histogram`.\n+\n+patience;;\n+\tDeprecated synonym for `diff-algorithm=patience`.\n+\n+diff-algorithm=[histogram|minimal|myers|patience];;\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`.  Note that `ort`\n+\tdefaults to `diff-algorithm=histogram`, while regular diffs\n+\tcurrently default to the `diff.algorithm` config setting.\n+\n subtree[=<path>];;\n \tThis option is a more advanced form of 'subtree' strategy, where\n \tthe strategy makes a guess on how two trees must be shifted to\n@@ -111,20 +125,7 @@ recursive::\n For a path that is a submodule, the same caution as 'ort' applies to this\n strategy.\n +\n-The 'recursive' strategy takes the same options as 'ort'.  However,\n-there are two additional options that 'ort' ignores (not documented\n-above) that are potentially useful with the 'recursive' strategy:\n-\n-patience;;\n-\tDeprecated synonym for `diff-algorithm=patience`.\n-\n-diff-algorithm=[patience|minimal|histogram|myers];;\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`.  Note that `ort`\n-\tspecifically uses `diff-algorithm=histogram`, while `recursive`\n-\tdefaults to the `diff.algorithm` config setting.\n+The 'recursive' strategy takes the same options as 'ort'.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 2b7d86aa4ec..14a7ae4a6bf 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -4957,9 +4957,6 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)\n \t}\n \ttrace2_region_leave(\"merge\", \"sanity checks\", opt->repo);\n \n-\t/* Default to histogram diff.  Actually, just hardcode it...for now. */\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n \t/* Handle attr direction stuff for renormalization */\n \tif (opt->renormalize)\n \t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 884ccf99a58..f3df127ad9b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -3981,6 +3981,7 @@ static void init_merge_options(struct merge_options *opt,\n \topt->renormalize = 0;\n \n \topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n \n \tmerge_recursive_config(opt, ui);\n \tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-- \ngitgitgadget\n\n"},{"id":"515709","messageId":"6203589ac17be5571a175e92326f688c118313db.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 4/8] sequencer: switch non-recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:10Z","receivedAt":"2025-04-05T22:16:23Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe do_recursive_merge() function, which is somewhat misleadingly named\nsince its purpose in life is to do a *non*-recursive merge, had code to\nallow either using the recursive or ort backends.  The default has been\nort for a very long time, let's just remove the code path for allowing\nthe recursive backend to be selected.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n sequencer.c | 35 +++++++++++++----------------------\n 1 file changed, 13 insertions(+), 22 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ad0ab75c8d4..b5d91fd3515 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -781,28 +781,19 @@ static int do_recursive_merge(struct repository *r,\n \tfor (i = 0; i < opts->xopts.nr; i++)\n \t\tparse_merge_opt(&o, opts->xopts.v[i]);\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\tmemset(&result, 0, sizeof(result));\n-\t\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,\n-\t\t\t\t\t    &result);\n-\t\tshow_output = !is_rebase_i(opts) || !result.clean;\n-\t\t/*\n-\t\t * TODO: merge_switch_to_result will update index/working tree;\n-\t\t * we only really want to do that if !result.clean || this is\n-\t\t * the final patch to be picked.  But determining this is the\n-\t\t * final patch would take some work, and \"head_tree\" would need\n-\t\t * to be replace with the tree the index matched before we\n-\t\t * started doing any picks.\n-\t\t */\n-\t\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n-\t\tclean = result.clean;\n-\t} else {\n-\t\tensure_full_index(r->index);\n-\t\tclean = merge_trees(&o, head_tree, next_tree, base_tree);\n-\t\tif (is_rebase_i(opts) && clean <= 0)\n-\t\t\tfputs(o.obuf.buf, stdout);\n-\t\tstrbuf_release(&o.obuf);\n-\t}\n+\tmemset(&result, 0, sizeof(result));\n+\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree, &result);\n+\tshow_output = !is_rebase_i(opts) || !result.clean;\n+\t/*\n+\t * TODO: merge_switch_to_result will update index/working tree;\n+\t * we only really want to do that if !result.clean || this is\n+\t * the final patch to be picked.  But determining this is the\n+\t * final patch would take some work, and \"head_tree\" would need\n+\t * to be replace with the tree the index matched before we\n+\t * started doing any picks.\n+\t */\n+\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n+\tclean = result.clean;\n \tif (clean < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn clean;\n-- \ngitgitgadget\n\n"},{"id":"515710","messageId":"8821f22d5eac351cbf05505668b1bdff9705a982.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 5/8] merge, sequencer: switch recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:11Z","receivedAt":"2025-04-05T22:16:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nMore precisely, replace calls to merge_recursive() with\nmerge_ort_recursive().\n\nAlso change t7615 to quit calling out recursive; it is not needed\nanymore, and we are in fact using ort now.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c                            |  9 ++-------\n sequencer.c                                | 23 ++++++++--------------\n t/t7615-diff-algo-with-mergy-operations.sh |  2 --\n 3 files changed, 10 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex ba9faf126aa..c0bbdab7104 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -39,7 +39,6 @@\n #include \"rerere.h\"\n #include \"help.h\"\n #include \"merge.h\"\n-#include \"merge-recursive.h\"\n #include \"merge-ort-wrappers.h\"\n #include \"resolve-undo.h\"\n #include \"remote.h\"\n@@ -750,12 +749,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \n \t\trepo_hold_locked_index(the_repository, &lock,\n \t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (!strcmp(strategy, \"ort\"))\n-\t\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\t    reversed, &result);\n-\t\telse\n-\t\t\tclean = merge_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\treversed, &result);\n+\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n+\t\t\t\t\t    reversed, &result);\n \t\tfree_commit_list(reversed);\n \t\tstrbuf_release(&o.obuf);\n \ndiff --git a/sequencer.c b/sequencer.c\nindex b5d91fd3515..8bb49735891 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4319,20 +4319,13 @@ static int do_merge(struct repository *r,\n \to.branch2 = ref_name.buf;\n \to.buffer_output = 2;\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\t/*\n-\t\t * TODO: Should use merge_incore_recursive() and\n-\t\t * merge_switch_to_result(), skipping the call to\n-\t\t * merge_switch_to_result() when we don't actually need to\n-\t\t * update the index and working copy immediately.\n-\t\t */\n-\t\tret = merge_ort_recursive(&o,\n-\t\t\t\t\t  head_commit, merge_commit, bases,\n-\t\t\t\t\t  &i);\n-\t} else {\n-\t\tret = merge_recursive(&o, head_commit, merge_commit, bases,\n-\t\t\t\t      &i);\n-\t}\n+\t/*\n+\t * TODO: Should use merge_incore_recursive() and\n+\t * merge_switch_to_result(), skipping the call to\n+\t * merge_switch_to_result() when we don't actually need to\n+\t * update the index and working copy immediately.\n+\t */\n+\tret = merge_ort_recursive(&o, head_commit, merge_commit, bases, &i);\n \tif (ret <= 0)\n \t\tfputs(o.obuf.buf, stdout);\n \tstrbuf_release(&o.obuf);\n@@ -4343,7 +4336,7 @@ static int do_merge(struct repository *r,\n \t\tgoto leave_merge;\n \t}\n \t/*\n-\t * The return value of merge_recursive() is 1 on clean, and 0 on\n+\t * The return value of merge_ort_recursive() is 1 on clean, and 0 on\n \t * unclean merge.\n \t *\n \t * Let's reverse that, so that do_merge() returns 0 upon success and\ndiff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh\nindex ac5863e788c..5822d02d517 100755\n--- a/t/t7615-diff-algo-with-mergy-operations.sh\n+++ b/t/t7615-diff-algo-with-mergy-operations.sh\n@@ -22,8 +22,6 @@ test_expect_success 'setup' '\n \tgit tag c2\n '\n \n-GIT_TEST_MERGE_ALGORITHM=recursive\n-\n test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '\n \tgit reset --hard c1 &&\n \ttest_must_fail git merge -s recursive -Xdiff-algorithm=myers c2\n-- \ngitgitgadget\n\n"},{"id":"515711","messageId":"d1dea986646eb826409e0b7cc33889e62456a815.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 8/8] builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:14Z","receivedAt":"2025-04-05T22:16:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThis environment variable existed to allow the testsuite to reuse all\nthe merge-related tests in the testsuite while easily flipping between\nthe 'recursive' and the 'ort' backends.  Now that we have removed\nmerge-recursive and remapped 'recursive' to mean 'ort', we don't need\nthis scaffolding anymore.  Remove it from these three builtins.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c  | 14 +-------------\n builtin/rebase.c |  5 -----\n builtin/revert.c |  2 --\n 3 files changed, 1 insertion(+), 20 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex c0bbdab7104..9efd585842f 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -170,7 +170,7 @@ static struct strategy *get_strategy(const char *name)\n \tstruct strategy *ret;\n \tstatic struct cmdnames main_cmds = {0}, other_cmds = {0};\n \tstatic int loaded;\n-\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n+\tchar *default_strategy = NULL;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -1311,12 +1311,6 @@ int cmd_merge(int argc,\n \tif (branch)\n \t\tskip_prefix(branch, \"refs/heads/\", &branch);\n \n-\tif (!pull_twohead) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy && !strcmp(default_strategy, \"ort\"))\n-\t\t\tpull_twohead = xstrdup(\"ort\");\n-\t}\n-\n \tinit_diff_ui_defaults();\n \tgit_config(git_merge_config, NULL);\n \n@@ -1517,12 +1511,6 @@ int cmd_merge(int argc,\n \t\t\tfast_forward = FF_NO;\n \t}\n \n-\tif (!use_strategies && !pull_twohead &&\n-\t    remoteheads && !remoteheads->next) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy)\n-\t\t\tappend_strategy(get_strategy(default_strategy));\n-\t}\n \tif (!use_strategies) {\n \t\tif (!remoteheads)\n \t\t\t; /* already up-to-date */\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex d4715ed35d7..e83193ac73e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1575,11 +1575,6 @@ int cmd_rebase(int argc,\n \t\t\t    options.default_backend);\n \t}\n \n-\tif (options.type == REBASE_MERGE &&\n-\t    !options.strategy &&\n-\t    getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\toptions.strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n-\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \t\toptions.state_dir = merge_dir();\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex aca6c293cdf..2654f769a88 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -252,8 +252,6 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,\n \t\tfree(opts->strategy);\n \t\topts->strategy = xstrdup_or_null(strategy);\n \t}\n-\tif (!opts->strategy && getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\topts->strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n \tfree(options);\n \n \tif (cmd == 'q') {\n-- \ngitgitgadget\n"},{"id":"515712","messageId":"a6501ee85fa219fd214247b8122bce85cd6f86b1.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 7/8] tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:13Z","receivedAt":"2025-04-05T22:16:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nBoth of these existed to allow us to reuse all the merge-related tests\nin the testsuite while easily flipping between the 'recursive' and the\n'ort' backends.  Now that we have removed merge-recursive and remapped\n'recursive' to mean 'ort', we don't need this scaffolding anymore.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n ci/run-build-and-tests.sh                     |   1 -\n t/lib-merge.sh                                |  13 -\n t/t1092-sparse-checkout-compatibility.sh      |   2 -\n t/t2501-cwd-empty.sh                          |   2 -\n t/t3512-cherry-pick-submodule.sh              |   5 -\n t/t3513-revert-submodule.sh                   |   4 -\n t/t4069-remerge-diff.sh                       |   7 -\n t/t4301-merge-tree-write-tree.sh              |   7 -\n t/t5572-pull-submodule.sh                     |   5 -\n t/t6400-merge-df.sh                           |  14 +-\n t/t6402-merge-rename.sh                       | 125 +----\n t/t6404-recursive-merge.sh                    |  21 +-\n t/t6406-merge-attr.sh                         |   7 +-\n t/t6416-recursive-corner-cases.sh             | 194 ++-----\n t/t6421-merge-partial-clone.sh                |   7 +-\n t/t6422-merge-rename-corner-cases.sh          |  31 +-\n t/t6423-merge-rename-directories.sh           | 517 ++++--------------\n t/t6424-merge-unrelated-index-changes.sh      |   4 +-\n t/t6426-merge-skip-unneeded-updates.sh        |   4 +-\n t/t6428-merge-conflicts-sparse.sh             |   2 -\n t/t6430-merge-recursive.sh                    |   3 +-\n t/t6436-merge-overwrite.sh                    |  17 +-\n t/t6437-submodule-merge.sh                    |  65 +--\n t/t6438-submodule-directory-file-conflicts.sh |   5 -\n t/t6439-merge-co-error-msgs.sh                |   2 +-\n t/t7402-submodule-rebase.sh                   |   7 +-\n t/t7602-merge-octopus-many.sh                 |   9 +-\n t/t7610-mergetool.sh                          |  40 +-\n t/test-lib.sh                                 |   2 -\n 29 files changed, 248 insertions(+), 874 deletions(-)\n delete mode 100644 t/lib-merge.sh\n\ndiff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\nindex 1c698467235..f99b7db2ee8 100755\n--- a/ci/run-build-and-tests.sh\n+++ b/ci/run-build-and-tests.sh\n@@ -20,7 +20,6 @@ linux-breaking-changes)\n linux-TEST-vars)\n \texport OPENSSL_SHA1_UNSAFE=YesPlease\n \texport GIT_TEST_SPLIT_INDEX=yes\n-\texport GIT_TEST_MERGE_ALGORITHM=recursive\n \texport GIT_TEST_FULL_IN_PACK_ARRAY=true\n \texport GIT_TEST_OE_SIZE=10\n \texport GIT_TEST_OE_DELTA_SIZE=5\ndiff --git a/t/lib-merge.sh b/t/lib-merge.sh\ndeleted file mode 100644\nindex 8734ebfc17f..00000000000\n--- a/t/lib-merge.sh\n+++ /dev/null\n@@ -1,13 +0,0 @@\n-# Helper functions used by merge tests.\n-\n-test_expect_merge_algorithm () {\n-\tstatus_for_recursive=$1 status_for_ort=$2\n-\tshift 2\n-\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_expect_${status_for_ort} \"$@\"\n-\telse\n-\t\ttest_expect_${status_for_recursive} \"$@\"\n-\tfi\n-}\ndiff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh\nindex a4c7c41fc00..f9b448792cb 100755\n--- a/t/t1092-sparse-checkout-compatibility.sh\n+++ b/t/t1092-sparse-checkout-compatibility.sh\n@@ -1486,7 +1486,6 @@ test_expect_success 'sparse-index is not expanded' '\n \tensure_not_expanded checkout -f update-deep &&\n \ttest_config -C sparse-index pull.twohead ort &&\n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tfor OPERATION in \"merge -m merge\" cherry-pick rebase\n \t\tdo\n \t\t\tensure_not_expanded merge -m merge update-folder1 &&\n@@ -1506,7 +1505,6 @@ test_expect_success 'sparse-index is not expanded: merge conflict in cone' '\n \tdone &&\n \n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tgit -C sparse-index config pull.twohead ort &&\n \t\tensure_not_expanded ! merge -m merged expand-right\n \t)\ndiff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh\nindex f6d8d7d03d7..be9140bbaa4 100755\n--- a/t/t2501-cwd-empty.sh\n+++ b/t/t2501-cwd-empty.sh\n@@ -117,8 +117,6 @@ test_expect_success 'merge fails if cwd needs to be removed; recursive friendly'\n \tgrep \"Refusing to remove the current working directory\" error\n '\n \n-GIT_TEST_MERGE_ALGORITHM=ort\n-\n test_expect_success 'merge fails if cwd needs to be removed' '\n \ttest_required_dir_removal git merge fd_conflict\n '\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex f22d1ddead1..85a79326977 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -8,11 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 8bfe3ed2467..32e15c72eee 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -30,10 +30,6 @@ git_revert () {\n \tgit revert HEAD\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-fi\n test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh\nindex c6c94aef14d..966882ce912 100755\n--- a/t/t4069-remerge-diff.sh\n+++ b/t/t4069-remerge-diff.sh\n@@ -4,13 +4,6 @@ test_description='remerge-diff handling'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"${GIT_TEST_MERGE_ALGORITHM}\" != ort\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success 'setup basic merges' '\n \ttest_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&\n \tgit add numbers &&\ndiff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh\nindex 44f7d077593..f9c5883a7f7 100755\n--- a/t/t4301-merge-tree-write-tree.sh\n+++ b/t/t4301-merge-tree-write-tree.sh\n@@ -4,13 +4,6 @@ test_description='git merge-tree --write-tree'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != \"ort\"\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \ttest_write_lines 1 2 3 4 5 >numbers &&\n \techo hello >greeting &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f7650e8475e..45f384dd328 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -45,11 +45,6 @@ git_pull_noff () {\n \t$2 git pull --no-ff\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'setup' '\ndiff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh\nindex 3de4ef6bd9e..b46fe494409 100755\n--- a/t/t6400-merge-df.sh\n+++ b/t/t6400-merge-df.sh\n@@ -84,12 +84,7 @@ test_expect_success 'modify/delete + directory/file conflict' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\n@@ -105,12 +100,7 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\ndiff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh\nindex 2738b50c2a9..ff00b74e9c1 100755\n--- a/t/t6402-merge-rename.sh\n+++ b/t/t6402-merge-rename.sh\n@@ -313,12 +313,7 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '\n \n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~HEAD instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~HEAD instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~HEAD instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -340,12 +335,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \t! grep \"error: refusing to lose untracked file at\" errors &&\n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~renamed-file-has-no-conflicts instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -400,14 +390,7 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t\n \ttest_must_fail git merge --strategy=recursive dir-in-way &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -425,14 +408,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \ttest_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -488,12 +464,7 @@ test_expect_success 'both rename source and destination involved in D/F conflict\n \tgit checkout -q rename-dest^0 &&\n \ttest_must_fail git merge --strategy=recursive source-conflict &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 2 git ls-files -u\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -u\n-\tfi &&\n+\ttest_stdout_line_count = 2 git ls-files -u &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -527,63 +498,33 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '\n \tgit commit -m \"Rename one/file -> two\"\n '\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-then\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n-\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two &&\n-\n-\t\ttest_must_fail git diff --quiet &&\n-\n-\t\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n-\n-\t\ttest_path_is_file one &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-else\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n+test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n+\tgit checkout -q rename-one^0 &&\n+\tmkdir one &&\n+\ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n-\t\ttest_must_fail git diff --quiet &&\n+\ttest_must_fail git diff --quiet &&\n \n-\t\ttest 4 -eq $(find . | grep -v .git | wc -l) &&\n+\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n \n-\t\ttest_path_is_dir one &&\n-\t\ttest_path_is_file one~rename-two &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one~rename-two) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-fi\n+\ttest_path_is_file one &&\n+\ttest_path_is_file two &&\n+\ttest \"other\" = $(cat one) &&\n+\ttest \"stuff\" = $(cat two)\n+'\n \n test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '\n \tgit reset --hard &&\n \tgit clean -fdqx &&\n \ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two\n-\telse\n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two\n-\tfi &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -623,22 +564,12 @@ test_expect_success 'check handling of differently renamed file with D/F conflic\n \tgit checkout -q first-rename^0 &&\n \ttest_must_fail git merge --strategy=recursive second-rename &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 2 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 5 git ls-files -s &&\n+\ttest_stdout_line_count = 3 git ls-files -u &&\n+\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n+\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n+\ttest_stdout_line_count = 1 git ls-files -u original &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file one/file &&\n \ttest_path_is_file two/file &&\ndiff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh\nindex ae687f2ce54..346f3608b98 100755\n--- a/t/t6404-recursive-merge.sh\n+++ b/t/t6404-recursive-merge.sh\n@@ -108,12 +108,7 @@ test_expect_success 'refuse to merge binary files' '\n \tprintf \"\\0\\0\" >binary-file &&\n \tgit add binary-file &&\n \tgit commit -m binary2 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge F >merge_output\n-\telse\n-\t\ttest_must_fail git merge F 2>merge_output\n-\tfi &&\n+\ttest_must_fail git merge F >merge_output &&\n \tgrep \"Cannot merge binary files: binary-file (HEAD vs. F)\" merge_output\n '\n \n@@ -129,22 +124,12 @@ test_expect_success 'mark rename/delete as unmerged' '\n \ttest_tick &&\n \tgit commit -m rename &&\n \ttest_must_fail git merge delete &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \tgit rev-parse --verify :2:a2 &&\n \ttest_must_fail git rev-parse --verify :3:a2 &&\n \tgit checkout -f delete &&\n \ttest_must_fail git merge rename &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \ttest_must_fail git rev-parse --verify :2:a2 &&\n \tgit rev-parse --verify :3:a2\n '\ndiff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh\nindex 66e01464b5e..8f6fbef0024 100755\n--- a/t/t6406-merge-attr.sh\n+++ b/t/t6406-merge-attr.sh\n@@ -259,12 +259,7 @@ test_expect_success 'binary files with union attribute' '\n \tprintf \"two\\0\" >bin.txt &&\n \tgit commit -am two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge bin-main >output\n-\telse\n-\t\ttest_must_fail git merge bin-main 2>output\n-\tfi &&\n+\ttest_must_fail git merge bin-main >output &&\n \tgrep -i \"warning.*cannot merge.*HEAD vs. bin-main\" output\n '\n \ndiff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh\nindex 17b54d625d0..ed20de8ea22 100755\n--- a/t/t6416-recursive-corner-cases.sh\n+++ b/t/t6416-recursive-corner-cases.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n #  L1  L2\n@@ -529,15 +528,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git merge C^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~HEAD\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~HEAD &&\n \t\tgit cat-file -p B:a >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m D2 &&\n@@ -556,12 +548,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd\n-\t\tfi &&\n+\t\tgit rm a~B^0 &&\n \t\tgit rm -rf a/ &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a &&\n \t\tgit add a &&\n@@ -570,15 +557,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~B^0 &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m E4 &&\n@@ -596,34 +576,16 @@ test_expect_success 'merge of D1 & E1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    A:ignore-me  B:a D1:a &&\n+\t\tgit rev-parse >actual   :0:ignore-me :1:a :2:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -637,34 +599,18 @@ test_expect_success 'merge of E1 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tA:ignore-me  B:a  D1:a &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:0:ignore-me :1:a :3:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -678,32 +624,17 @@ test_expect_success 'merge of D1 & E2 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E2^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a    E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:2:a   :3:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~HEAD\n@@ -720,32 +651,17 @@ test_expect_success 'merge of E2 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a   E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:3:a  :2:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~D1^0\n@@ -777,7 +693,7 @@ test_expect_success 'merge of D1 & E3 succeeds' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n+test_expect_success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n \ttest_when_finished \"git -C directory-file reset --hard\" &&\n \ttest_when_finished \"git -C directory-file clean -fdqx\" &&\n \t(\n@@ -1140,7 +1056,7 @@ test_expect_success 'setup symlink modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink modify/modify' '\n+test_expect_success 'check symlink modify/modify' '\n \t(\n \t\tcd symlink-modify-modify &&\n \n@@ -1206,7 +1122,7 @@ test_expect_success 'setup symlink add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink add/add' '\n+test_expect_success 'check symlink add/add' '\n \t(\n \t\tcd symlink-add-add &&\n \n@@ -1294,7 +1210,7 @@ test_expect_success 'setup submodule modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule modify/modify' '\n+test_expect_success 'check submodule modify/modify' '\n \t(\n \t\tcd submodule-modify-modify &&\n \n@@ -1382,7 +1298,7 @@ test_expect_success 'setup submodule add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule add/add' '\n+test_expect_success 'check submodule add/add' '\n \t(\n \t\tcd submodule-add-add &&\n \n@@ -1457,7 +1373,7 @@ test_expect_success 'setup conflicting entry types (submodule vs symlink)' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check conflicting entry types (submodule vs symlink)' '\n+test_expect_success 'check conflicting entry types (submodule vs symlink)' '\n \t(\n \t\tcd submodule-symlink-add-add &&\n \ndiff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh\nindex b99f29ef9ba..6eb51285a0c 100755\n--- a/t/t6421-merge-partial-clone.sh\n+++ b/t/t6421-merge-partial-clone.sh\n@@ -27,7 +27,6 @@ test_description=\"limiting blob downloads when merging with partial clones\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_repo () {\n \ttest -d server && return\n@@ -207,7 +206,7 @@ test_setup_repo () {\n #\n #   Summary: 2 fetches (1 for 2 objects, 1 for 1 object)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded for single relevant rename' '\n+test_expect_success 'Objects downloaded for single relevant rename' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-single &&\n \t(\n@@ -297,7 +296,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded for single relev\n #      this are not all that common.)\n #   Summary: 1 fetches for 6 objects\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded when a directory rename triggered' '\n+test_expect_success 'Objects downloaded when a directory rename triggered' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-dir &&\n \t(\n@@ -399,7 +398,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory\n #\n #   Summary: 4 fetches (1 for 6 objects, 1 for 8, 1 for 3, 1 for 2)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded with lots of renames and modifications' '\n+test_expect_success 'Objects downloaded with lots of renames and modifications' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-many &&\n \t(\ndiff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh\nindex 62b49c67e22..9cbe7ca7824 100755\n--- a/t/t6422-merge-rename-corner-cases.sh\n+++ b/t/t6422-merge-rename-corner-cases.sh\n@@ -7,7 +7,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_rename_delete_untracked () {\n \tgit init rename-delete-untracked &&\n@@ -316,12 +315,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\techo 0 >expect &&\n \t\tgit cat-file -p base:file >>expect &&\n@@ -350,12 +344,7 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 3 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\tgit cat-file -p left-conflict:newfile >left &&\n \t\tgit cat-file -p base:file    >base &&\n@@ -369,14 +358,8 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \n \t\tgit rev-parse >expect   \\\n \t\t\tbase:file       left-conflict:newfile right:file &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD\n-\t\telse\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile      :2:newfile      :3:newfile\n-\t\tfi &&\n+\t\tgit rev-parse >actual \\\n+\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file newfile/realfile &&\n@@ -896,7 +879,7 @@ test_setup_rad () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rad-check: rename/add/delete conflict' '\n+test_expect_success 'rad-check: rename/add/delete conflict' '\n \ttest_setup_rad &&\n \t(\n \t\tcd rad &&\n@@ -969,7 +952,7 @@ test_setup_rrdd () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n+test_expect_success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n \ttest_setup_rrdd &&\n \t(\n \t\tcd rrdd &&\n@@ -1058,7 +1041,7 @@ test_setup_mod6 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n+test_expect_success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n \ttest_setup_mod6 &&\n \t(\n \t\tcd mod6 &&\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex e0785410cd9..f48ed6d0353 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -26,8 +26,6 @@ test_description=\"recursive merge with directory renames\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Basic cases we should be able to handle\n@@ -302,20 +300,11 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'\n \t\tgit cat-file -p :2:x/wham >expect &&\n \t\tgit cat-file -p :3:x/wham >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/wham\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/wham\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/wham\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/wham\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect x/wham\n \t)\n '\n@@ -1186,18 +1175,10 @@ test_expect_success '5d: Directory/file/file conflict due to directory rename' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e\n-\t\telse\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d      :0:y/d/e\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e &&\n \t\tgit rev-parse >expect \\\n \t\t\t O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&\n \t\ttest_cmp expect actual &&\n@@ -1280,32 +1261,17 @@ test_expect_success '6a: Tricky rename/delete' '\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*z/c.*y/c\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :1:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:z/c\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :1:y/c :3:y/c &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:z/c &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -1372,7 +1338,7 @@ test_setup_6b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b1: Same renames done on both sides, plus another rename' '\n+test_expect_success '6b1: Same renames done on both sides, plus another rename' '\n \ttest_setup_6b1 &&\n \t(\n \t\tcd 6b1 &&\n@@ -1445,7 +1411,7 @@ test_setup_6b2 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b2: Same rename done on both sides' '\n+test_expect_success '6b2: Same rename done on both sides' '\n \ttest_setup_6b2 &&\n \t(\n \t\tcd 6b2 &&\n@@ -1832,20 +1798,11 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'\n \t\tgit cat-file -p :2:y/d >expect &&\n \t\tgit cat-file -p :3:y/d >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/d\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/d\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/d\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/d\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect y/d\n \t)\n '\n@@ -1967,32 +1924,17 @@ test_expect_success '7d: transitive rename involved in rename/delete; how is it\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d  O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:x/d  O:x/d &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -2073,32 +2015,17 @@ test_expect_success '7e: transitive rename in rename/delete AND dirs in the way'\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d &&\n \t\ttest_cmp expect actual &&\n \n \t\tgit hash-object y/d~B^0 >actual &&\n@@ -3284,34 +3211,15 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '\n \t\techo contents >y/e &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/delete).*Version B\\^0 of y/d left in tree at y/d~B\\^0\" out &&\n-\t\t\ttest_grep \"Error: Refusing to lose untracked file at y/e; writing to y/e~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/d :3:y/e &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\tO:z/b  O:z/c  B:z/e &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 1 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 5 out &&\n \n \t\techo very >expect &&\n \t\ttest_cmp expect y/c &&\n@@ -3374,38 +3282,15 @@ test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~B^0 >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3425,38 +3310,15 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~HEAD instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3514,47 +3376,15 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '\n \t\techo important >y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/wham\n@@ -3596,7 +3426,7 @@ test_setup_10e () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '10e: Does git complain about untracked file that is not really in the way?' '\n+test_expect_success '10e: Does git complain about untracked file that is not really in the way?' '\n \ttest_setup_10e &&\n \t(\n \t\tcd 10e &&\n@@ -3687,30 +3517,8 @@ test_expect_success '11a: Avoid losing dirty contents with simple rename' '\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:z/a :2:z/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  B:z/b &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object z/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:z/b >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo stuff >>expected &&\n@@ -3766,34 +3574,9 @@ test_expect_success '11b: Avoid losing dirty file involved in directory rename'\n \t\tgit checkout A^0 &&\n \t\techo stuff >>z/c &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\tgit -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -m >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3850,13 +3633,8 @@ test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"following files would be overwritten by merge\" err\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff y/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3924,30 +3702,8 @@ test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c/d :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:y/c/d  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -4010,39 +3766,8 @@ test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to\n \t\techo mods >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 7 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# See if y/c~merged has expected contents; requires manually\n-\t\t\t# doing the expected file merge\n-\t\t\tgit cat-file -p A:y/c >c1 &&\n-\t\t\tgit cat-file -p B:z/c >c2 &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\tc1 empty c2 &&\n-\t\t\ttest_cmp c1 y/c~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\techo different >expected &&\n \t\techo mods >>expected &&\n@@ -4099,40 +3824,8 @@ test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to\n \t\techo important >>y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/c     O:x/d &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo important >>expected &&\n@@ -4267,7 +3960,7 @@ test_setup_12b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12b1: Moving two directory hierarchies into each other' '\n+test_expect_success '12b1: Moving two directory hierarchies into each other' '\n \ttest_setup_12b1 &&\n \t(\n \t\tcd 12b1 &&\n@@ -4435,7 +4128,7 @@ test_setup_12c1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12c1: Moving one directory hierarchy into another w/ content merge' '\n+test_expect_success '12c1: Moving one directory hierarchy into another w/ content merge' '\n \ttest_setup_12c1 &&\n \t(\n \t\tcd 12c1 &&\n@@ -4797,7 +4490,7 @@ test_setup_12f () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '\n+test_expect_success '12f: Trivial directory resolve, caching, all kinds of fun' '\n \ttest_setup_12f &&\n \t(\n \t\tcd 12f &&\n@@ -5253,7 +4946,7 @@ test_setup_12l () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12l (B into A): Rename into each other + add/add conflict' '\n+test_expect_success '12l (B into A): Rename into each other + add/add conflict' '\n \ttest_setup_12l BintoA &&\n \t(\n \t\tcd 12l_BintoA &&\n@@ -5280,7 +4973,7 @@ test_expect_merge_algorithm failure success '12l (B into A): Rename into each ot\n \t)\n '\n \n-test_expect_merge_algorithm failure success '12l (A into B): Rename into each other + add/add conflict' '\n+test_expect_success '12l (A into B): Rename into each other + add/add conflict' '\n \ttest_setup_12l AintoB &&\n \t(\n \t\tcd 12l_AintoB &&\n@@ -5348,7 +5041,7 @@ test_setup_12m () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 084bfe7e6ce..ddc7524f6c1 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -296,10 +296,8 @@ test_expect_success 'with multiple strategies, recursive or ort failure do not e\n \tgit add a &&\n \tgit rev-parse :a >expect &&\n \n-\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n-\ttest_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&\n+\ttest_must_fail git merge -s ort -s octopus C^0 >output 2>&1 &&\n \n-\tgrep \"Trying merge strategy recursive...\" output &&\n \tgrep \"Trying merge strategy ort...\" output &&\n \tgrep \"Trying merge strategy octopus...\" output &&\n \tgrep \"No merge strategy handled the merge.\" output &&\ndiff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh\nindex b059475ed03..404cd3f2ca1 100755\n--- a/t/t6426-merge-skip-unneeded-updates.sh\n+++ b/t/t6426-merge-skip-unneeded-updates.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Cases involving no renames (one side has subset of changes of\n@@ -663,7 +661,7 @@ test_setup_4a () {\n #   correct requires doing the merge in-memory first, then realizing that no\n #   updates to the file are necessary, and thus that we can just leave the path\n #   alone.\n-test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '\n+test_expect_success '4a: Change on A, change on B subset of A, dirty mods present' '\n \ttest_setup_4a &&\n \t(\n \t\tcd 4a &&\ndiff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh\nindex 9919c3fa7cd..c86e02c6e23 100755\n--- a/t/t6428-merge-conflicts-sparse.sh\n+++ b/t/t6428-merge-conflicts-sparse.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n # Testcase basic, conflicting changes in 'numerals'\n \ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex c539a68fd07..e59560a5dd9 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_expect_success 'setup 1' '\n \n@@ -645,7 +644,7 @@ test_expect_success 'merge-recursive copy vs. rename' '\n \ttest_cmp expected actual\n '\n \n-test_expect_merge_algorithm failure success 'merge-recursive rename vs. rename/symlink' '\n+test_expect_success 'merge-recursive rename vs. rename/symlink' '\n \n \tgit checkout -f rename &&\n \tgit merge rename-ln &&\ndiff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh\nindex 4f4376421e7..70b5d2d6944 100755\n--- a/t/t6436-merge-overwrite.sh\n+++ b/t/t6436-merge-overwrite.sh\n@@ -101,19 +101,10 @@ test_expect_success 'will not overwrite unstaged changes in renamed file' '\n \tgit mv c1.c other.c &&\n \tgit commit -m rename &&\n \tcp important other.c &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge c1a >out 2>err &&\n-\t\ttest_grep \"would be overwritten by merge\" err &&\n-\t\ttest_cmp important other.c &&\n-\t\ttest_path_is_missing .git/MERGE_HEAD\n-\telse\n-\t\ttest_must_fail git merge c1a >out &&\n-\t\ttest_grep \"Refusing to lose dirty file at other.c\" out &&\n-\t\ttest_path_is_file other.c~HEAD &&\n-\t\ttest $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&\n-\t\ttest_cmp important other.c\n-\tfi\n+\ttest_must_fail git merge c1a >out 2>err &&\n+\ttest_grep \"would be overwritten by merge\" err &&\n+\ttest_cmp important other.c &&\n+\ttest_path_is_missing .git/MERGE_HEAD\n '\n \n test_expect_success 'will not overwrite untracked subtree' '\ndiff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\nindex 4815559157b..a564758f528 100755\n--- a/t/t6437-submodule-merge.sh\n+++ b/t/t6437-submodule-merge.sh\n@@ -9,7 +9,6 @@ GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1\n export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n # history\n@@ -110,14 +109,10 @@ test_expect_success 'merging should conflict for non fast-forward' '\n \ttest_when_finished \"git -C merge-search reset --hard\" &&\n \t(cd merge-search &&\n \t git checkout -b test-nonforward-a b &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c 2>actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi)\n+\t test_must_fail git merge c 2>actual &&\n+\t sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t grep \"$sub_expect\" actual\n+\t )\n '\n \n test_expect_success 'finish setup for merge-search' '\n@@ -151,14 +146,9 @@ test_expect_success 'merging should conflict for non fast-forward (resolution ex\n \t git checkout -b test-nonforward-b b &&\n \t (cd sub &&\n \t  git rev-parse --short sub-d > ../expect) &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi &&\n+\t  test_must_fail git merge c >actual 2>sub-actual &&\n+\t  sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t  grep \"$sub_expect\" sub-actual &&\n \t grep $(cat expect) actual > /dev/null &&\n \t git reset --hard)\n '\n@@ -169,23 +159,12 @@ test_expect_success 'merging should fail for ambiguous common parent' '\n \t(cd sub &&\n \t git checkout -b ambiguous sub-b &&\n \t git merge sub-c &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\tgit rev-parse --short sub-d >../expect1 &&\n-\t\tgit rev-parse --short ambiguous >../expect2\n-\t else\n-\t\tgit rev-parse sub-d > ../expect1 &&\n-\t\tgit rev-parse ambiguous > ../expect2\n-\t fi\n+\t git rev-parse --short sub-d >../expect1 &&\n+\t git rev-parse --short ambiguous >../expect2\n \t ) &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t else\n-\t\ttest_must_fail git merge c 2> actual\n-\t fi &&\n+\ttest_must_fail git merge c >actual 2>sub-actual &&\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\tgrep \"$sub_expect\" sub-actual &&\n \tgrep $(cat expect1) actual > /dev/null &&\n \tgrep $(cat expect2) actual > /dev/null &&\n \tgit reset --hard)\n@@ -227,11 +206,9 @@ test_expect_success 'merging should fail for changes that are backwards' '\n \n \tgit checkout -b test-backward e &&\n \ttest_must_fail git merge f 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n \n@@ -358,7 +335,7 @@ test_expect_success 'setup file/submodule conflict' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'file/submodule conflict' '\n+test_expect_success 'file/submodule conflict' '\n \ttest_when_finished \"git -C file-submodule reset --hard\" &&\n \t(\n \t\tcd file-submodule &&\n@@ -467,7 +444,7 @@ test_expect_failure 'directory/submodule conflict; keep submodule clean' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n+test_expect_success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n \ttest_when_finished \"git -C directory-submodule/path reset --hard\" &&\n \ttest_when_finished \"git -C directory-submodule reset --hard\" &&\n \t(\n@@ -535,11 +512,9 @@ test_expect_success 'merging should fail with no merge base' '\n \tgit add sub &&\n \tgit commit -m \"b\" &&\n \ttest_must_fail git merge a 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n test_done\ndiff --git a/t/t6438-submodule-directory-file-conflicts.sh b/t/t6438-submodule-directory-file-conflicts.sh\nindex 8df67a0ef99..53d83c828a7 100755\n--- a/t/t6438-submodule-directory-file-conflicts.sh\n+++ b/t/t6438-submodule-directory-file-conflicts.sh\n@@ -12,11 +12,6 @@ test_submodule_switch \"merge --ff\"\n \n test_submodule_switch \"merge --ff-only\"\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"merge --no-ff\"\n \n test_done\ndiff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh\nindex 55bd744a3f4..643c9368e0e 100755\n--- a/t/t6439-merge-co-error-msgs.sh\n+++ b/t/t6439-merge-co-error-msgs.sh\n@@ -47,7 +47,7 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for\n \t\texport GIT_MERGE_VERBOSITY &&\n \t\ttest_must_fail git merge branch 2>out2\n \t) &&\n-\techo \"Merge with strategy ${GIT_TEST_MERGE_ALGORITHM:-ort} failed.\" >>expect &&\n+\techo \"Merge with strategy ort failed.\" >>expect &&\n \ttest_cmp out2 expect &&\n \tgit reset --hard HEAD^\n '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 25b33a1e875..06cee3432fe 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -124,11 +124,8 @@ test_expect_success 'rebasing submodule that should conflict' '\n \t\techo \"160000 $(git rev-parse HEAD) 3\tsubmodule\"\n \t) >expect &&\n \ttest_cmp expect actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n-\t\tgrep \"$sub_expect\" actual_output\n-\tfi\n+\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n+\tgrep \"$sub_expect\" actual_output\n '\n \n test_done\ndiff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh\nindex ff085b086cc..42f675b7399 100755\n--- a/t/t7602-merge-octopus-many.sh\n+++ b/t/t7602-merge-octopus-many.sh\n@@ -77,12 +77,9 @@ Merge made by the 'recursive' strategy.\n EOF\n \n test_expect_success 'merge reduces irrelevant remote heads' '\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv expected expected.tmp &&\n-\t\tsed s/recursive/ort/ expected.tmp >expected &&\n-\t\trm expected.tmp\n-\tfi &&\n+\tmv expected expected.tmp &&\n+\tsed s/recursive/ort/ expected.tmp >expected &&\n+\trm expected.tmp &&\n \tGIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&\n \ttest_cmp expected actual\n '\ndiff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh\nindex c077aba7ced..957f8e20ba3 100755\n--- a/t/t7610-mergetool.sh\n+++ b/t/t7610-mergetool.sh\n@@ -535,14 +535,9 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"c\" | git mergetool submod~HEAD &&\n-\t\tgit rm submod &&\n-\t\tgit mv submod~HEAD submod\n-\telse\n-\t\tyes \"l\" | git mergetool submod\n-\tfi &&\n+\tyes \"c\" | git mergetool submod~HEAD &&\n+\tgit rm submod &&\n+\tgit mv submod~HEAD submod &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod &&\n@@ -559,15 +554,10 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv submod submod.orig &&\n-\t\tgit rm --cached submod &&\n-\t\tyes \"c\" | git mergetool submod~test19 &&\n-\t\tgit mv submod~test19 submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tmv submod submod.orig &&\n+\tgit rm --cached submod &&\n+\tyes \"c\" | git mergetool submod~test19 &&\n+\tgit mv submod~test19 submod &&\n \ttest -d submod.orig &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n@@ -585,10 +575,7 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n \tyes \"l\" | git mergetool submod &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"d\" | git mergetool submod~test19\n-\tfi &&\n+\tyes \"d\" | git mergetool submod~test19 &&\n \techo \"main submodule\" >expect &&\n \ttest_cmp expect submod/bar &&\n \tgit submodule update -N &&\n@@ -686,14 +673,9 @@ test_expect_success 'directory vs modified submodule' '\n \ttest_must_fail git merge main &&\n \ttest -n \"$(git ls-files -u)\" &&\n \ttest ! -e submod.orig &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"r\" | git mergetool submod~main &&\n-\t\tgit mv submod submod.orig &&\n-\t\tgit mv submod~main submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tyes \"r\" | git mergetool submod~main &&\n+\tgit mv submod submod.orig &&\n+\tgit mv submod~main submod &&\n \ttest -d submod.orig &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod.orig/file16 &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..5952eb56e27 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -544,8 +544,6 @@ GIT_DEFAULT_HASH=\"${GIT_TEST_DEFAULT_HASH:-sha1}\"\n export GIT_DEFAULT_HASH\n GIT_DEFAULT_REF_FORMAT=\"${GIT_TEST_DEFAULT_REF_FORMAT:-files}\"\n export GIT_DEFAULT_REF_FORMAT\n-GIT_TEST_MERGE_ALGORITHM=\"${GIT_TEST_MERGE_ALGORITHM:-ort}\"\n-export GIT_TEST_MERGE_ALGORITHM\n \n # Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output\n GIT_TRACE_BARE=1\n-- \ngitgitgadget\n\n"},{"id":"515713","messageId":"770f611c2b6b7356dc416d1b6d426a47248bc177.1743891375.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v2 6/8] merge-recursive.[ch]: thoroughly debug these","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-05T22:16:12Z","receivedAt":"2025-04-05T22:16:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAs a wise man once told me, \"Deleted code is debugged code!\"  So, move\nthe functions that are shared between merge-recursive and merge-ort from\nthe former to the latter, and then debug the remainder of\nmerge-recursive.[ch].\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc          |   24 +-\n Documentation/technical/sparse-checkout.adoc |    2 -\n Makefile                                     |    1 -\n merge-ort-wrappers.h                         |    2 +-\n merge-ort.c                                  |  159 +\n merge-ort.h                                  |   60 +-\n merge-recursive.c                            | 4080 ------------------\n merge-recursive.h                            |  132 -\n meson.build                                  |    1 -\n 9 files changed, 225 insertions(+), 4236 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 8c87dd70210..9e034f447e7 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -109,23 +109,11 @@ subtree[=<path>];;\n \ttwo trees to match.\n \n recursive::\n-\tThis can only resolve two heads using a 3-way merge\n-\talgorithm.  When there is more than one common\n-\tancestor that can be used for 3-way merge, it creates a\n-\tmerged tree of the common ancestors and uses that as\n-\tthe reference tree for the 3-way merge.  This has been\n-\treported to result in fewer merge conflicts without\n-\tcausing mismerges by tests done on actual merge commits\n-\ttaken from Linux 2.6 kernel development history.\n-\tAdditionally this can detect and handle merges involving\n-\trenames.  It does not make use of detected copies.  This was\n-\tthe default strategy for resolving two heads from Git v0.99.9k\n-\tuntil v2.33.0.\n-+\n-For a path that is a submodule, the same caution as 'ort' applies to this\n-strategy.\n-+\n-The 'recursive' strategy takes the same options as 'ort'.\n+\tThis is now a synonym for `ort`.  It was an alternative\n+\timplementation until v2.49.0, but was redirected to mean `ort`\n+\tin v2.50.0.  The previous recursive strategy was the default\n+\tstrategy for resolving two heads from Git v0.99.9k until\n+\tv2.33.0.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\n@@ -146,7 +134,7 @@ ours::\n \tignoring all changes from all other branches.  It is meant to\n \tbe used to supersede old development history of side\n \tbranches.  Note that this is different from the -Xours option to\n-\tthe 'recursive' merge strategy.\n+\tthe 'ort' merge strategy.\n \n subtree::\n \tThis is a modified `ort` strategy. When merging trees A and\ndiff --git a/Documentation/technical/sparse-checkout.adoc b/Documentation/technical/sparse-checkout.adoc\nindex d9686593548..dc2e763bbec 100644\n--- a/Documentation/technical/sparse-checkout.adoc\n+++ b/Documentation/technical/sparse-checkout.adoc\n@@ -356,8 +356,6 @@ understanding these differences can be beneficial.\n     The behavior for these commands somewhat depends upon the merge\n     strategy being used:\n       * `ort` behaves as described above\n-      * `recursive` tries to not vivify files unnecessarily, but does sometimes\n-\tvivify files without conflicts.\n       * `octopus` and `resolve` will always vivify any file changed in the merge\n \trelative to the first parent, which is rather suboptimal.\n \ndiff --git a/Makefile b/Makefile\nindex ac32d2d0bda..4fbd29cc7e9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1069,7 +1069,6 @@ LIB_OBJS += merge-blobs.o\n LIB_OBJS += merge-ll.o\n LIB_OBJS += merge-ort.o\n LIB_OBJS += merge-ort-wrappers.o\n-LIB_OBJS += merge-recursive.o\n LIB_OBJS += merge.o\n LIB_OBJS += midx.o\n LIB_OBJS += midx-write.o\ndiff --git a/merge-ort-wrappers.h b/merge-ort-wrappers.h\nindex aeffa1c87b4..b7e1ced9d7f 100644\n--- a/merge-ort-wrappers.h\n+++ b/merge-ort-wrappers.h\n@@ -1,7 +1,7 @@\n #ifndef MERGE_ORT_WRAPPERS_H\n #define MERGE_ORT_WRAPPERS_H\n \n-#include \"merge-recursive.h\"\n+#include \"merge-ort.h\"\n \n /*\n  * rename-detecting three-way merge, no recursion.\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 14a7ae4a6bf..f943f5ddcba 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -26,6 +26,7 @@\n #include \"cache-tree.h\"\n #include \"commit.h\"\n #include \"commit-reach.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"dir.h\"\n@@ -5322,3 +5323,161 @@ void merge_incore_recursive(struct merge_options *opt,\n \tmerge_ort_internal(opt, merge_bases, side1, side2, result);\n \ttrace2_region_leave(\"merge\", \"incore_recursive\", opt->repo);\n }\n+\n+static void merge_recursive_config(struct merge_options *opt, int ui)\n+{\n+\tchar *value = NULL;\n+\tint renormalize = 0;\n+\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n+\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n+\topt->renormalize = renormalize;\n+\tif (!git_config_get_string(\"diff.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n+\t\tint boolval = git_parse_maybe_bool(value);\n+\t\tif (0 <= boolval) {\n+\t\t\topt->detect_directory_renames = boolval ?\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n+\t\t} else if (!strcasecmp(value, \"conflict\")) {\n+\t\t\topt->detect_directory_renames =\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n+\t\t} /* avoid erroring on values from future versions of git */\n+\t\tfree(value);\n+\t}\n+\tif (ui) {\n+\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n+\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n+\t\t\tif (diff_algorithm < 0)\n+\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n+\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n+\t\t\tfree(value);\n+\t\t}\n+\t}\n+\tgit_config(git_xmerge_config, NULL);\n+}\n+\n+static void init_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo, int ui)\n+{\n+\tconst char *merge_verbosity;\n+\tmemset(opt, 0, sizeof(struct merge_options));\n+\n+\topt->repo = repo;\n+\n+\topt->detect_renames = -1;\n+\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n+\topt->rename_limit = -1;\n+\n+\topt->verbosity = 2;\n+\topt->buffer_output = 1;\n+\tstrbuf_init(&opt->obuf, 0);\n+\n+\topt->renormalize = 0;\n+\n+\topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\n+\tmerge_recursive_config(opt, ui);\n+\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n+\tif (merge_verbosity)\n+\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n+\tif (opt->verbosity >= 5)\n+\t\topt->buffer_output = 0;\n+}\n+\n+void init_ui_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 1);\n+}\n+\n+void init_basic_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 0);\n+}\n+\n+/*\n+ * For now, members of merge_options do not need deep copying, but\n+ * it may change in the future, in which case we would need to update\n+ * this, and also make a matching change to clear_merge_options() to\n+ * release the resources held by a copied instance.\n+ */\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n+{\n+\t*dst = *src;\n+}\n+\n+void clear_merge_options(struct merge_options *opt UNUSED)\n+{\n+\t; /* no-op as our copy is shallow right now */\n+}\n+\n+int parse_merge_opt(struct merge_options *opt, const char *s)\n+{\n+\tconst char *arg;\n+\n+\tif (!s || !*s)\n+\t\treturn -1;\n+\tif (!strcmp(s, \"ours\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n+\telse if (!strcmp(s, \"theirs\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n+\telse if (!strcmp(s, \"subtree\"))\n+\t\topt->subtree_shift = \"\";\n+\telse if (skip_prefix(s, \"subtree=\", &arg))\n+\t\topt->subtree_shift = arg;\n+\telse if (!strcmp(s, \"patience\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n+\telse if (!strcmp(s, \"histogram\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n+\t\tlong value = parse_algorithm_value(arg);\n+\t\tif (value < 0)\n+\t\t\treturn -1;\n+\t\t/* clear out previous settings */\n+\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n+\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n+\t\topt->xdl_opts |= value;\n+\t}\n+\telse if (!strcmp(s, \"ignore-space-change\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n+\telse if (!strcmp(s, \"ignore-all-space\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n+\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n+\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n+\telse if (!strcmp(s, \"renormalize\"))\n+\t\topt->renormalize = 1;\n+\telse if (!strcmp(s, \"no-renormalize\"))\n+\t\topt->renormalize = 0;\n+\telse if (!strcmp(s, \"no-renames\"))\n+\t\topt->detect_renames = 0;\n+\telse if (!strcmp(s, \"find-renames\")) {\n+\t\topt->detect_renames = 1;\n+\t\topt->rename_score = 0;\n+\t}\n+\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n+\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n+\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n+\t\t\treturn -1;\n+\t\topt->detect_renames = 1;\n+\t}\n+\t/*\n+\t * Please update $__git_merge_strategy_options in\n+\t * git-completion.bash when you add new options\n+\t */\n+\telse\n+\t\treturn -1;\n+\treturn 0;\n+}\ndiff --git a/merge-ort.h b/merge-ort.h\nindex b63bc5424e7..30750c03962 100644\n--- a/merge-ort.h\n+++ b/merge-ort.h\n@@ -1,10 +1,11 @@\n #ifndef MERGE_ORT_H\n #define MERGE_ORT_H\n \n-#include \"merge-recursive.h\"\n #include \"hash.h\"\n+#include \"strbuf.h\"\n \n struct commit;\n+struct commit_list;\n struct tree;\n struct strmap;\n \n@@ -44,6 +45,51 @@ struct merge_result {\n \tunsigned _properly_initialized;\n };\n \n+struct merge_options_internal;\n+struct merge_options {\n+\tstruct repository *repo;\n+\n+\t/* ref names used in console messages and conflict markers */\n+\tconst char *ancestor;\n+\tconst char *branch1;\n+\tconst char *branch2;\n+\n+\t/* rename related options */\n+\tint detect_renames;\n+\tenum {\n+\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n+\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n+\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n+\t} detect_directory_renames;\n+\tint rename_limit;\n+\tint rename_score;\n+\tint show_rename_progress;\n+\n+\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n+\tlong xdl_opts;\n+\tint conflict_style;\n+\tenum {\n+\t\tMERGE_VARIANT_NORMAL = 0,\n+\t\tMERGE_VARIANT_OURS,\n+\t\tMERGE_VARIANT_THEIRS\n+\t} recursive_variant;\n+\n+\t/* console output related options */\n+\tint verbosity;\n+\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n+\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n+\t\t\t\t * must handle and call strbuf_release */\n+\n+\t/* miscellaneous control options */\n+\tconst char *subtree_shift;\n+\tunsigned renormalize : 1;\n+\tunsigned record_conflict_msgs_as_headers : 1;\n+\tconst char *msg_header_prefix;\n+\n+\t/* internal fields used by the implementation */\n+\tstruct merge_options_internal *priv;\n+};\n+\n /* Mostly internal function also used by merge-ort-wrappers.c */\n struct commit *make_virtual_commit(struct repository *repo,\n \t\t\t\t   struct tree *tree,\n@@ -119,4 +165,16 @@ void merge_get_conflicted_files(struct merge_result *result,\n void merge_finalize(struct merge_options *opt,\n \t\t    struct merge_result *result);\n \n+\n+/* for use by porcelain commands */\n+void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n+/* for use by plumbing commands */\n+void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n+\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n+void clear_merge_options(struct merge_options *opt);\n+\n+/* parse the option in s and update the relevant field of opt */\n+int parse_merge_opt(struct merge_options *opt, const char *s);\n+\n #endif\ndiff --git a/merge-recursive.c b/merge-recursive.c\ndeleted file mode 100644\nindex f3df127ad9b..00000000000\n--- a/merge-recursive.c\n+++ /dev/null\n@@ -1,4080 +0,0 @@\n-/*\n- * Recursive Merge algorithm stolen from git-merge-recursive.py by\n- * Fredrik Kuivinen.\n- * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006\n- */\n-\n-#define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n-\n-#include \"git-compat-util.h\"\n-#include \"merge-recursive.h\"\n-\n-#include \"alloc.h\"\n-#include \"cache-tree.h\"\n-#include \"commit.h\"\n-#include \"commit-reach.h\"\n-#include \"config.h\"\n-#include \"diff.h\"\n-#include \"diffcore.h\"\n-#include \"dir.h\"\n-#include \"environment.h\"\n-#include \"gettext.h\"\n-#include \"hex.h\"\n-#include \"merge-ll.h\"\n-#include \"lockfile.h\"\n-#include \"match-trees.h\"\n-#include \"name-hash.h\"\n-#include \"object-file.h\"\n-#include \"object-name.h\"\n-#include \"object-store-ll.h\"\n-#include \"path.h\"\n-#include \"repository.h\"\n-#include \"revision.h\"\n-#include \"sparse-index.h\"\n-#include \"string-list.h\"\n-#include \"symlinks.h\"\n-#include \"tag.h\"\n-#include \"tree-walk.h\"\n-#include \"unpack-trees.h\"\n-#include \"xdiff-interface.h\"\n-\n-struct merge_options_internal {\n-\tint call_depth;\n-\tint needed_rename_limit;\n-\tstruct hashmap current_file_dir_set;\n-\tstruct string_list df_conflict_file_set;\n-\tstruct unpack_trees_options unpack_opts;\n-\tstruct index_state orig_index;\n-};\n-\n-struct path_hashmap_entry {\n-\tstruct hashmap_entry e;\n-\tchar path[FLEX_ARRAY];\n-};\n-\n-static int path_hashmap_cmp(const void *cmp_data UNUSED,\n-\t\t\t    const struct hashmap_entry *eptr,\n-\t\t\t    const struct hashmap_entry *entry_or_key,\n-\t\t\t    const void *keydata)\n-{\n-\tconst struct path_hashmap_entry *a, *b;\n-\tconst char *key = keydata;\n-\n-\ta = container_of(eptr, const struct path_hashmap_entry, e);\n-\tb = container_of(entry_or_key, const struct path_hashmap_entry, e);\n-\n-\treturn fspathcmp(a->path, key ? key : b->path);\n-}\n-\n-/*\n- * For dir_rename_entry, directory names are stored as a full path from the\n- * toplevel of the repository and do not include a trailing '/'.  Also:\n- *\n- *   dir:                original name of directory being renamed\n- *   non_unique_new_dir: if true, could not determine new_dir\n- *   new_dir:            final name of directory being renamed\n- *   possible_new_dirs:  temporary used to help determine new_dir; see comments\n- *                       in get_directory_renames() for details\n- */\n-struct dir_rename_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *dir;\n-\tunsigned non_unique_new_dir:1;\n-\tstruct strbuf new_dir;\n-\tstruct string_list possible_new_dirs;\n-};\n-\n-static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t      char *dir)\n-{\n-\tstruct dir_rename_entry key;\n-\n-\tif (!dir)\n-\t\treturn NULL;\n-\thashmap_entry_init(&key.ent, strhash(dir));\n-\tkey.dir = dir;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int dir_rename_cmp(const void *cmp_data UNUSED,\n-\t\t\t  const struct hashmap_entry *eptr,\n-\t\t\t  const struct hashmap_entry *entry_or_key,\n-\t\t\t  const void *keydata UNUSED)\n-{\n-\tconst struct dir_rename_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct dir_rename_entry, ent);\n-\te2 = container_of(entry_or_key, const struct dir_rename_entry, ent);\n-\n-\treturn strcmp(e1->dir, e2->dir);\n-}\n-\n-static void dir_rename_init(struct hashmap *map)\n-{\n-\thashmap_init(map, dir_rename_cmp, NULL, 0);\n-}\n-\n-static void dir_rename_entry_init(struct dir_rename_entry *entry,\n-\t\t\t\t  char *directory)\n-{\n-\thashmap_entry_init(&entry->ent, strhash(directory));\n-\tentry->dir = directory;\n-\tentry->non_unique_new_dir = 0;\n-\tstrbuf_init(&entry->new_dir, 0);\n-\tstring_list_init_nodup(&entry->possible_new_dirs);\n-}\n-\n-struct collision_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *target_file;\n-\tstruct string_list source_files;\n-\tunsigned reported_already:1;\n-};\n-\n-static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t    char *target_file)\n-{\n-\tstruct collision_entry key;\n-\n-\thashmap_entry_init(&key.ent, strhash(target_file));\n-\tkey.target_file = target_file;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int collision_cmp(const void *cmp_data UNUSED,\n-\t\t\t const struct hashmap_entry *eptr,\n-\t\t\t const struct hashmap_entry *entry_or_key,\n-\t\t\t const void *keydata UNUSED)\n-{\n-\tconst struct collision_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct collision_entry, ent);\n-\te2 = container_of(entry_or_key, const struct collision_entry, ent);\n-\n-\treturn strcmp(e1->target_file, e2->target_file);\n-}\n-\n-static void collision_init(struct hashmap *map)\n-{\n-\thashmap_init(map, collision_cmp, NULL, 0);\n-}\n-\n-static void flush_output(struct merge_options *opt)\n-{\n-\tif (opt->buffer_output < 2 && opt->obuf.len) {\n-\t\tfputs(opt->obuf.buf, stdout);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-}\n-\n-__attribute__((format (printf, 2, 3)))\n-static int err(struct merge_options *opt, const char *err, ...)\n-{\n-\tva_list params;\n-\n-\tif (opt->buffer_output < 2)\n-\t\tflush_output(opt);\n-\telse {\n-\t\tstrbuf_complete(&opt->obuf, '\\n');\n-\t\tstrbuf_addstr(&opt->obuf, \"error: \");\n-\t}\n-\tva_start(params, err);\n-\tstrbuf_vaddf(&opt->obuf, err, params);\n-\tva_end(params);\n-\tif (opt->buffer_output > 1)\n-\t\tstrbuf_addch(&opt->obuf, '\\n');\n-\telse {\n-\t\terror(\"%s\", opt->obuf.buf);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-\n-\treturn -1;\n-}\n-\n-static struct tree *shift_tree_object(struct repository *repo,\n-\t\t\t\t      struct tree *one, struct tree *two,\n-\t\t\t\t      const char *subtree_shift)\n-{\n-\tstruct object_id shifted;\n-\n-\tif (!*subtree_shift) {\n-\t\tshift_tree(repo, &one->object.oid, &two->object.oid, &shifted, 0);\n-\t} else {\n-\t\tshift_tree_by(repo, &one->object.oid, &two->object.oid, &shifted,\n-\t\t\t      subtree_shift);\n-\t}\n-\tif (oideq(&two->object.oid, &shifted))\n-\t\treturn two;\n-\treturn lookup_tree(repo, &shifted);\n-}\n-\n-static inline void set_commit_tree(struct commit *c, struct tree *t)\n-{\n-\tc->maybe_tree = t;\n-}\n-\n-static struct commit *make_virtual_commit(struct repository *repo,\n-\t\t\t\t\t  struct tree *tree,\n-\t\t\t\t\t  const char *comment)\n-{\n-\tstruct commit *commit = alloc_commit_node(repo);\n-\n-\tset_merge_remote_desc(commit, comment, (struct object *)commit);\n-\tset_commit_tree(commit, tree);\n-\tcommit->object.parsed = 1;\n-\treturn commit;\n-}\n-\n-enum rename_type {\n-\tRENAME_NORMAL = 0,\n-\tRENAME_VIA_DIR,\n-\tRENAME_ADD,\n-\tRENAME_DELETE,\n-\tRENAME_ONE_FILE_TO_ONE,\n-\tRENAME_ONE_FILE_TO_TWO,\n-\tRENAME_TWO_FILES_TO_ONE\n-};\n-\n-/*\n- * Since we want to write the index eventually, we cannot reuse the index\n- * for these (temporary) data.\n- */\n-struct stage_data {\n-\tstruct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */\n-\tstruct rename_conflict_info *rename_conflict_info;\n-\tunsigned processed:1,\n-\t\t rename_conflict_info_owned:1;\n-};\n-\n-struct rename {\n-\tunsigned processed:1;\n-\tstruct diff_filepair *pair;\n-\tconst char *branch; /* branch that the rename occurred on */\n-\t/*\n-\t * If directory rename detection affected this rename, what was its\n-\t * original type ('A' or 'R') and it's original destination before\n-\t * the directory rename (otherwise, '\\0' and NULL for these two vars).\n-\t */\n-\tchar dir_rename_original_type;\n-\tchar *dir_rename_original_dest;\n-\t/*\n-\t * Purpose of src_entry and dst_entry:\n-\t *\n-\t * If 'before' is renamed to 'after' then src_entry will contain\n-\t * the versions of 'before' from the merge_base, HEAD, and MERGE in\n-\t * stages 1, 2, and 3; dst_entry will contain the respective\n-\t * versions of 'after' in corresponding locations.  Thus, we have a\n-\t * total of six modes and oids, though some will be null.  (Stage 0\n-\t * is ignored; we're interested in handling conflicts.)\n-\t *\n-\t * Since we don't turn on break-rewrites by default, neither\n-\t * src_entry nor dst_entry can have all three of their stages have\n-\t * non-null oids, meaning at most four of the six will be non-null.\n-\t * Also, since this is a rename, both src_entry and dst_entry will\n-\t * have at least one non-null oid, meaning at least two will be\n-\t * non-null.  Of the six oids, a typical rename will have three be\n-\t * non-null.  Only two implies a rename/delete, and four implies a\n-\t * rename/add.\n-\t */\n-\tstruct stage_data *src_entry;\n-\tstruct stage_data *dst_entry;\n-};\n-\n-struct rename_conflict_info {\n-\tenum rename_type rename_type;\n-\tstruct rename *ren1;\n-\tstruct rename *ren2;\n-};\n-\n-static inline void setup_rename_conflict_info(enum rename_type rename_type,\n-\t\t\t\t\t      struct merge_options *opt,\n-\t\t\t\t\t      struct rename *ren1,\n-\t\t\t\t\t      struct rename *ren2)\n-{\n-\tstruct rename_conflict_info *ci;\n-\n-\t/*\n-\t * When we have two renames involved, it's easiest to get the\n-\t * correct things into stage 2 and 3, and to make sure that the\n-\t * content merge puts HEAD before the other branch if we just\n-\t * ensure that branch1 == opt->branch1.  So, simply flip arguments\n-\t * around if we don't have that.\n-\t */\n-\tif (ren2 && ren1->branch != opt->branch1) {\n-\t\tsetup_rename_conflict_info(rename_type, opt, ren2, ren1);\n-\t\treturn;\n-\t}\n-\n-\tCALLOC_ARRAY(ci, 1);\n-\tci->rename_type = rename_type;\n-\tci->ren1 = ren1;\n-\tci->ren2 = ren2;\n-\n-\tci->ren1->dst_entry->processed = 0;\n-\tci->ren1->dst_entry->rename_conflict_info = ci;\n-\tci->ren1->dst_entry->rename_conflict_info_owned = 1;\n-\tif (ren2) {\n-\t\tci->ren2->dst_entry->rename_conflict_info = ci;\n-\t}\n-}\n-\n-static int show(struct merge_options *opt, int v)\n-{\n-\treturn (!opt->priv->call_depth && opt->verbosity >= v) ||\n-\t\topt->verbosity >= 5;\n-}\n-\n-__attribute__((format (printf, 3, 4)))\n-static void output(struct merge_options *opt, int v, const char *fmt, ...)\n-{\n-\tva_list ap;\n-\n-\tif (!show(opt, v))\n-\t\treturn;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\n-\tva_start(ap, fmt);\n-\tstrbuf_vaddf(&opt->obuf, fmt, ap);\n-\tva_end(ap);\n-\n-\tstrbuf_addch(&opt->obuf, '\\n');\n-\tif (!opt->buffer_output)\n-\t\tflush_output(opt);\n-}\n-\n-static void repo_output_commit_title(struct merge_options *opt,\n-\t\t\t\t     struct repository *repo,\n-\t\t\t\t     struct commit *commit)\n-{\n-\tstruct merge_remote_desc *desc;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\tdesc = merge_remote_util(commit);\n-\tif (desc)\n-\t\tstrbuf_addf(&opt->obuf, \"virtual %s\\n\", desc->name);\n-\telse {\n-\t\tstrbuf_repo_add_unique_abbrev(&opt->obuf, repo,\n-\t\t\t\t\t      &commit->object.oid,\n-\t\t\t\t\t      DEFAULT_ABBREV);\n-\t\tstrbuf_addch(&opt->obuf, ' ');\n-\t\tif (repo_parse_commit(repo, commit) != 0)\n-\t\t\tstrbuf_addstr(&opt->obuf, _(\"(bad commit)\\n\"));\n-\t\telse {\n-\t\t\tconst char *title;\n-\t\t\tconst char *msg = repo_get_commit_buffer(repo, commit, NULL);\n-\t\t\tint len = find_commit_subject(msg, &title);\n-\t\t\tif (len)\n-\t\t\t\tstrbuf_addf(&opt->obuf, \"%.*s\\n\", len, title);\n-\t\t\trepo_unuse_commit_buffer(repo, commit, msg);\n-\t\t}\n-\t}\n-\tflush_output(opt);\n-}\n-\n-static void output_commit_title(struct merge_options *opt, struct commit *commit)\n-{\n-\trepo_output_commit_title(opt, the_repository, commit);\n-}\n-\n-static int add_cacheinfo(struct merge_options *opt,\n-\t\t\t const struct diff_filespec *blob,\n-\t\t\t const char *path, int stage, int refresh, int options)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tstruct cache_entry *ce;\n-\tint ret;\n-\n-\tce = make_cache_entry(istate, blob->mode, &blob->oid, path, stage, 0);\n-\tif (!ce)\n-\t\treturn err(opt, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n-\n-\tret = add_index_entry(istate, ce, options);\n-\tif (refresh) {\n-\t\tstruct cache_entry *nce;\n-\n-\t\tnce = refresh_cache_entry(istate, ce,\n-\t\t\t\t\t  CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);\n-\t\tif (!nce)\n-\t\t\treturn err(opt, _(\"add_cacheinfo failed to refresh for path '%s'; merge aborting.\"), path);\n-\t\tif (nce != ce)\n-\t\t\tret = add_index_entry(istate, nce, options);\n-\t}\n-\treturn ret;\n-}\n-\n-static inline int merge_detect_rename(struct merge_options *opt)\n-{\n-\treturn (opt->detect_renames >= 0) ? opt->detect_renames : 1;\n-}\n-\n-static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)\n-{\n-\tif (parse_tree(tree) < 0)\n-\t\texit(128);\n-\tinit_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size);\n-}\n-\n-static int unpack_trees_start(struct merge_options *opt,\n-\t\t\t      struct tree *common,\n-\t\t\t      struct tree *head,\n-\t\t\t      struct tree *merge)\n-{\n-\tint rc;\n-\tstruct tree_desc t[3];\n-\tstruct index_state tmp_index = INDEX_STATE_INIT(opt->repo);\n-\n-\tmemset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));\n-\tif (opt->priv->call_depth)\n-\t\topt->priv->unpack_opts.index_only = 1;\n-\telse {\n-\t\topt->priv->unpack_opts.update = 1;\n-\t\t/* FIXME: should only do this if !overwrite_ignore */\n-\t\topt->priv->unpack_opts.preserve_ignored = 0;\n-\t}\n-\topt->priv->unpack_opts.merge = 1;\n-\topt->priv->unpack_opts.head_idx = 2;\n-\topt->priv->unpack_opts.fn = threeway_merge;\n-\topt->priv->unpack_opts.src_index = opt->repo->index;\n-\topt->priv->unpack_opts.dst_index = &tmp_index;\n-\topt->priv->unpack_opts.aggressive = !merge_detect_rename(opt);\n-\tsetup_unpack_trees_porcelain(&opt->priv->unpack_opts, \"merge\");\n-\n-\tinit_tree_desc_from_tree(t+0, common);\n-\tinit_tree_desc_from_tree(t+1, head);\n-\tinit_tree_desc_from_tree(t+2, merge);\n-\n-\trc = unpack_trees(3, t, &opt->priv->unpack_opts);\n-\tcache_tree_free(&opt->repo->index->cache_tree);\n-\n-\t/*\n-\t * Update opt->repo->index to match the new results, AFTER saving a\n-\t * copy in opt->priv->orig_index.  Update src_index to point to the\n-\t * saved copy.  (verify_uptodate() checks src_index, and the original\n-\t * index is the one that had the necessary modification timestamps.)\n-\t */\n-\topt->priv->orig_index = *opt->repo->index;\n-\t*opt->repo->index = tmp_index;\n-\topt->priv->unpack_opts.src_index = &opt->priv->orig_index;\n-\n-\treturn rc;\n-}\n-\n-static void unpack_trees_finish(struct merge_options *opt)\n-{\n-\tdiscard_index(&opt->priv->orig_index);\n-\tclear_unpack_trees_porcelain(&opt->priv->unpack_opts);\n-}\n-\n-static int save_files_dirs(const struct object_id *oid UNUSED,\n-\t\t\t   struct strbuf *base, const char *path,\n-\t\t\t   unsigned int mode, void *context)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tint baselen = base->len;\n-\tstruct merge_options *opt = context;\n-\n-\tstrbuf_addstr(base, path);\n-\n-\tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\n-\tstrbuf_setlen(base, baselen);\n-\treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n-}\n-\n-static void get_files_dirs(struct merge_options *opt, struct tree *tree)\n-{\n-\tstruct pathspec match_all;\n-\tmemset(&match_all, 0, sizeof(match_all));\n-\tread_tree(opt->repo, tree,\n-\t\t  &match_all, save_files_dirs, opt);\n-}\n-\n-static int get_tree_entry_if_blob(struct repository *r,\n-\t\t\t\t  const struct object_id *tree,\n-\t\t\t\t  const char *path,\n-\t\t\t\t  struct diff_filespec *dfs)\n-{\n-\tint ret;\n-\n-\tret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);\n-\tif (S_ISDIR(dfs->mode)) {\n-\t\toidcpy(&dfs->oid, null_oid());\n-\t\tdfs->mode = 0;\n-\t}\n-\treturn ret;\n-}\n-\n-/*\n- * Returns an index_entry instance which doesn't have to correspond to\n- * a real cache entry in Git's index.\n- */\n-static struct stage_data *insert_stage_data(struct repository *r,\n-\t\tconst char *path,\n-\t\tstruct tree *o, struct tree *a, struct tree *b,\n-\t\tstruct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tstruct stage_data *e = xcalloc(1, sizeof(struct stage_data));\n-\tget_tree_entry_if_blob(r, &o->object.oid, path, &e->stages[1]);\n-\tget_tree_entry_if_blob(r, &a->object.oid, path, &e->stages[2]);\n-\tget_tree_entry_if_blob(r, &b->object.oid, path, &e->stages[3]);\n-\titem = string_list_insert(entries, path);\n-\titem->util = e;\n-\treturn e;\n-}\n-\n-/*\n- * Create a dictionary mapping file names to stage_data objects. The\n- * dictionary contains one entry for every path with a non-zero stage entry.\n- */\n-static struct string_list *get_unmerged(struct index_state *istate)\n-{\n-\tstruct string_list *unmerged = xmalloc(sizeof(struct string_list));\n-\tint i;\n-\n-\tstring_list_init_dup(unmerged);\n-\n-\t/* TODO: audit for interaction with sparse-index. */\n-\tensure_full_index(istate);\n-\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct stage_data *e;\n-\t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_stage(ce))\n-\t\t\tcontinue;\n-\n-\t\titem = string_list_lookup(unmerged, ce->name);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(unmerged, ce->name);\n-\t\t\titem->util = xcalloc(1, sizeof(struct stage_data));\n-\t\t}\n-\t\te = item->util;\n-\t\te->stages[ce_stage(ce)].mode = ce->ce_mode;\n-\t\toidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid);\n-\t}\n-\n-\treturn unmerged;\n-}\n-\n-static int string_list_df_name_compare(const char *one, const char *two)\n-{\n-\tint onelen = strlen(one);\n-\tint twolen = strlen(two);\n-\t/*\n-\t * Here we only care that entries for D/F conflicts are\n-\t * adjacent, in particular with the file of the D/F conflict\n-\t * appearing before files below the corresponding directory.\n-\t * The order of the rest of the list is irrelevant for us.\n-\t *\n-\t * To achieve this, we sort with df_name_compare and provide\n-\t * the mode S_IFDIR so that D/F conflicts will sort correctly.\n-\t * We use the mode S_IFDIR for everything else for simplicity,\n-\t * since in other cases any changes in their order due to\n-\t * sorting cause no problems for us.\n-\t */\n-\tint cmp = df_name_compare(one, onelen, S_IFDIR,\n-\t\t\t\t  two, twolen, S_IFDIR);\n-\t/*\n-\t * Now that 'foo' and 'foo/bar' compare equal, we have to make sure\n-\t * that 'foo' comes before 'foo/bar'.\n-\t */\n-\tif (cmp)\n-\t\treturn cmp;\n-\treturn onelen - twolen;\n-}\n-\n-static void record_df_conflict_files(struct merge_options *opt,\n-\t\t\t\t     struct string_list *entries)\n-{\n-\t/* If there is a D/F conflict and the file for such a conflict\n-\t * currently exists in the working tree, we want to allow it to be\n-\t * removed to make room for the corresponding directory if needed.\n-\t * The files underneath the directories of such D/F conflicts will\n-\t * be processed before the corresponding file involved in the D/F\n-\t * conflict.  If the D/F directory ends up being removed by the\n-\t * merge, then we won't have to touch the D/F file.  If the D/F\n-\t * directory needs to be written to the working copy, then the D/F\n-\t * file will simply be removed (in make_room_for_path()) to make\n-\t * room for the necessary paths.  Note that if both the directory\n-\t * and the file need to be present, then the D/F file will be\n-\t * reinstated with a new unique name at the time it is processed.\n-\t */\n-\tstruct string_list df_sorted_entries = STRING_LIST_INIT_NODUP;\n-\tconst char *last_file = NULL;\n-\tint last_len = 0;\n-\tint i;\n-\n-\t/*\n-\t * If we're merging merge-bases, we don't want to bother with\n-\t * any working directory changes.\n-\t */\n-\tif (opt->priv->call_depth)\n-\t\treturn;\n-\n-\t/* Ensure D/F conflicts are adjacent in the entries list. */\n-\tfor (i = 0; i < entries->nr; i++) {\n-\t\tstruct string_list_item *next = &entries->items[i];\n-\t\tstring_list_append(&df_sorted_entries, next->string)->util =\n-\t\t\t\t   next->util;\n-\t}\n-\tdf_sorted_entries.cmp = string_list_df_name_compare;\n-\tstring_list_sort(&df_sorted_entries);\n-\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 1);\n-\tfor (i = 0; i < df_sorted_entries.nr; i++) {\n-\t\tconst char *path = df_sorted_entries.items[i].string;\n-\t\tint len = strlen(path);\n-\t\tstruct stage_data *e = df_sorted_entries.items[i].util;\n-\n-\t\t/*\n-\t\t * Check if last_file & path correspond to a D/F conflict;\n-\t\t * i.e. whether path is last_file+'/'+<something>.\n-\t\t * If so, record that it's okay to remove last_file to make\n-\t\t * room for path and friends if needed.\n-\t\t */\n-\t\tif (last_file &&\n-\t\t    len > last_len &&\n-\t\t    memcmp(path, last_file, last_len) == 0 &&\n-\t\t    path[last_len] == '/') {\n-\t\t\tstring_list_insert(&opt->priv->df_conflict_file_set, last_file);\n-\t\t}\n-\n-\t\t/*\n-\t\t * Determine whether path could exist as a file in the\n-\t\t * working directory as a possible D/F conflict.  This\n-\t\t * will only occur when it exists in stage 2 as a\n-\t\t * file.\n-\t\t */\n-\t\tif (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) {\n-\t\t\tlast_file = path;\n-\t\t\tlast_len = len;\n-\t\t} else {\n-\t\t\tlast_file = NULL;\n-\t\t}\n-\t}\n-\tstring_list_clear(&df_sorted_entries, 0);\n-}\n-\n-static int update_stages(struct merge_options *opt, const char *path,\n-\t\t\t const struct diff_filespec *o,\n-\t\t\t const struct diff_filespec *a,\n-\t\t\t const struct diff_filespec *b)\n-{\n-\n-\t/*\n-\t * NOTE: It is usually a bad idea to call update_stages on a path\n-\t * before calling update_file on that same path, since it can\n-\t * sometimes lead to spurious \"refusing to lose untracked file...\"\n-\t * messages from update_file (via make_room_for path via\n-\t * would_lose_untracked).  Instead, reverse the order of the calls\n-\t * (executing update_file first and then update_stages).\n-\t */\n-\tint clear = 1;\n-\tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;\n-\tif (clear)\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\tif (o)\n-\t\tif (add_cacheinfo(opt, o, path, 1, 0, options))\n-\t\t\treturn -1;\n-\tif (a)\n-\t\tif (add_cacheinfo(opt, a, path, 2, 0, options))\n-\t\t\treturn -1;\n-\tif (b)\n-\t\tif (add_cacheinfo(opt, b, path, 3, 0, options))\n-\t\t\treturn -1;\n-\treturn 0;\n-}\n-\n-static void update_entry(struct stage_data *entry,\n-\t\t\t struct diff_filespec *o,\n-\t\t\t struct diff_filespec *a,\n-\t\t\t struct diff_filespec *b)\n-{\n-\tentry->processed = 0;\n-\tentry->stages[1].mode = o->mode;\n-\tentry->stages[2].mode = a->mode;\n-\tentry->stages[3].mode = b->mode;\n-\toidcpy(&entry->stages[1].oid, &o->oid);\n-\toidcpy(&entry->stages[2].oid, &a->oid);\n-\toidcpy(&entry->stages[3].oid, &b->oid);\n-}\n-\n-static int remove_file(struct merge_options *opt, int clean,\n-\t\t       const char *path, int no_wd)\n-{\n-\tint update_cache = opt->priv->call_depth || clean;\n-\tint update_working_directory = !opt->priv->call_depth && !no_wd;\n-\n-\tif (update_cache) {\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\t}\n-\tif (update_working_directory) {\n-\t\tif (ignore_case) {\n-\t\t\tstruct cache_entry *ce;\n-\t\t\tce = index_file_exists(opt->repo->index, path, strlen(path),\n-\t\t\t\t\t       ignore_case);\n-\t\t\tif (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))\n-\t\t\t\treturn 0;\n-\t\t}\n-\t\tif (remove_path(path))\n-\t\t\treturn -1;\n-\t}\n-\treturn 0;\n-}\n-\n-/* add a string to a strbuf, but converting \"/\" to \"_\" */\n-static void add_flattened_path(struct strbuf *out, const char *s)\n-{\n-\tsize_t i = out->len;\n-\tstrbuf_addstr(out, s);\n-\tfor (; i < out->len; i++)\n-\t\tif (out->buf[i] == '/')\n-\t\t\tout->buf[i] = '_';\n-}\n-\n-static char *unique_path(struct merge_options *opt,\n-\t\t\t const char *path,\n-\t\t\t const char *branch)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tstruct strbuf newpath = STRBUF_INIT;\n-\tint suffix = 0;\n-\tsize_t base_len;\n-\n-\tstrbuf_addf(&newpath, \"%s~\", path);\n-\tadd_flattened_path(&newpath, branch);\n-\n-\tbase_len = newpath.len;\n-\twhile (hashmap_get_from_hash(&opt->priv->current_file_dir_set,\n-\t\t\t\t     fspathhash(newpath.buf), newpath.buf) ||\n-\t       (!opt->priv->call_depth && file_exists(newpath.buf))) {\n-\t\tstrbuf_setlen(&newpath, base_len);\n-\t\tstrbuf_addf(&newpath, \"_%d\", suffix++);\n-\t}\n-\n-\tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\treturn strbuf_detach(&newpath, NULL);\n-}\n-\n-/**\n- * Check whether a directory in the index is in the way of an incoming\n- * file.  Return 1 if so.  If check_working_copy is non-zero, also\n- * check the working directory.  If empty_ok is non-zero, also return\n- * 0 in the case where the working-tree dir exists but is empty.\n- */\n-static int dir_in_way(struct index_state *istate, const char *path,\n-\t\t      int check_working_copy, int empty_ok)\n-{\n-\tint pos;\n-\tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct stat st;\n-\n-\tstrbuf_addstr(&dirpath, path);\n-\tstrbuf_addch(&dirpath, '/');\n-\n-\tpos = index_name_pos(istate, dirpath.buf, dirpath.len);\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\tif (pos < istate->cache_nr &&\n-\t    !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {\n-\t\tstrbuf_release(&dirpath);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_release(&dirpath);\n-\treturn check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&\n-\t\t!(empty_ok && is_empty_dir(path)) &&\n-\t\t!has_symlink_leading_path(path, strlen(path));\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started,\n- * and its oid and mode match the specified values\n- */\n-static int was_tracked_and_matches(struct merge_options *opt, const char *path,\n-\t\t\t\t   const struct diff_filespec *blob)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\tstruct cache_entry *ce;\n-\n-\tif (0 > pos)\n-\t\t/* we were not tracking this path before the merge */\n-\t\treturn 0;\n-\n-\t/* See if the file we were tracking before matches */\n-\tce = opt->priv->orig_index.cache[pos];\n-\treturn (oideq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started\n- */\n-static int was_tracked(struct merge_options *opt, const char *path)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\n-\tif (0 <= pos)\n-\t\t/* we were tracking this path before the merge */\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-static int would_lose_untracked(struct merge_options *opt, const char *path)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\n-\t/*\n-\t * This may look like it can be simplified to:\n-\t *   return !was_tracked(opt, path) && file_exists(path)\n-\t * but it can't.  This function needs to know whether path was in\n-\t * the working tree due to EITHER having been tracked in the index\n-\t * before the merge OR having been put into the working copy and\n-\t * index by unpack_trees().  Due to that either-or requirement, we\n-\t * check the current index instead of the original one.\n-\t *\n-\t * Note that we do not need to worry about merge-recursive itself\n-\t * updating the index after unpack_trees() and before calling this\n-\t * function, because we strictly require all code paths in\n-\t * merge-recursive to update the working tree first and the index\n-\t * second.  Doing otherwise would break\n-\t * update_file()/would_lose_untracked(); see every comment in this\n-\t * file which mentions \"update_stages\".\n-\t */\n-\tint pos = index_name_pos(istate, path, strlen(path));\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\twhile (pos < istate->cache_nr &&\n-\t       !strcmp(path, istate->cache[pos]->name)) {\n-\t\t/*\n-\t\t * If stage #0, it is definitely tracked.\n-\t\t * If it has stage #2 then it was tracked\n-\t\t * before this merge started.  All other\n-\t\t * cases the path was not tracked.\n-\t\t */\n-\t\tswitch (ce_stage(istate->cache[pos])) {\n-\t\tcase 0:\n-\t\tcase 2:\n-\t\t\treturn 0;\n-\t\t}\n-\t\tpos++;\n-\t}\n-\treturn file_exists(path);\n-}\n-\n-static int was_dirty(struct merge_options *opt, const char *path)\n-{\n-\tstruct cache_entry *ce;\n-\tint dirty = 1;\n-\n-\tif (opt->priv->call_depth || !was_tracked(opt, path))\n-\t\treturn !dirty;\n-\n-\tce = index_file_exists(opt->priv->unpack_opts.src_index,\n-\t\t\t       path, strlen(path), ignore_case);\n-\tdirty = verify_uptodate(ce, &opt->priv->unpack_opts) != 0;\n-\treturn dirty;\n-}\n-\n-static int make_room_for_path(struct merge_options *opt, const char *path)\n-{\n-\tint status, i;\n-\tconst char *msg = _(\"failed to create path '%s'%s\");\n-\n-\t/* Unlink any D/F conflict files that are in the way */\n-\tfor (i = 0; i < opt->priv->df_conflict_file_set.nr; i++) {\n-\t\tconst char *df_path = opt->priv->df_conflict_file_set.items[i].string;\n-\t\tsize_t pathlen = strlen(path);\n-\t\tsize_t df_pathlen = strlen(df_path);\n-\t\tif (df_pathlen < pathlen &&\n-\t\t    path[df_pathlen] == '/' &&\n-\t\t    strncmp(path, df_path, df_pathlen) == 0) {\n-\t\t\toutput(opt, 3,\n-\t\t\t       _(\"Removing %s to make room for subdirectory\\n\"),\n-\t\t\t       df_path);\n-\t\t\tunlink(df_path);\n-\t\t\tunsorted_string_list_delete_item(&opt->priv->df_conflict_file_set,\n-\t\t\t\t\t\t\t i, 0);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\t/* Make sure leading directories are created */\n-\tstatus = safe_create_leading_directories_const(path);\n-\tif (status) {\n-\t\tif (status == SCLD_EXISTS)\n-\t\t\t/* something else exists */\n-\t\t\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-\t\treturn err(opt, msg, path, \"\");\n-\t}\n-\n-\t/*\n-\t * Do not unlink a file in the work tree if we are not\n-\t * tracking it.\n-\t */\n-\tif (would_lose_untracked(opt, path))\n-\t\treturn err(opt, _(\"refusing to lose untracked file at '%s'\"),\n-\t\t\t   path);\n-\n-\t/* Successful unlink is good.. */\n-\tif (!unlink(path))\n-\t\treturn 0;\n-\t/* .. and so is no existing file */\n-\tif (errno == ENOENT)\n-\t\treturn 0;\n-\t/* .. but not some other error (who really cares what?) */\n-\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-}\n-\n-static int update_file_flags(struct merge_options *opt,\n-\t\t\t     const struct diff_filespec *contents,\n-\t\t\t     const char *path,\n-\t\t\t     int update_cache,\n-\t\t\t     int update_wd)\n-{\n-\tint ret = 0;\n-\n-\tif (opt->priv->call_depth)\n-\t\tupdate_wd = 0;\n-\n-\tif (update_wd) {\n-\t\tenum object_type type;\n-\t\tvoid *buf;\n-\t\tunsigned long size;\n-\n-\t\tif (S_ISGITLINK(contents->mode)) {\n-\t\t\t/*\n-\t\t\t * We may later decide to recursively descend into\n-\t\t\t * the submodule directory and update its index\n-\t\t\t * and/or work tree, but we do not do that now.\n-\t\t\t */\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto update_index;\n-\t\t}\n-\n-\t\tbuf = repo_read_object_file(the_repository, &contents->oid,\n-\t\t\t\t\t    &type, &size);\n-\t\tif (!buf) {\n-\t\t\tret = err(opt, _(\"cannot read object %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (type != OBJ_BLOB) {\n-\t\t\tret = err(opt, _(\"blob expected for %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode)) {\n-\t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(opt->repo->index,\n-\t\t\t\t\t\t    path, buf, size, &strbuf, NULL)) {\n-\t\t\t\tfree(buf);\n-\t\t\t\tsize = strbuf.len;\n-\t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (make_room_for_path(opt, path) < 0) {\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode) ||\n-\t\t    (!has_symlinks && S_ISLNK(contents->mode))) {\n-\t\t\tint fd;\n-\t\t\tint mode = (contents->mode & 0100 ? 0777 : 0666);\n-\n-\t\t\tfd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);\n-\t\t\tif (fd < 0) {\n-\t\t\t\tret = err(opt, _(\"failed to open '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\t\tgoto free_buf;\n-\t\t\t}\n-\t\t\twrite_in_full(fd, buf, size);\n-\t\t\tclose(fd);\n-\t\t} else if (S_ISLNK(contents->mode)) {\n-\t\t\tchar *lnk = xmemdupz(buf, size);\n-\t\t\tsafe_create_leading_directories_const(path);\n-\t\t\tunlink(path);\n-\t\t\tif (symlink(lnk, path))\n-\t\t\t\tret = err(opt, _(\"failed to symlink '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\tfree(lnk);\n-\t\t} else\n-\t\t\tret = err(opt,\n-\t\t\t\t  _(\"do not know what to do with %06o %s '%s'\"),\n-\t\t\t\t  contents->mode, oid_to_hex(&contents->oid), path);\n-\tfree_buf:\n-\t\tfree(buf);\n-\t}\n-update_index:\n-\tif (!ret && update_cache) {\n-\t\tint refresh = (!opt->priv->call_depth &&\n-\t\t\t       contents->mode != S_IFGITLINK);\n-\t\tif (add_cacheinfo(opt, contents, path, 0, refresh,\n-\t\t\t\t  ADD_CACHE_OK_TO_ADD))\n-\t\t\treturn -1;\n-\t}\n-\treturn ret;\n-}\n-\n-static int update_file(struct merge_options *opt,\n-\t\t       int clean,\n-\t\t       const struct diff_filespec *contents,\n-\t\t       const char *path)\n-{\n-\treturn update_file_flags(opt, contents, path,\n-\t\t\t\t opt->priv->call_depth || clean, !opt->priv->call_depth);\n-}\n-\n-/* Low level file merging, update and removal */\n-\n-struct merge_file_info {\n-\tstruct diff_filespec blob; /* mostly use oid & mode; sometimes path */\n-\tunsigned clean:1,\n-\t\t merge:1;\n-};\n-\n-static int merge_3way(struct merge_options *opt,\n-\t\t      mmbuffer_t *result_buf,\n-\t\t      const struct diff_filespec *o,\n-\t\t      const struct diff_filespec *a,\n-\t\t      const struct diff_filespec *b,\n-\t\t      const char *branch1,\n-\t\t      const char *branch2,\n-\t\t      const int extra_marker_size)\n-{\n-\tmmfile_t orig, src1, src2;\n-\tstruct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;\n-\tchar *base, *name1, *name2;\n-\tenum ll_merge_result merge_status;\n-\n-\tll_opts.renormalize = opt->renormalize;\n-\tll_opts.extra_marker_size = extra_marker_size;\n-\tll_opts.xdl_opts = opt->xdl_opts;\n-\tll_opts.conflict_style = opt->conflict_style;\n-\n-\tif (opt->priv->call_depth) {\n-\t\tll_opts.virtual_ancestor = 1;\n-\t\tll_opts.variant = 0;\n-\t} else {\n-\t\tswitch (opt->recursive_variant) {\n-\t\tcase MERGE_VARIANT_OURS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_OURS;\n-\t\t\tbreak;\n-\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_THEIRS;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tll_opts.variant = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tassert(a->path && b->path && o->path && opt->ancestor);\n-\tif (strcmp(a->path, b->path) || strcmp(a->path, o->path) != 0) {\n-\t\tbase  = mkpathdup(\"%s:%s\", opt->ancestor, o->path);\n-\t\tname1 = mkpathdup(\"%s:%s\", branch1, a->path);\n-\t\tname2 = mkpathdup(\"%s:%s\", branch2, b->path);\n-\t} else {\n-\t\tbase  = mkpathdup(\"%s\", opt->ancestor);\n-\t\tname1 = mkpathdup(\"%s\", branch1);\n-\t\tname2 = mkpathdup(\"%s\", branch2);\n-\t}\n-\n-\tread_mmblob(&orig, &o->oid);\n-\tread_mmblob(&src1, &a->oid);\n-\tread_mmblob(&src2, &b->oid);\n-\n-\t/*\n-\t * FIXME: Using a->path for normalization rules in ll_merge could be\n-\t * wrong if we renamed from a->path to b->path.  We should use the\n-\t * target path for where the file will be written.\n-\t */\n-\tmerge_status = ll_merge(result_buf, a->path, &orig, base,\n-\t\t\t\t&src1, name1, &src2, name2,\n-\t\t\t\topt->repo->index, &ll_opts);\n-\tif (merge_status == LL_MERGE_BINARY_CONFLICT)\n-\t\twarning(\"Cannot merge binary files: %s (%s vs. %s)\",\n-\t\t\ta->path, name1, name2);\n-\n-\tfree(base);\n-\tfree(name1);\n-\tfree(name2);\n-\tfree(orig.ptr);\n-\tfree(src1.ptr);\n-\tfree(src2.ptr);\n-\treturn merge_status;\n-}\n-\n-static int find_first_merges(struct repository *repo,\n-\t\t\t     struct object_array *result, const char *path,\n-\t\t\t     struct commit *a, struct commit *b)\n-{\n-\tint i, j;\n-\tstruct object_array merges = OBJECT_ARRAY_INIT;\n-\tstruct commit *commit;\n-\tint contains_another;\n-\n-\tchar merged_revision[GIT_MAX_HEXSZ + 2];\n-\tconst char *rev_args[] = { \"rev-list\", \"--merges\", \"--ancestry-path\",\n-\t\t\t\t   \"--all\", merged_revision, NULL };\n-\tstruct rev_info revs;\n-\tstruct setup_revision_opt rev_opts;\n-\n-\tmemset(result, 0, sizeof(struct object_array));\n-\tmemset(&rev_opts, 0, sizeof(rev_opts));\n-\n-\t/* get all revisions that merge commit a */\n-\txsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n-\t\t  oid_to_hex(&a->object.oid));\n-\trepo_init_revisions(repo, &revs, NULL);\n-\t/* FIXME: can't handle linked worktrees in submodules yet */\n-\trevs.single_worktree = path != NULL;\n-\tsetup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);\n-\n-\t/* save all revisions from the above list that contain b */\n-\tif (prepare_revision_walk(&revs))\n-\t\tdie(\"revision walk setup failed\");\n-\twhile ((commit = get_revision(&revs)) != NULL) {\n-\t\tstruct object *o = &(commit->object);\n-\t\tint ret = repo_in_merge_bases(repo, b, commit);\n-\t\tif (ret < 0) {\n-\t\t\tobject_array_clear(&merges);\n-\t\t\trelease_revisions(&revs);\n-\t\t\treturn ret;\n-\t\t}\n-\t\tif (ret)\n-\t\t\tadd_object_array(o, NULL, &merges);\n-\t}\n-\treset_revision_walk();\n-\n-\t/* Now we've got all merges that contain a and b. Prune all\n-\t * merges that contain another found merge and save them in\n-\t * result.\n-\t */\n-\tfor (i = 0; i < merges.nr; i++) {\n-\t\tstruct commit *m1 = (struct commit *) merges.objects[i].item;\n-\n-\t\tcontains_another = 0;\n-\t\tfor (j = 0; j < merges.nr; j++) {\n-\t\t\tstruct commit *m2 = (struct commit *) merges.objects[j].item;\n-\t\t\tif (i != j) {\n-\t\t\t\tint ret = repo_in_merge_bases(repo, m2, m1);\n-\t\t\t\tif (ret < 0) {\n-\t\t\t\t\tobject_array_clear(&merges);\n-\t\t\t\t\trelease_revisions(&revs);\n-\t\t\t\t\treturn ret;\n-\t\t\t\t}\n-\t\t\t\tif (ret > 0) {\n-\t\t\t\t\tcontains_another = 1;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (!contains_another)\n-\t\t\tadd_object_array(merges.objects[i].item, NULL, result);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-\trelease_revisions(&revs);\n-\treturn result->nr;\n-}\n-\n-static void print_commit(struct repository *repo, struct commit *commit)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tstruct pretty_print_context ctx = {0};\n-\tctx.date_mode.type = DATE_NORMAL;\n-\t/* FIXME: Merge this with output_commit_title() */\n-\tassert(!merge_remote_util(commit));\n-\trepo_format_commit_message(repo, commit, \" %h: %m %s\", &sb, &ctx);\n-\tfprintf(stderr, \"%s\\n\", sb.buf);\n-\tstrbuf_release(&sb);\n-}\n-\n-static int is_valid(const struct diff_filespec *dfs)\n-{\n-\treturn dfs->mode != 0 && !is_null_oid(&dfs->oid);\n-}\n-\n-static int merge_submodule(struct merge_options *opt,\n-\t\t\t   struct object_id *result, const char *path,\n-\t\t\t   const struct object_id *base, const struct object_id *a,\n-\t\t\t   const struct object_id *b)\n-{\n-\tstruct repository subrepo;\n-\tint ret = 0, ret2;\n-\tstruct commit *commit_base, *commit_a, *commit_b;\n-\tint parent_count;\n-\tstruct object_array merges;\n-\n-\tint i;\n-\tint search = !opt->priv->call_depth;\n-\n-\t/* store a in result in case we fail */\n-\t/* FIXME: This is the WRONG resolution for the recursive case when\n-\t * we need to be careful to avoid accidentally matching either side.\n-\t * Should probably use o instead there, much like we do for merging\n-\t * binaries.\n-\t */\n-\toidcpy(result, a);\n-\n-\t/* we can not handle deletion conflicts */\n-\tif (is_null_oid(base))\n-\t\treturn 0;\n-\tif (is_null_oid(a))\n-\t\treturn 0;\n-\tif (is_null_oid(b))\n-\t\treturn 0;\n-\n-\tif (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not checked out)\"), path);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!(commit_base = lookup_commit_reference(&subrepo, base)) ||\n-\t    !(commit_a = lookup_commit_reference(&subrepo, a)) ||\n-\t    !(commit_b = lookup_commit_reference(&subrepo, b))) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits not present)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* check whether both changes are forward */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2 > 0)\n-\t\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (!ret2) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits don't follow merge-base)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* Case #1: a is contained in b or vice versa */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, b);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_b);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\tret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, a);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_a);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/*\n-\t * Case #2: There are one or more merges that contain a and b in\n-\t * the submodule. If there is only one, then present it as a\n-\t * suggestion to the user, but leave it marked unmerged so the\n-\t * user needs to confirm the resolution.\n-\t */\n-\n-\t/* Skip the search if makes no sense to the calling context.  */\n-\tif (!search)\n-\t\tgoto cleanup;\n-\n-\t/* find commit which merges them */\n-\tparent_count = find_first_merges(&subrepo, &merges, path,\n-\t\t\t\t\t commit_a, commit_b);\n-\tswitch (parent_count) {\n-\tcase -1:\n-\t\toutput(opt, 1,_(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tbreak;\n-\tcase 0:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (merge following commits not found)\"), path);\n-\t\tbreak;\n-\n-\tcase 1:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not fast-forward)\"), path);\n-\t\toutput(opt, 2, _(\"Found a possible merge resolution for the submodule:\\n\"));\n-\t\tprint_commit(&subrepo, (struct commit *) merges.objects[0].item);\n-\t\toutput(opt, 2, _(\n-\t\t       \"If this is correct simply add it to the index \"\n-\t\t       \"for example\\n\"\n-\t\t       \"by using:\\n\\n\"\n-\t\t       \"  git update-index --cacheinfo 160000 %s \\\"%s\\\"\\n\\n\"\n-\t\t       \"which will accept this suggestion.\\n\"),\n-\t\t       oid_to_hex(&merges.objects[0].item->oid), path);\n-\t\tbreak;\n-\n-\tdefault:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (multiple merges found)\"), path);\n-\t\tfor (i = 0; i < merges.nr; i++)\n-\t\t\tprint_commit(&subrepo, (struct commit *) merges.objects[i].item);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-cleanup:\n-\trepo_clear(&subrepo);\n-\treturn ret;\n-}\n-\n-static int merge_mode_and_contents(struct merge_options *opt,\n-\t\t\t\t   const struct diff_filespec *o,\n-\t\t\t\t   const struct diff_filespec *a,\n-\t\t\t\t   const struct diff_filespec *b,\n-\t\t\t\t   const char *filename,\n-\t\t\t\t   const char *branch1,\n-\t\t\t\t   const char *branch2,\n-\t\t\t\t   const int extra_marker_size,\n-\t\t\t\t   struct merge_file_info *result)\n-{\n-\tif (opt->branch1 != branch1) {\n-\t\t/*\n-\t\t * It's weird getting a reverse merge with HEAD on the bottom\n-\t\t * side of the conflict markers and the other branch on the\n-\t\t * top.  Fix that.\n-\t\t */\n-\t\treturn merge_mode_and_contents(opt, o, b, a,\n-\t\t\t\t\t       filename,\n-\t\t\t\t\t       branch2, branch1,\n-\t\t\t\t\t       extra_marker_size, result);\n-\t}\n-\n-\tresult->merge = 0;\n-\tresult->clean = 1;\n-\n-\tif ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {\n-\t\tresult->clean = 0;\n-\t\t/*\n-\t\t * FIXME: This is a bad resolution for recursive case; for\n-\t\t * the recursive case we want something that is unlikely to\n-\t\t * accidentally match either side.  Also, while it makes\n-\t\t * sense to prefer regular files over symlinks, it doesn't\n-\t\t * make sense to prefer regular files over submodules.\n-\t\t */\n-\t\tif (S_ISREG(a->mode)) {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t} else {\n-\t\t\tresult->blob.mode = b->mode;\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t}\n-\t} else {\n-\t\tif (!oideq(&a->oid, &o->oid) && !oideq(&b->oid, &o->oid))\n-\t\t\tresult->merge = 1;\n-\n-\t\t/*\n-\t\t * Merge modes\n-\t\t */\n-\t\tif (a->mode == b->mode || a->mode == o->mode)\n-\t\t\tresult->blob.mode = b->mode;\n-\t\telse {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\tif (b->mode != o->mode) {\n-\t\t\t\tresult->clean = 0;\n-\t\t\t\tresult->merge = 1;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\telse if (oideq(&b->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\telse if (S_ISREG(a->mode)) {\n-\t\t\tmmbuffer_t result_buf;\n-\t\t\tint ret = 0, merge_status;\n-\n-\t\t\tmerge_status = merge_3way(opt, &result_buf, o, a, b,\n-\t\t\t\t\t\t  branch1, branch2,\n-\t\t\t\t\t\t  extra_marker_size);\n-\n-\t\t\tif ((merge_status < 0) || !result_buf.ptr)\n-\t\t\t\tret = err(opt, _(\"failed to execute internal merge\"));\n-\n-\t\t\tif (!ret &&\n-\t\t\t    write_object_file(result_buf.ptr, result_buf.size,\n-\t\t\t\t\t      OBJ_BLOB, &result->blob.oid))\n-\t\t\t\tret = err(opt, _(\"unable to add %s to database\"),\n-\t\t\t\t\t  a->path);\n-\n-\t\t\tfree(result_buf.ptr);\n-\t\t\tif (ret)\n-\t\t\t\treturn ret;\n-\t\t\t/* FIXME: bug, what if modes didn't match? */\n-\t\t\tresult->clean = (merge_status == 0);\n-\t\t} else if (S_ISGITLINK(a->mode)) {\n-\t\t\tint clean = merge_submodule(opt, &result->blob.oid,\n-\t\t\t\t\t\t    o->path,\n-\t\t\t\t\t\t    &o->oid,\n-\t\t\t\t\t\t    &a->oid,\n-\t\t\t\t\t\t    &b->oid);\n-\t\t\tif (clean < 0)\n-\t\t\t\treturn -1;\n-\t\t\tresult->clean = clean;\n-\t\t} else if (S_ISLNK(a->mode)) {\n-\t\t\tswitch (opt->recursive_variant) {\n-\t\t\tcase MERGE_VARIANT_NORMAL:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tif (!oideq(&a->oid, &b->oid))\n-\t\t\t\t\tresult->clean = 0;\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_OURS:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t} else\n-\t\t\tBUG(\"unsupported object type in the tree\");\n-\t}\n-\n-\tif (result->merge)\n-\t\toutput(opt, 2, _(\"Auto-merging %s\"), filename);\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_via_dir(struct merge_options *opt,\n-\t\t\t\t struct rename_conflict_info *ci)\n-{\n-\t/*\n-\t * Handle file adds that need to be renamed due to directory rename\n-\t * detection.  This differs from handle_rename_normal, because\n-\t * there is no content merge to do; just move the file into the\n-\t * desired final location.\n-\t */\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tchar *file_path = dest->path;\n-\tint mark_conflicted = (opt->detect_directory_renames ==\n-\t\t\t       MERGE_DIRECTORY_RENAMES_CONFLICT);\n-\tassert(ren->dir_rename_original_dest);\n-\n-\tif (!opt->priv->call_depth && would_lose_untracked(opt, dest->path)) {\n-\t\tmark_conflicted = 1;\n-\t\tfile_path = unique_path(opt, dest->path, ren->branch);\n-\t\toutput(opt, 1, _(\"Error: Refusing to lose untracked file at %s; \"\n-\t\t\t\t \"writing to %s instead.\"),\n-\t\t       dest->path, file_path);\n-\t}\n-\n-\tif (mark_conflicted) {\n-\t\t/*\n-\t\t * Write the file in worktree at file_path.  In the index,\n-\t\t * only record the file at dest->path in the appropriate\n-\t\t * higher stage.\n-\t\t */\n-\t\tif (update_file(opt, 0, dest, file_path))\n-\t\t\treturn -1;\n-\t\tif (file_path != dest->path)\n-\t\t\tfree(file_path);\n-\t\tif (update_stages(opt, dest->path, NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? NULL : dest))\n-\t\t\treturn -1;\n-\t\treturn 0; /* not clean, but conflicted */\n-\t} else {\n-\t\t/* Update dest->path both in index and in worktree */\n-\t\tif (update_file(opt, 1, dest, dest->path))\n-\t\t\treturn -1;\n-\t\treturn 1; /* clean */\n-\t}\n-}\n-\n-static int handle_change_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path, const char *old_path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *changed,\n-\t\t\t\tconst char *change_branch,\n-\t\t\t\tconst char *delete_branch,\n-\t\t\t\tconst char *change, const char *change_past)\n-{\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = path;\n-\tint ret = 0;\n-\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0) ||\n-\t    (!opt->priv->call_depth && would_lose_untracked(opt, path))) {\n-\t\tupdate_path = alt_path = unique_path(opt, path, change_branch);\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t/*\n-\t\t * We cannot arbitrarily accept either a_sha or b_sha as\n-\t\t * correct; since there is no true \"middle point\" between\n-\t\t * them, simply reuse the base version for virtual merge base.\n-\t\t */\n-\t\tret = remove_file_from_index(opt->repo->index, path);\n-\t\tif (!ret)\n-\t\t\tret = update_file(opt, 0, o, update_path);\n-\t} else {\n-\t\t/*\n-\t\t * Despite the four nearly duplicate messages and argument\n-\t\t * lists below and the ugliness of the nested if-statements,\n-\t\t * having complete messages makes the job easier for\n-\t\t * translators.\n-\t\t *\n-\t\t * The slight variance among the cases is due to the fact\n-\t\t * that:\n-\t\t *   1) directory/file conflicts (in effect if\n-\t\t *      !alt_path) could cause us to need to write the\n-\t\t *      file to a different path.\n-\t\t *   2) renames (in effect if !old_path) could mean that\n-\t\t *      there are two names for the path that the user\n-\t\t *      may know the file by.\n-\t\t */\n-\t\tif (!alt_path) {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t}\n-\t\t}\n-\t\t/*\n-\t\t * No need to call update_file() on path when change_branch ==\n-\t\t * opt->branch1 && !alt_path, since that would needlessly touch\n-\t\t * path.  We could call update_file_flags() with update_cache=0\n-\t\t * and update_wd=0, but that's a no-op.\n-\t\t */\n-\t\tif (change_branch != opt->branch1 || alt_path)\n-\t\t\tret = update_file(opt, 0, changed, update_path);\n-\t}\n-\tfree(alt_path);\n-\n-\treturn ret;\n-}\n-\n-static int handle_rename_delete(struct merge_options *opt,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *orig = ren->pair->one;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tconst char *rename_branch = ren->branch;\n-\tconst char *delete_branch = (opt->branch1 == ren->branch ?\n-\t\t\t\t     opt->branch2 : opt->branch1);\n-\n-\tif (handle_change_delete(opt,\n-\t\t\t\t opt->priv->call_depth ? orig->path : dest->path,\n-\t\t\t\t opt->priv->call_depth ? NULL : orig->path,\n-\t\t\t\t orig, dest,\n-\t\t\t\t rename_branch, delete_branch,\n-\t\t\t\t _(\"rename\"), _(\"renamed\")))\n-\t\treturn -1;\n-\n-\tif (opt->priv->call_depth)\n-\t\treturn remove_file_from_index(opt->repo->index, dest->path);\n-\telse\n-\t\treturn update_stages(opt, dest->path, NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? NULL : dest);\n-}\n-\n-static int handle_file_collision(struct merge_options *opt,\n-\t\t\t\t const char *collide_path,\n-\t\t\t\t const char *prev_path1,\n-\t\t\t\t const char *prev_path2,\n-\t\t\t\t const char *branch1, const char *branch2,\n-\t\t\t\t struct diff_filespec *a,\n-\t\t\t\t struct diff_filespec *b)\n-{\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec null;\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = collide_path;\n-\n-\t/*\n-\t * It's easiest to get the correct things into stage 2 and 3, and\n-\t * to make sure that the content merge puts HEAD before the other\n-\t * branch if we just ensure that branch1 == opt->branch1.  So, simply\n-\t * flip arguments around if we don't have that.\n-\t */\n-\tif (branch1 != opt->branch1) {\n-\t\treturn handle_file_collision(opt, collide_path,\n-\t\t\t\t\t     prev_path2, prev_path1,\n-\t\t\t\t\t     branch2, branch1,\n-\t\t\t\t\t     b, a);\n-\t}\n-\n-\t/* Remove rename sources if rename/add or rename/rename(2to1) */\n-\tif (prev_path1)\n-\t\tremove_file(opt, 1, prev_path1,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path1));\n-\tif (prev_path2)\n-\t\tremove_file(opt, 1, prev_path2,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path2));\n-\n-\t/*\n-\t * Remove the collision path, if it wouldn't cause dirty contents\n-\t * or an untracked file to get lost.  We'll either overwrite with\n-\t * merged contents, or just write out to differently named files.\n-\t */\n-\tif (was_dirty(opt, collide_path)) {\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else if (would_lose_untracked(opt, collide_path)) {\n-\t\t/*\n-\t\t * Only way we get here is if both renames were from\n-\t\t * a directory rename AND user had an untracked file\n-\t\t * at the location where both files end up after the\n-\t\t * two directory renames.  See testcase 10d of t6043.\n-\t\t */\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file at \"\n-\t\t\t       \"%s, even though it's in the way.\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else {\n-\t\t/*\n-\t\t * FIXME: It's possible that the two files are identical\n-\t\t * and that the current working copy happens to match, in\n-\t\t * which case we are unnecessarily touching the working\n-\t\t * tree file.  It's not a likely enough scenario that I\n-\t\t * want to code up the checks for it and a better fix is\n-\t\t * available if we restructure how unpack_trees() and\n-\t\t * merge-recursive interoperate anyway, so punting for\n-\t\t * now...\n-\t\t */\n-\t\tremove_file(opt, 0, collide_path, 0);\n-\t}\n-\n-\t/* Store things in diff_filespecs for functions that need it */\n-\tnull.path = (char *)collide_path;\n-\toidcpy(&null.oid, null_oid());\n-\tnull.mode = 0;\n-\n-\tif (merge_mode_and_contents(opt, &null, a, b, collide_path,\n-\t\t\t\t    branch1, branch2, opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tmfi.clean &= !alt_path;\n-\tif (update_file(opt, mfi.clean, &mfi.blob, update_path))\n-\t\treturn -1;\n-\tif (!mfi.clean && !opt->priv->call_depth &&\n-\t    update_stages(opt, collide_path, NULL, a, b))\n-\t\treturn -1;\n-\tfree(alt_path);\n-\t/*\n-\t * FIXME: If both a & b both started with conflicts (only possible\n-\t * if they came from a rename/rename(2to1)), but had IDENTICAL\n-\t * contents including those conflicts, then in the next line we claim\n-\t * it was clean.  If someone cares about this case, we should have the\n-\t * caller notify us if we started with conflicts.\n-\t */\n-\treturn mfi.clean;\n-}\n-\n-static int handle_rename_add(struct merge_options *opt,\n-\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* a was renamed to c, and a separate c was added. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *c = ci->ren1->pair->two;\n-\tchar *path = c->path;\n-\tchar *prev_path_desc;\n-\tstruct merge_file_info mfi;\n-\n-\tconst char *rename_branch = ci->ren1->branch;\n-\tconst char *add_branch = (opt->branch1 == rename_branch ?\n-\t\t\t\t  opt->branch2 : opt->branch1);\n-\tint other_stage = (ci->ren1->branch == opt->branch1 ? 3 : 2);\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/add): \"\n-\t       \"Rename %s->%s in %s.  Added %s in %s\"),\n-\t       a->path, c->path, rename_branch,\n-\t       c->path, add_branch);\n-\n-\tprev_path_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tci->ren1->src_entry->stages[other_stage].path = a->path;\n-\tif (merge_mode_and_contents(opt, a, c,\n-\t\t\t\t    &ci->ren1->src_entry->stages[other_stage],\n-\t\t\t\t    prev_path_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(prev_path_desc);\n-\n-\tci->ren1->dst_entry->stages[other_stage].path = mfi.blob.path = c->path;\n-\treturn handle_file_collision(opt,\n-\t\t\t\t     c->path, a->path, NULL,\n-\t\t\t\t     rename_branch, add_branch,\n-\t\t\t\t     &mfi.blob,\n-\t\t\t\t     &ci->ren1->dst_entry->stages[other_stage]);\n-}\n-\n-static char *find_path_for_conflict(struct merge_options *opt,\n-\t\t\t\t    const char *path,\n-\t\t\t\t    const char *branch1,\n-\t\t\t\t    const char *branch2)\n-{\n-\tchar *new_path = NULL;\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"%s is a directory in %s adding \"\n-\t\t\t       \"as %s instead\"),\n-\t\t       path, branch2, new_path);\n-\t} else if (would_lose_untracked(opt, path)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file\"\n-\t\t\t       \" at %s; adding as %s instead\"),\n-\t\t       path, new_path);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * Toggle the stage number between \"ours\" and \"theirs\" (2 and 3).\n- */\n-static inline int flip_stage(int stage)\n-{\n-\treturn (2 + 3) - stage;\n-}\n-\n-static int handle_rename_rename_1to2(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* One file was renamed in both branches, but to different names. */\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec *add;\n-\tstruct diff_filespec *o = ci->ren1->pair->one;\n-\tstruct diff_filespec *a = ci->ren1->pair->two;\n-\tstruct diff_filespec *b = ci->ren2->pair->two;\n-\tchar *path_desc;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename \\\"%s\\\"->\\\"%s\\\" in branch \\\"%s\\\" \"\n-\t       \"rename \\\"%s\\\"->\\\"%s\\\" in \\\"%s\\\"%s\"),\n-\t       o->path, a->path, ci->ren1->branch,\n-\t       o->path, b->path, ci->ren2->branch,\n-\t       opt->priv->call_depth ? _(\" (left unresolved)\") : \"\");\n-\n-\tpath_desc = xstrfmt(\"%s and %s, both renamed from %s\",\n-\t\t\t    a->path, b->path, o->path);\n-\tif (merge_mode_and_contents(opt, o, a, b, path_desc,\n-\t\t\t\t    ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t    opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(path_desc);\n-\n-\tif (opt->priv->call_depth)\n-\t\tremove_file_from_index(opt->repo->index, o->path);\n-\n-\t/*\n-\t * For each destination path, we need to see if there is a\n-\t * rename/add collision.  If not, we can write the file out\n-\t * to the specified location.\n-\t */\n-\tadd = &ci->ren1->dst_entry->stages[flip_stage(2)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = a->path;\n-\t\tif (handle_file_collision(opt, a->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  &mfi.blob, add) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, a->path,\n-\t\t\t\t\t\t\tci->ren1->branch,\n-\t\t\t\t\t\t\tci->ren2->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : a->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, a->path, NULL, a, NULL))\n-\t\t\treturn -1;\n-\t}\n-\n-\tif (!mfi.clean && mfi.blob.mode == a->mode &&\n-\t    oideq(&mfi.blob.oid, &a->oid)) {\n-\t\t/*\n-\t\t * Getting here means we were attempting to merge a binary\n-\t\t * blob.  Since we can't merge binaries, the merge algorithm\n-\t\t * just takes one side.  But we don't want to copy the\n-\t\t * contents of one side to both paths; we'd rather use the\n-\t\t * original content at the given path for each path.\n-\t\t */\n-\t\toidcpy(&mfi.blob.oid, &b->oid);\n-\t\tmfi.blob.mode = b->mode;\n-\t}\n-\tadd = &ci->ren2->dst_entry->stages[flip_stage(3)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = b->path;\n-\t\tif (handle_file_collision(opt, b->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  add, &mfi.blob) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, b->path,\n-\t\t\t\t\t\t\tci->ren2->branch,\n-\t\t\t\t\t\t\tci->ren1->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : b->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, b->path, NULL, NULL, b))\n-\t\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_rename_2to1(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* Two files, a & b, were renamed to the same thing, c. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *b = ci->ren2->pair->one;\n-\tstruct diff_filespec *c1 = ci->ren1->pair->two;\n-\tstruct diff_filespec *c2 = ci->ren2->pair->two;\n-\tchar *path = c1->path; /* == c2->path */\n-\tchar *path_side_1_desc;\n-\tchar *path_side_2_desc;\n-\tstruct merge_file_info mfi_c1;\n-\tstruct merge_file_info mfi_c2;\n-\tint ostage1, ostage2;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename %s->%s in %s. \"\n-\t       \"Rename %s->%s in %s\"),\n-\t       a->path, c1->path, ci->ren1->branch,\n-\t       b->path, c2->path, ci->ren2->branch);\n-\n-\tpath_side_1_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tpath_side_2_desc = xstrfmt(\"version of %s from %s\", path, b->path);\n-\tostage1 = ci->ren1->branch == opt->branch1 ? 3 : 2;\n-\tostage2 = flip_stage(ostage1);\n-\tci->ren1->src_entry->stages[ostage1].path = a->path;\n-\tci->ren2->src_entry->stages[ostage2].path = b->path;\n-\tif (merge_mode_and_contents(opt, a, c1,\n-\t\t\t\t    &ci->ren1->src_entry->stages[ostage1],\n-\t\t\t\t    path_side_1_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c1) ||\n-\t    merge_mode_and_contents(opt, b,\n-\t\t\t\t    &ci->ren2->src_entry->stages[ostage2],\n-\t\t\t\t    c2, path_side_2_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c2))\n-\t\treturn -1;\n-\tfree(path_side_1_desc);\n-\tfree(path_side_2_desc);\n-\tmfi_c1.blob.path = path;\n-\tmfi_c2.blob.path = path;\n-\n-\treturn handle_file_collision(opt, path, a->path, b->path,\n-\t\t\t\t     ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t     &mfi_c1.blob, &mfi_c2.blob);\n-}\n-\n-/*\n- * Get the diff_filepairs changed between o_tree and tree.\n- */\n-static struct diff_queue_struct *get_diffpairs(struct merge_options *opt,\n-\t\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t\t       struct tree *tree)\n-{\n-\tstruct diff_queue_struct *ret;\n-\tstruct diff_options opts;\n-\n-\trepo_diff_setup(opt->repo, &opts);\n-\topts.flags.recursive = 1;\n-\topts.flags.rename_empty = 0;\n-\topts.detect_rename = merge_detect_rename(opt);\n-\t/*\n-\t * We do not have logic to handle the detection of copies.  In\n-\t * fact, it may not even make sense to add such logic: would we\n-\t * really want a change to a base file to be propagated through\n-\t * multiple other files by a merge?\n-\t */\n-\tif (opts.detect_rename > DIFF_DETECT_RENAME)\n-\t\topts.detect_rename = DIFF_DETECT_RENAME;\n-\topts.rename_limit = (opt->rename_limit >= 0) ? opt->rename_limit : 7000;\n-\topts.rename_score = opt->rename_score;\n-\topts.show_rename_progress = opt->show_rename_progress;\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_setup_done(&opts);\n-\tdiff_tree_oid(&o_tree->object.oid, &tree->object.oid, \"\", &opts);\n-\tdiffcore_std(&opts);\n-\tif (opts.needed_rename_limit > opt->priv->needed_rename_limit)\n-\t\topt->priv->needed_rename_limit = opts.needed_rename_limit;\n-\n-\tret = xmalloc(sizeof(*ret));\n-\t*ret = diff_queued_diff;\n-\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_queued_diff.nr = 0;\n-\tdiff_queued_diff.queue = NULL;\n-\tdiff_flush(&opts);\n-\treturn ret;\n-}\n-\n-static int tree_has_path(struct repository *r, struct tree *tree,\n-\t\t\t const char *path)\n-{\n-\tstruct object_id hashy;\n-\tunsigned short mode_o;\n-\n-\treturn !get_tree_entry(r,\n-\t\t\t       &tree->object.oid, path,\n-\t\t\t       &hashy, &mode_o);\n-}\n-\n-/*\n- * Return a new string that replaces the beginning portion (which matches\n- * entry->dir), with entry->new_dir.  In perl-speak:\n- *   new_path_name = (old_path =~ s/entry->dir/entry->new_dir/);\n- * NOTE:\n- *   Caller must ensure that old_path starts with entry->dir + '/'.\n- */\n-static char *apply_dir_rename(struct dir_rename_entry *entry,\n-\t\t\t      const char *old_path)\n-{\n-\tstruct strbuf new_path = STRBUF_INIT;\n-\tint oldlen, newlen;\n-\n-\tif (entry->non_unique_new_dir)\n-\t\treturn NULL;\n-\n-\toldlen = strlen(entry->dir);\n-\tif (entry->new_dir.len == 0)\n-\t\t/*\n-\t\t * If someone renamed/merged a subdirectory into the root\n-\t\t * directory (e.g. 'some/subdir' -> ''), then we want to\n-\t\t * avoid returning\n-\t\t *     '' + '/filename'\n-\t\t * as the rename; we need to make old_path + oldlen advance\n-\t\t * past the '/' character.\n-\t\t */\n-\t\toldlen++;\n-\tnewlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;\n-\tstrbuf_grow(&new_path, newlen);\n-\tstrbuf_addbuf(&new_path, &entry->new_dir);\n-\tstrbuf_addstr(&new_path, &old_path[oldlen]);\n-\n-\treturn strbuf_detach(&new_path, NULL);\n-}\n-\n-static void get_renamed_dir_portion(const char *old_path, const char *new_path,\n-\t\t\t\t    char **old_dir, char **new_dir)\n-{\n-\tchar *end_of_old, *end_of_new;\n-\n-\t/* Default return values: NULL, meaning no rename */\n-\t*old_dir = NULL;\n-\t*new_dir = NULL;\n-\n-\t/*\n-\t * For\n-\t *    \"a/b/c/d/e/foo.c\" -> \"a/b/some/thing/else/e/foo.c\"\n-\t * the \"e/foo.c\" part is the same, we just want to know that\n-\t *    \"a/b/c/d\" was renamed to \"a/b/some/thing/else\"\n-\t * so, for this example, this function returns \"a/b/c/d\" in\n-\t * *old_dir and \"a/b/some/thing/else\" in *new_dir.\n-\t */\n-\n-\t/*\n-\t * If the basename of the file changed, we don't care.  We want\n-\t * to know which portion of the directory, if any, changed.\n-\t */\n-\tend_of_old = strrchr(old_path, '/');\n-\tend_of_new = strrchr(new_path, '/');\n-\n-\t/*\n-\t * If end_of_old is NULL, old_path wasn't in a directory, so there\n-\t * could not be a directory rename (our rule elsewhere that a\n-\t * directory which still exists is not considered to have been\n-\t * renamed means the root directory can never be renamed -- because\n-\t * the root directory always exists).\n-\t */\n-\tif (!end_of_old)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If new_path contains no directory (end_of_new is NULL), then we\n-\t * have a rename of old_path's directory to the root directory.\n-\t */\n-\tif (!end_of_new) {\n-\t\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/* Find the first non-matching character traversing backwards */\n-\twhile (*--end_of_new == *--end_of_old &&\n-\t       end_of_old != old_path &&\n-\t       end_of_new != new_path)\n-\t\t; /* Do nothing; all in the while loop */\n-\n-\t/*\n-\t * If both got back to the beginning of their strings, then the\n-\t * directory didn't change at all, only the basename did.\n-\t */\n-\tif (end_of_old == old_path && end_of_new == new_path &&\n-\t    *end_of_old == *end_of_new)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If end_of_new got back to the beginning of its string, and\n-\t * end_of_old got back to the beginning of some subdirectory, then\n-\t * we have a rename/merge of a subdirectory into the root, which\n-\t * needs slightly special handling.\n-\t *\n-\t * Note: There is no need to consider the opposite case, with a\n-\t * rename/merge of the root directory into some subdirectory\n-\t * because as noted above the root directory always exists so it\n-\t * cannot be considered to be renamed.\n-\t */\n-\tif (end_of_new == new_path &&\n-\t    end_of_old != old_path && end_of_old[-1] == '/') {\n-\t\t*old_dir = xstrndup(old_path, --end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * We've found the first non-matching character in the directory\n-\t * paths.  That means the current characters we were looking at\n-\t * were part of the first non-matching subdir name going back from\n-\t * the end of the strings.  Get the whole name by advancing both\n-\t * end_of_old and end_of_new to the NEXT '/' character.  That will\n-\t * represent the entire directory rename.\n-\t *\n-\t * The reason for the increment is cases like\n-\t *    a/b/star/foo/whatever.c -> a/b/tar/foo/random.c\n-\t * After dropping the basename and going back to the first\n-\t * non-matching character, we're now comparing:\n-\t *    a/b/s          and         a/b/\n-\t * and we want to be comparing:\n-\t *    a/b/star/      and         a/b/tar/\n-\t * but without the pre-increment, the one on the right would stay\n-\t * a/b/.\n-\t */\n-\tend_of_old = strchr(++end_of_old, '/');\n-\tend_of_new = strchr(++end_of_new, '/');\n-\n-\t/* Copy the old and new directories into *old_dir and *new_dir. */\n-\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t*new_dir = xstrndup(new_path, end_of_new - new_path);\n-}\n-\n-static void remove_hashmap_entries(struct hashmap *dir_renames,\n-\t\t\t\t   struct string_list *items_to_remove)\n-{\n-\tint i;\n-\tstruct dir_rename_entry *entry;\n-\n-\tfor (i = 0; i < items_to_remove->nr; i++) {\n-\t\tentry = items_to_remove->items[i].util;\n-\t\thashmap_remove(dir_renames, &entry->ent, NULL);\n-\t}\n-\tstring_list_clear(items_to_remove, 0);\n-}\n-\n-/*\n- * See if there is a directory rename for path, and if there are any file\n- * level conflicts for the renamed location.  If there is a rename and\n- * there are no conflicts, return the new name.  Otherwise, return NULL.\n- */\n-static char *handle_path_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t const char *path,\n-\t\t\t\t\t struct dir_rename_entry *entry,\n-\t\t\t\t\t struct hashmap *collisions,\n-\t\t\t\t\t struct tree *tree)\n-{\n-\tchar *new_path = NULL;\n-\tstruct collision_entry *collision_ent;\n-\tint clean = 1;\n-\tstruct strbuf collision_paths = STRBUF_INIT;\n-\n-\t/*\n-\t * entry has the mapping of old directory name to new directory name\n-\t * that we want to apply to path.\n-\t */\n-\tnew_path = apply_dir_rename(entry, path);\n-\n-\tif (!new_path) {\n-\t\t/* This should only happen when entry->non_unique_new_dir set */\n-\t\tif (!entry->non_unique_new_dir)\n-\t\t\tBUG(\"entry->non_unique_new_dir not set and !new_path\");\n-\t\toutput(opt, 1, _(\"CONFLICT (directory rename split): \"\n-\t\t\t       \"Unclear where to place %s because directory \"\n-\t\t\t       \"%s was renamed to multiple other directories, \"\n-\t\t\t       \"with no destination getting a majority of the \"\n-\t\t\t       \"files.\"),\n-\t\t       path, entry->dir);\n-\t\tclean = 0;\n-\t\treturn NULL;\n-\t}\n-\n-\t/*\n-\t * The caller needs to have ensured that it has pre-populated\n-\t * collisions with all paths that map to new_path.  Do a quick check\n-\t * to ensure that's the case.\n-\t */\n-\tcollision_ent = collision_find_entry(collisions, new_path);\n-\tif (!collision_ent)\n-\t\tBUG(\"collision_ent is NULL\");\n-\n-\t/*\n-\t * Check for one-sided add/add/.../add conflicts, i.e.\n-\t * where implicit renames from the other side doing\n-\t * directory rename(s) can affect this side of history\n-\t * to put multiple paths into the same location.  Warn\n-\t * and bail on directory renames for such paths.\n-\t */\n-\tif (collision_ent->reported_already) {\n-\t\tclean = 0;\n-\t} else if (tree_has_path(opt->repo, tree, new_path)) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Existing \"\n-\t\t\t       \"file/dir at %s in the way of implicit \"\n-\t\t\t       \"directory rename(s) putting the following \"\n-\t\t\t       \"path(s) there: %s.\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t} else if (collision_ent->source_files.nr > 1) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Cannot map \"\n-\t\t\t       \"more than one path to %s; implicit directory \"\n-\t\t\t       \"renames tried to put these paths there: %s\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t}\n-\n-\t/* Free memory we no longer need */\n-\tstrbuf_release(&collision_paths);\n-\tif (!clean && new_path) {\n-\t\tfree(new_path);\n-\t\treturn NULL;\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * There are a couple things we want to do at the directory level:\n- *   1. Check for both sides renaming to the same thing, in order to avoid\n- *      implicit renaming of files that should be left in place.  (See\n- *      testcase 6b in t6043 for details.)\n- *   2. Prune directory renames if there are still files left in the\n- *      original directory.  These represent a partial directory rename,\n- *      i.e. a rename where only some of the files within the directory\n- *      were renamed elsewhere.  (Technically, this could be done earlier\n- *      in get_directory_renames(), except that would prevent us from\n- *      doing the previous check and thus failing testcase 6b.)\n- *   3. Check for rename/rename(1to2) conflicts (at the directory level).\n- *      In the future, we could potentially record this info as well and\n- *      omit reporting rename/rename(1to2) conflicts for each path within\n- *      the affected directories, thus cleaning up the merge output.\n- *   NOTE: We do NOT check for rename/rename(2to1) conflicts at the\n- *         directory level, because merging directories is fine.  If it\n- *         causes conflicts for files within those merged directories, then\n- *         that should be detected at the individual path level.\n- */\n-static void handle_directory_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t     struct hashmap *dir_re_head,\n-\t\t\t\t\t     struct tree *head,\n-\t\t\t\t\t     struct hashmap *dir_re_merge,\n-\t\t\t\t\t     struct tree *merge)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *head_ent;\n-\tstruct dir_rename_entry *merge_ent;\n-\n-\tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n-\tstruct string_list remove_from_merge = STRING_LIST_INIT_NODUP;\n-\n-\thashmap_for_each_entry(dir_re_head, &iter, head_ent,\n-\t\t\t\tent /* member name */) {\n-\t\tmerge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);\n-\t\tif (merge_ent &&\n-\t\t    !head_ent->non_unique_new_dir &&\n-\t\t    !merge_ent->non_unique_new_dir &&\n-\t\t    !strbuf_cmp(&head_ent->new_dir, &merge_ent->new_dir)) {\n-\t\t\t/* 1. Renamed identically; remove it from both sides */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t} else if (tree_has_path(opt->repo, head, head_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-\n-\thashmap_for_each_entry(dir_re_merge, &iter, merge_ent,\n-\t\t\t\tent /* member name */) {\n-\t\thead_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);\n-\t\tif (tree_has_path(opt->repo, merge, merge_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t} else if (head_ent &&\n-\t\t\t   !head_ent->non_unique_new_dir &&\n-\t\t\t   !merge_ent->non_unique_new_dir) {\n-\t\t\t/* 3. rename/rename(1to2) */\n-\t\t\t/*\n-\t\t\t * We can assume it's not rename/rename(1to1) because\n-\t\t\t * that was case (1), already checked above.  So we\n-\t\t\t * know that head_ent->new_dir and merge_ent->new_dir\n-\t\t\t * are different strings.\n-\t\t\t */\n-\t\t\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t\t\t\t       \"Rename directory %s->%s in %s. \"\n-\t\t\t\t       \"Rename directory %s->%s in %s\"),\n-\t\t\t       head_ent->dir, head_ent->new_dir.buf, opt->branch1,\n-\t\t\t       head_ent->dir, merge_ent->new_dir.buf, opt->branch2);\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-}\n-\n-static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n-{\n-\tstruct hashmap *dir_renames;\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *entry;\n-\tint i;\n-\n-\t/*\n-\t * Typically, we think of a directory rename as all files from a\n-\t * certain directory being moved to a target directory.  However,\n-\t * what if someone first moved two files from the original\n-\t * directory in one commit, and then renamed the directory\n-\t * somewhere else in a later commit?  At merge time, we just know\n-\t * that files from the original directory went to two different\n-\t * places, and that the bulk of them ended up in the same place.\n-\t * We want each directory rename to represent where the bulk of the\n-\t * files from that directory end up; this function exists to find\n-\t * where the bulk of the files went.\n-\t *\n-\t * The first loop below simply iterates through the list of file\n-\t * renames, finding out how often each directory rename pair\n-\t * possibility occurs.\n-\t */\n-\tdir_renames = xmalloc(sizeof(*dir_renames));\n-\tdir_rename_init(dir_renames);\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tint *count;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *old_dir, *new_dir;\n-\n-\t\t/* File not part of directory rename if it wasn't renamed */\n-\t\tif (pair->status != 'R')\n-\t\t\tcontinue;\n-\n-\t\tget_renamed_dir_portion(pair->one->path, pair->two->path,\n-\t\t\t\t\t&old_dir,        &new_dir);\n-\t\tif (!old_dir)\n-\t\t\t/* Directory didn't change at all; ignore this one. */\n-\t\t\tcontinue;\n-\n-\t\tentry = dir_rename_find_entry(dir_renames, old_dir);\n-\t\tif (!entry) {\n-\t\t\tentry = xmalloc(sizeof(*entry));\n-\t\t\tdir_rename_entry_init(entry, old_dir);\n-\t\t\thashmap_put(dir_renames, &entry->ent);\n-\t\t} else {\n-\t\t\tfree(old_dir);\n-\t\t}\n-\t\titem = string_list_lookup(&entry->possible_new_dirs, new_dir);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(&entry->possible_new_dirs,\n-\t\t\t\t\t\t  new_dir);\n-\t\t\titem->util = xcalloc(1, sizeof(int));\n-\t\t} else {\n-\t\t\tfree(new_dir);\n-\t\t}\n-\t\tcount = item->util;\n-\t\t*count += 1;\n-\t}\n-\n-\t/*\n-\t * For each directory with files moved out of it, we find out which\n-\t * target directory received the most files so we can declare it to\n-\t * be the \"winning\" target location for the directory rename.  This\n-\t * winner gets recorded in new_dir.  If there is no winner\n-\t * (multiple target directories received the same number of files),\n-\t * we set non_unique_new_dir.  Once we've determined the winner (or\n-\t * that there is no winner), we no longer need possible_new_dirs.\n-\t */\n-\thashmap_for_each_entry(dir_renames, &iter, entry,\n-\t\t\t\tent /* member name */) {\n-\t\tint max = 0;\n-\t\tint bad_max = 0;\n-\t\tchar *best = NULL;\n-\n-\t\tfor (i = 0; i < entry->possible_new_dirs.nr; i++) {\n-\t\t\tint *count = entry->possible_new_dirs.items[i].util;\n-\n-\t\t\tif (*count == max)\n-\t\t\t\tbad_max = max;\n-\t\t\telse if (*count > max) {\n-\t\t\t\tmax = *count;\n-\t\t\t\tbest = entry->possible_new_dirs.items[i].string;\n-\t\t\t}\n-\t\t}\n-\t\tif (bad_max == max)\n-\t\t\tentry->non_unique_new_dir = 1;\n-\t\telse {\n-\t\t\tassert(entry->new_dir.len == 0);\n-\t\t\tstrbuf_addstr(&entry->new_dir, best);\n-\t\t}\n-\t\t/*\n-\t\t * The relevant directory sub-portion of the original full\n-\t\t * filepaths were xstrndup'ed before inserting into\n-\t\t * possible_new_dirs, and instead of manually iterating the\n-\t\t * list and free'ing each, just lie and tell\n-\t\t * possible_new_dirs that it did the strdup'ing so that it\n-\t\t * will free them for us.\n-\t\t */\n-\t\tentry->possible_new_dirs.strdup_strings = 1;\n-\t\tstring_list_clear(&entry->possible_new_dirs, 1);\n-\t}\n-\n-\treturn dir_renames;\n-}\n-\n-static struct dir_rename_entry *check_dir_renamed(const char *path,\n-\t\t\t\t\t\t  struct hashmap *dir_renames)\n-{\n-\tchar *temp = xstrdup(path);\n-\tchar *end;\n-\tstruct dir_rename_entry *entry = NULL;\n-\n-\twhile ((end = strrchr(temp, '/'))) {\n-\t\t*end = '\\0';\n-\t\tentry = dir_rename_find_entry(dir_renames, temp);\n-\t\tif (entry)\n-\t\t\tbreak;\n-\t}\n-\tfree(temp);\n-\treturn entry;\n-}\n-\n-static void compute_collisions(struct hashmap *collisions,\n-\t\t\t       struct hashmap *dir_renames,\n-\t\t\t       struct diff_queue_struct *pairs)\n-{\n-\tint i;\n-\n-\t/*\n-\t * Multiple files can be mapped to the same path due to directory\n-\t * renames done by the other side of history.  Since that other\n-\t * side of history could have merged multiple directories into one,\n-\t * if our side of history added the same file basename to each of\n-\t * those directories, then all N of them would get implicitly\n-\t * renamed by the directory rename detection into the same path,\n-\t * and we'd get an add/add/.../add conflict, and all those adds\n-\t * from *this* side of history.  This is not representable in the\n-\t * index, and users aren't going to easily be able to make sense of\n-\t * it.  So we need to provide a good warning about what's\n-\t * happening, and fall back to no-directory-rename detection\n-\t * behavior for those paths.\n-\t *\n-\t * See testcases 9e and all of section 5 from t6043 for examples.\n-\t */\n-\tcollision_init(collisions);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct dir_rename_entry *dir_rename_ent;\n-\t\tstruct collision_entry *collision_ent;\n-\t\tchar *new_path;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R')\n-\t\t\tcontinue;\n-\t\tdir_rename_ent = check_dir_renamed(pair->two->path,\n-\t\t\t\t\t\t   dir_renames);\n-\t\tif (!dir_rename_ent)\n-\t\t\tcontinue;\n-\n-\t\tnew_path = apply_dir_rename(dir_rename_ent, pair->two->path);\n-\t\tif (!new_path)\n-\t\t\t/*\n-\t\t\t * dir_rename_ent->non_unique_new_path is true, which\n-\t\t\t * means there is no directory rename for us to use,\n-\t\t\t * which means it won't cause us any additional\n-\t\t\t * collisions.\n-\t\t\t */\n-\t\t\tcontinue;\n-\t\tcollision_ent = collision_find_entry(collisions, new_path);\n-\t\tif (!collision_ent) {\n-\t\t\tCALLOC_ARRAY(collision_ent, 1);\n-\t\t\thashmap_entry_init(&collision_ent->ent,\n-\t\t\t\t\t\tstrhash(new_path));\n-\t\t\thashmap_put(collisions, &collision_ent->ent);\n-\t\t\tcollision_ent->target_file = new_path;\n-\t\t} else {\n-\t\t\tfree(new_path);\n-\t\t}\n-\t\tstring_list_insert(&collision_ent->source_files,\n-\t\t\t\t   pair->two->path);\n-\t}\n-}\n-\n-static char *check_for_directory_rename(struct merge_options *opt,\n-\t\t\t\t\tconst char *path,\n-\t\t\t\t\tstruct tree *tree,\n-\t\t\t\t\tstruct hashmap *dir_renames,\n-\t\t\t\t\tstruct hashmap *dir_rename_exclusions,\n-\t\t\t\t\tstruct hashmap *collisions,\n-\t\t\t\t\tint *clean_merge)\n-{\n-\tchar *new_path = NULL;\n-\tstruct dir_rename_entry *entry = check_dir_renamed(path, dir_renames);\n-\tstruct dir_rename_entry *oentry = NULL;\n-\n-\tif (!entry)\n-\t\treturn new_path;\n-\n-\t/*\n-\t * This next part is a little weird.  We do not want to do an\n-\t * implicit rename into a directory we renamed on our side, because\n-\t * that will result in a spurious rename/rename(1to2) conflict.  An\n-\t * example:\n-\t *   Base commit: dumbdir/afile, otherdir/bfile\n-\t *   Side 1:      smrtdir/afile, otherdir/bfile\n-\t *   Side 2:      dumbdir/afile, dumbdir/bfile\n-\t * Here, while working on Side 1, we could notice that otherdir was\n-\t * renamed/merged to dumbdir, and change the diff_filepair for\n-\t * otherdir/bfile into a rename into dumbdir/bfile.  However, Side\n-\t * 2 will notice the rename from dumbdir to smrtdir, and do the\n-\t * transitive rename to move it from dumbdir/bfile to\n-\t * smrtdir/bfile.  That gives us bfile in dumbdir vs being in\n-\t * smrtdir, a rename/rename(1to2) conflict.  We really just want\n-\t * the file to end up in smrtdir.  And the way to achieve that is\n-\t * to not let Side1 do the rename to dumbdir, since we know that is\n-\t * the source of one of our directory renames.\n-\t *\n-\t * That's why oentry and dir_rename_exclusions is here.\n-\t *\n-\t * As it turns out, this also prevents N-way transient rename\n-\t * confusion; See testcases 9c and 9d of t6043.\n-\t */\n-\toentry = dir_rename_find_entry(dir_rename_exclusions, entry->new_dir.buf);\n-\tif (oentry) {\n-\t\toutput(opt, 1, _(\"WARNING: Avoiding applying %s -> %s rename \"\n-\t\t\t       \"to %s, because %s itself was renamed.\"),\n-\t\t       entry->dir, entry->new_dir.buf, path, entry->new_dir.buf);\n-\t} else {\n-\t\tnew_path = handle_path_level_conflicts(opt, path, entry,\n-\t\t\t\t\t\t       collisions, tree);\n-\t\t*clean_merge &= (new_path != NULL);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-static void apply_directory_rename_modifications(struct merge_options *opt,\n-\t\t\t\t\t\t struct diff_filepair *pair,\n-\t\t\t\t\t\t char *new_path,\n-\t\t\t\t\t\t struct rename *re,\n-\t\t\t\t\t\t struct tree *tree,\n-\t\t\t\t\t\t struct tree *o_tree,\n-\t\t\t\t\t\t struct tree *a_tree,\n-\t\t\t\t\t\t struct tree *b_tree,\n-\t\t\t\t\t\t struct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tint stage = (tree == a_tree ? 2 : 3);\n-\tint update_wd;\n-\n-\t/*\n-\t * In all cases where we can do directory rename detection,\n-\t * unpack_trees() will have read pair->two->path into the\n-\t * index and the working copy.  We need to remove it so that\n-\t * we can instead place it at new_path.  It is guaranteed to\n-\t * not be untracked (unpack_trees() would have errored out\n-\t * saying the file would have been overwritten), but it might\n-\t * be dirty, though.\n-\t */\n-\tupdate_wd = !was_dirty(opt, pair->two->path);\n-\tif (!update_wd)\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       pair->two->path);\n-\tremove_file(opt, 1, pair->two->path, !update_wd);\n-\n-\t/* Find or create a new re->dst_entry */\n-\titem = string_list_lookup(entries, new_path);\n-\tif (item) {\n-\t\t/*\n-\t\t * Since we're renaming on this side of history, and it's\n-\t\t * due to a directory rename on the other side of history\n-\t\t * (which we only allow when the directory in question no\n-\t\t * longer exists on the other side of history), the\n-\t\t * original entry for re->dst_entry is no longer\n-\t\t * necessary...\n-\t\t */\n-\t\tre->dst_entry->processed = 1;\n-\n-\t\t/*\n-\t\t * ...because we'll be using this new one.\n-\t\t */\n-\t\tre->dst_entry = item->util;\n-\t} else {\n-\t\t/*\n-\t\t * re->dst_entry is for the before-dir-rename path, and we\n-\t\t * need it to hold information for the after-dir-rename\n-\t\t * path.  Before creating a new entry, we need to mark the\n-\t\t * old one as unnecessary (...unless it is shared by\n-\t\t * src_entry, i.e. this didn't use to be a rename, in which\n-\t\t * case we can just allow the normal processing to happen\n-\t\t * for it).\n-\t\t */\n-\t\tif (pair->status == 'R')\n-\t\t\tre->dst_entry->processed = 1;\n-\n-\t\tre->dst_entry = insert_stage_data(opt->repo, new_path,\n-\t\t\t\t\t\t  o_tree, a_tree, b_tree,\n-\t\t\t\t\t\t  entries);\n-\t\titem = string_list_insert(entries, new_path);\n-\t\titem->util = re->dst_entry;\n-\t}\n-\n-\t/*\n-\t * Update the stage_data with the information about the path we are\n-\t * moving into place.  That slot will be empty and available for us\n-\t * to write to because of the collision checks in\n-\t * handle_path_level_conflicts().  In other words,\n-\t * re->dst_entry->stages[stage].oid will be the null_oid, so it's\n-\t * open for us to write to.\n-\t *\n-\t * It may be tempting to actually update the index at this point as\n-\t * well, using update_stages_for_stage_data(), but as per the big\n-\t * \"NOTE\" in update_stages(), doing so will modify the current\n-\t * in-memory index which will break calls to would_lose_untracked()\n-\t * that we need to make.  Instead, we need to just make sure that\n-\t * the various handle_rename_*() functions update the index\n-\t * explicitly rather than relying on unpack_trees() to have done it.\n-\t */\n-\tget_tree_entry(opt->repo,\n-\t\t       &tree->object.oid,\n-\t\t       pair->two->path,\n-\t\t       &re->dst_entry->stages[stage].oid,\n-\t\t       &re->dst_entry->stages[stage].mode);\n-\n-\t/*\n-\t * Record the original change status (or 'type' of change).  If it\n-\t * was originally an add ('A'), this lets us differentiate later\n-\t * between a RENAME_DELETE conflict and RENAME_VIA_DIR (they\n-\t * otherwise look the same).  If it was originally a rename ('R'),\n-\t * this lets us remember and report accurately about the transitive\n-\t * renaming that occurred via the directory rename detection.  Also,\n-\t * record the original destination name.\n-\t */\n-\tre->dir_rename_original_type = pair->status;\n-\tre->dir_rename_original_dest = pair->two->path;\n-\n-\t/*\n-\t * We don't actually look at pair->status again, but it seems\n-\t * pedagogically correct to adjust it.\n-\t */\n-\tpair->status = 'R';\n-\n-\t/*\n-\t * Finally, record the new location.\n-\t */\n-\tpair->two->path = new_path;\n-}\n-\n-/*\n- * Get information of all renames which occurred in 'pairs', making use of\n- * any implicit directory renames inferred from the other side of history.\n- * We need the three trees in the merge ('o_tree', 'a_tree' and 'b_tree')\n- * to be able to associate the correct cache entries with the rename\n- * information; tree is always equal to either a_tree or b_tree.\n- */\n-static struct string_list *get_renames(struct merge_options *opt,\n-\t\t\t\t       const char *branch,\n-\t\t\t\t       struct diff_queue_struct *pairs,\n-\t\t\t\t       struct hashmap *dir_renames,\n-\t\t\t\t       struct hashmap *dir_rename_exclusions,\n-\t\t\t\t       struct tree *tree,\n-\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t       struct tree *a_tree,\n-\t\t\t\t       struct tree *b_tree,\n-\t\t\t\t       struct string_list *entries,\n-\t\t\t\t       int *clean_merge)\n-{\n-\tint i;\n-\tstruct hashmap collisions;\n-\tstruct hashmap_iter iter;\n-\tstruct collision_entry *e;\n-\tstruct string_list *renames;\n-\n-\tcompute_collisions(&collisions, dir_renames, pairs);\n-\tCALLOC_ARRAY(renames, 1);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct rename *re;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *new_path; /* non-NULL only with directory renames */\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R') {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tnew_path = check_for_directory_rename(opt, pair->two->path, tree,\n-\t\t\t\t\t\t      dir_renames,\n-\t\t\t\t\t\t      dir_rename_exclusions,\n-\t\t\t\t\t\t      &collisions,\n-\t\t\t\t\t\t      clean_merge);\n-\t\tif (pair->status != 'R' && !new_path) {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tre = xmalloc(sizeof(*re));\n-\t\tre->processed = 0;\n-\t\tre->pair = pair;\n-\t\tre->branch = branch;\n-\t\tre->dir_rename_original_type = '\\0';\n-\t\tre->dir_rename_original_dest = NULL;\n-\t\titem = string_list_lookup(entries, re->pair->one->path);\n-\t\tif (!item)\n-\t\t\tre->src_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->one->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->src_entry = item->util;\n-\n-\t\titem = string_list_lookup(entries, re->pair->two->path);\n-\t\tif (!item)\n-\t\t\tre->dst_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->two->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->dst_entry = item->util;\n-\t\titem = string_list_insert(renames, pair->one->path);\n-\t\titem->util = re;\n-\t\tif (new_path)\n-\t\t\tapply_directory_rename_modifications(opt, pair, new_path,\n-\t\t\t\t\t\t\t     re, tree, o_tree,\n-\t\t\t\t\t\t\t     a_tree, b_tree,\n-\t\t\t\t\t\t\t     entries);\n-\t}\n-\n-\thashmap_for_each_entry(&collisions, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->target_file);\n-\t\tstring_list_clear(&e->source_files, 0);\n-\t}\n-\thashmap_clear_and_free(&collisions, struct collision_entry, ent);\n-\treturn renames;\n-}\n-\n-static int process_renames(struct merge_options *opt,\n-\t\t\t   struct string_list *a_renames,\n-\t\t\t   struct string_list *b_renames)\n-{\n-\tint clean_merge = 1, i, j;\n-\tstruct string_list a_by_dst = STRING_LIST_INIT_NODUP;\n-\tstruct string_list b_by_dst = STRING_LIST_INIT_NODUP;\n-\tconst struct rename *sre;\n-\n-\t/*\n-\t * Note that as we build the list, we do not need to check if the\n-\t * existing destination path is already in the list, because the\n-\t * structure of diffcore_rename guarantees we won't have duplicates.\n-\t */\n-\tfor (i = 0; i < a_renames->nr; i++) {\n-\t\tsre = a_renames->items[i].util;\n-\t\tstring_list_append(&a_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tfor (i = 0; i < b_renames->nr; i++) {\n-\t\tsre = b_renames->items[i].util;\n-\t\tstring_list_append(&b_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tstring_list_sort(&a_by_dst);\n-\tstring_list_sort(&b_by_dst);\n-\n-\tfor (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {\n-\t\tstruct string_list *renames1, *renames2Dst;\n-\t\tstruct rename *ren1 = NULL, *ren2 = NULL;\n-\t\tconst char *ren1_src, *ren1_dst;\n-\t\tstruct string_list_item *lookup;\n-\n-\t\tif (i >= a_renames->nr) {\n-\t\t\tren2 = b_renames->items[j++].util;\n-\t\t} else if (j >= b_renames->nr) {\n-\t\t\tren1 = a_renames->items[i++].util;\n-\t\t} else {\n-\t\t\tint compare = strcmp(a_renames->items[i].string,\n-\t\t\t\t\t     b_renames->items[j].string);\n-\t\t\tif (compare <= 0)\n-\t\t\t\tren1 = a_renames->items[i++].util;\n-\t\t\tif (compare >= 0)\n-\t\t\t\tren2 = b_renames->items[j++].util;\n-\t\t}\n-\n-\t\t/* TODO: refactor, so that 1/2 are not needed */\n-\t\tif (ren1) {\n-\t\t\trenames1 = a_renames;\n-\t\t\trenames2Dst = &b_by_dst;\n-\t\t} else {\n-\t\t\trenames1 = b_renames;\n-\t\t\trenames2Dst = &a_by_dst;\n-\t\t\tSWAP(ren2, ren1);\n-\t\t}\n-\n-\t\tif (ren1->processed)\n-\t\t\tcontinue;\n-\t\tren1->processed = 1;\n-\t\tren1->dst_entry->processed = 1;\n-\t\t/* BUG: We should only mark src_entry as processed if we\n-\t\t * are not dealing with a rename + add-source case.\n-\t\t */\n-\t\tren1->src_entry->processed = 1;\n-\n-\t\tren1_src = ren1->pair->one->path;\n-\t\tren1_dst = ren1->pair->two->path;\n-\n-\t\tif (ren2) {\n-\t\t\t/* One file renamed on both sides */\n-\t\t\tconst char *ren2_src = ren2->pair->one->path;\n-\t\t\tconst char *ren2_dst = ren2->pair->two->path;\n-\t\t\tenum rename_type rename_type;\n-\t\t\tif (strcmp(ren1_src, ren2_src) != 0)\n-\t\t\t\tBUG(\"ren1_src != ren2_src\");\n-\t\t\tren2->dst_entry->processed = 1;\n-\t\t\tren2->processed = 1;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0) {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_TWO;\n-\t\t\t\tclean_merge = 0;\n-\t\t\t} else {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_ONE;\n-\t\t\t\t/* BUG: We should only remove ren1_src in\n-\t\t\t\t * the base stage (think of rename +\n-\t\t\t\t * add-source cases).\n-\t\t\t\t */\n-\t\t\t\tremove_file(opt, 1, ren1_src, 1);\n-\t\t\t\tupdate_entry(ren1->dst_entry,\n-\t\t\t\t\t     ren1->pair->one,\n-\t\t\t\t\t     ren1->pair->two,\n-\t\t\t\t\t     ren2->pair->two);\n-\t\t\t}\n-\t\t\tsetup_rename_conflict_info(rename_type, opt, ren1, ren2);\n-\t\t} else if ((lookup = string_list_lookup(renames2Dst, ren1_dst))) {\n-\t\t\t/* Two different files renamed to the same thing */\n-\t\t\tchar *ren2_dst;\n-\t\t\tren2 = lookup->util;\n-\t\t\tren2_dst = ren2->pair->two->path;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0)\n-\t\t\t\tBUG(\"ren1_dst != ren2_dst\");\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tren2->processed = 1;\n-\t\t\t/*\n-\t\t\t * BUG: We should only mark src_entry as processed\n-\t\t\t * if we are not dealing with a rename + add-source\n-\t\t\t * case.\n-\t\t\t */\n-\t\t\tren2->src_entry->processed = 1;\n-\n-\t\t\tsetup_rename_conflict_info(RENAME_TWO_FILES_TO_ONE,\n-\t\t\t\t\t\t   opt, ren1, ren2);\n-\t\t} else {\n-\t\t\t/* Renamed in 1, maybe changed in 2 */\n-\t\t\t/* we only use sha1 and mode of these */\n-\t\t\tstruct diff_filespec src_other, dst_other;\n-\t\t\tint try_merge;\n-\n-\t\t\t/*\n-\t\t\t * unpack_trees loads entries from common-commit\n-\t\t\t * into stage 1, from head-commit into stage 2, and\n-\t\t\t * from merge-commit into stage 3.  We keep track\n-\t\t\t * of which side corresponds to the rename.\n-\t\t\t */\n-\t\t\tint renamed_stage = a_renames == renames1 ? 2 : 3;\n-\t\t\tint other_stage =   a_renames == renames1 ? 3 : 2;\n-\n-\t\t\t/*\n-\t\t\t * Directory renames have a funny corner case...\n-\t\t\t */\n-\t\t\tint renamed_to_self = !strcmp(ren1_src, ren1_dst);\n-\n-\t\t\t/* BUG: We should only remove ren1_src in the base\n-\t\t\t * stage and in other_stage (think of rename +\n-\t\t\t * add-source case).\n-\t\t\t */\n-\t\t\tif (!renamed_to_self)\n-\t\t\t\tremove_file(opt, 1, ren1_src,\n-\t\t\t\t\t    renamed_stage == 2 ||\n-\t\t\t\t\t    !was_tracked(opt, ren1_src));\n-\n-\t\t\toidcpy(&src_other.oid,\n-\t\t\t       &ren1->src_entry->stages[other_stage].oid);\n-\t\t\tsrc_other.mode = ren1->src_entry->stages[other_stage].mode;\n-\t\t\toidcpy(&dst_other.oid,\n-\t\t\t       &ren1->dst_entry->stages[other_stage].oid);\n-\t\t\tdst_other.mode = ren1->dst_entry->stages[other_stage].mode;\n-\t\t\ttry_merge = 0;\n-\n-\t\t\tif (oideq(&src_other.oid, null_oid()) &&\n-\t\t\t    ren1->dir_rename_original_type == 'A') {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_VIA_DIR,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (renamed_to_self) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (oideq(&src_other.oid, null_oid())) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_DELETE,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if ((dst_other.mode == ren1->pair->two->mode) &&\n-\t\t\t\t   oideq(&dst_other.oid, &ren1->pair->two->oid)) {\n-\t\t\t\t/*\n-\t\t\t\t * Added file on the other side identical to\n-\t\t\t\t * the file being renamed: clean merge.\n-\t\t\t\t * Also, there is no need to overwrite the\n-\t\t\t\t * file already in the working copy, so call\n-\t\t\t\t * update_file_flags() instead of\n-\t\t\t\t * update_file().\n-\t\t\t\t */\n-\t\t\t\tif (update_file_flags(opt,\n-\t\t\t\t\t\t      ren1->pair->two,\n-\t\t\t\t\t\t      ren1_dst,\n-\t\t\t\t\t\t      1, /* update_cache */\n-\t\t\t\t\t\t      0  /* update_wd    */))\n-\t\t\t\t\tclean_merge = -1;\n-\t\t\t} else if (!oideq(&dst_other.oid, null_oid())) {\n-\t\t\t\t/*\n-\t\t\t\t * Probably not a clean merge, but it's\n-\t\t\t\t * premature to set clean_merge to 0 here,\n-\t\t\t\t * because if the rename merges cleanly and\n-\t\t\t\t * the merge exactly matches the newly added\n-\t\t\t\t * file, then the merge will be clean.\n-\t\t\t\t */\n-\t\t\t\tsetup_rename_conflict_info(RENAME_ADD,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else\n-\t\t\t\ttry_merge = 1;\n-\n-\t\t\tif (clean_merge < 0)\n-\t\t\t\tgoto cleanup_and_return;\n-\t\t\tif (try_merge) {\n-\t\t\t\tstruct diff_filespec *o, *a, *b;\n-\t\t\t\tsrc_other.path = (char *)ren1_src;\n-\n-\t\t\t\to = ren1->pair->one;\n-\t\t\t\tif (a_renames == renames1) {\n-\t\t\t\t\ta = ren1->pair->two;\n-\t\t\t\t\tb = &src_other;\n-\t\t\t\t} else {\n-\t\t\t\t\tb = ren1->pair->two;\n-\t\t\t\t\ta = &src_other;\n-\t\t\t\t}\n-\t\t\t\tupdate_entry(ren1->dst_entry, o, a, b);\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t}\n-\t\t}\n-\t}\n-cleanup_and_return:\n-\tstring_list_clear(&a_by_dst, 0);\n-\tstring_list_clear(&b_by_dst, 0);\n-\n-\treturn clean_merge;\n-}\n-\n-struct rename_info {\n-\tstruct string_list *head_renames;\n-\tstruct string_list *merge_renames;\n-};\n-\n-static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n-\t\t\t\t   struct hashmap *dir_renames)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *e;\n-\n-\thashmap_for_each_entry(dir_renames, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->dir);\n-\t\tstrbuf_release(&e->new_dir);\n-\t\t/* possible_new_dirs already cleared in get_directory_renames */\n-\t}\n-\thashmap_clear_and_free(dir_renames, struct dir_rename_entry, ent);\n-\tfree(dir_renames);\n-\n-\tfree(pairs->queue);\n-\tfree(pairs);\n-}\n-\n-static int detect_and_process_renames(struct merge_options *opt,\n-\t\t\t\t      struct tree *common,\n-\t\t\t\t      struct tree *head,\n-\t\t\t\t      struct tree *merge,\n-\t\t\t\t      struct string_list *entries,\n-\t\t\t\t      struct rename_info *ri)\n-{\n-\tstruct diff_queue_struct *head_pairs, *merge_pairs;\n-\tstruct hashmap *dir_re_head, *dir_re_merge;\n-\tint clean = 1;\n-\n-\tri->head_renames = NULL;\n-\tri->merge_renames = NULL;\n-\n-\tif (!merge_detect_rename(opt))\n-\t\treturn 1;\n-\n-\thead_pairs = get_diffpairs(opt, common, head);\n-\tmerge_pairs = get_diffpairs(opt, common, merge);\n-\n-\tif ((opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) ||\n-\t    (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t     !opt->priv->call_depth)) {\n-\t\tdir_re_head = get_directory_renames(head_pairs);\n-\t\tdir_re_merge = get_directory_renames(merge_pairs);\n-\n-\t\thandle_directory_level_conflicts(opt,\n-\t\t\t\t\t\t dir_re_head, head,\n-\t\t\t\t\t\t dir_re_merge, merge);\n-\t} else {\n-\t\tdir_re_head  = xmalloc(sizeof(*dir_re_head));\n-\t\tdir_re_merge = xmalloc(sizeof(*dir_re_merge));\n-\t\tdir_rename_init(dir_re_head);\n-\t\tdir_rename_init(dir_re_merge);\n-\t}\n-\n-\tri->head_renames  = get_renames(opt, opt->branch1, head_pairs,\n-\t\t\t\t\tdir_re_merge, dir_re_head, head,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tri->merge_renames = get_renames(opt, opt->branch2, merge_pairs,\n-\t\t\t\t\tdir_re_head, dir_re_merge, merge,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tclean &= process_renames(opt, ri->head_renames, ri->merge_renames);\n-\n-cleanup:\n-\t/*\n-\t * Some cleanup is deferred until cleanup_renames() because the\n-\t * data structures are still needed and referenced in\n-\t * process_entry().  But there are a few things we can free now.\n-\t */\n-\tinitial_cleanup_rename(head_pairs, dir_re_head);\n-\tinitial_cleanup_rename(merge_pairs, dir_re_merge);\n-\n-\treturn clean;\n-}\n-\n-static void final_cleanup_rename(struct string_list *rename)\n-{\n-\tconst struct rename *re;\n-\tint i;\n-\n-\tif (!rename)\n-\t\treturn;\n-\n-\tfor (i = 0; i < rename->nr; i++) {\n-\t\tre = rename->items[i].util;\n-\t\tdiff_free_filepair(re->pair);\n-\t\tif (re->src_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->src_entry->rename_conflict_info);\n-\t\tif (re->dst_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->dst_entry->rename_conflict_info);\n-\t}\n-\tstring_list_clear(rename, 1);\n-\tfree(rename);\n-}\n-\n-static void final_cleanup_renames(struct rename_info *re_info)\n-{\n-\tfinal_cleanup_rename(re_info->head_renames);\n-\tfinal_cleanup_rename(re_info->merge_renames);\n-}\n-\n-static int read_oid_strbuf(struct merge_options *opt,\n-\t\t\t   const struct object_id *oid,\n-\t\t\t   struct strbuf *dst)\n-{\n-\tvoid *buf;\n-\tenum object_type type;\n-\tunsigned long size;\n-\tbuf = repo_read_object_file(the_repository, oid, &type, &size);\n-\tif (!buf)\n-\t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n-\tif (type != OBJ_BLOB) {\n-\t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n-\t}\n-\tstrbuf_attach(dst, buf, size, size + 1);\n-\treturn 0;\n-}\n-\n-static int blob_unchanged(struct merge_options *opt,\n-\t\t\t  const struct diff_filespec *o,\n-\t\t\t  const struct diff_filespec *a,\n-\t\t\t  int renormalize, const char *path)\n-{\n-\tstruct strbuf obuf = STRBUF_INIT;\n-\tstruct strbuf abuf = STRBUF_INIT;\n-\tint ret = 0; /* assume changed for safety */\n-\tstruct index_state *idx = opt->repo->index;\n-\n-\tif (a->mode != o->mode)\n-\t\treturn 0;\n-\tif (oideq(&o->oid, &a->oid))\n-\t\treturn 1;\n-\tif (!renormalize)\n-\t\treturn 0;\n-\n-\tif (read_oid_strbuf(opt, &o->oid, &obuf) ||\n-\t    read_oid_strbuf(opt, &a->oid, &abuf))\n-\t\tgoto error_return;\n-\t/*\n-\t * Note: binary | is used so that both renormalizations are\n-\t * performed.  Comparison can be skipped if both files are\n-\t * unchanged since their sha1s have already been compared.\n-\t */\n-\tif (renormalize_buffer(idx, path, obuf.buf, obuf.len, &obuf) |\n-\t    renormalize_buffer(idx, path, abuf.buf, abuf.len, &abuf))\n-\t\tret = (obuf.len == abuf.len && !memcmp(obuf.buf, abuf.buf, obuf.len));\n-\n-error_return:\n-\tstrbuf_release(&obuf);\n-\tstrbuf_release(&abuf);\n-\treturn ret;\n-}\n-\n-static int handle_modify_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b)\n-{\n-\tconst char *modify_branch, *delete_branch;\n-\tconst struct diff_filespec *changed;\n-\n-\tif (is_valid(a)) {\n-\t\tmodify_branch = opt->branch1;\n-\t\tdelete_branch = opt->branch2;\n-\t\tchanged = a;\n-\t} else {\n-\t\tmodify_branch = opt->branch2;\n-\t\tdelete_branch = opt->branch1;\n-\t\tchanged = b;\n-\t}\n-\n-\treturn handle_change_delete(opt,\n-\t\t\t\t    path, NULL,\n-\t\t\t\t    o, changed,\n-\t\t\t\t    modify_branch, delete_branch,\n-\t\t\t\t    _(\"modify\"), _(\"modified\"));\n-}\n-\n-static int handle_content_merge(struct merge_file_info *mfi,\n-\t\t\t\tstruct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tint is_dirty,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst char *reason = _(\"content\");\n-\tunsigned df_conflict_remains = 0;\n-\n-\tif (!is_valid(o))\n-\t\treason = _(\"add/add\");\n-\n-\tassert(o->path && a->path && b->path);\n-\tif (ci && dir_in_way(opt->repo->index, path, !opt->priv->call_depth,\n-\t\t\t     S_ISGITLINK(ci->ren1->pair->two->mode)))\n-\t\tdf_conflict_remains = 1;\n-\n-\tif (merge_mode_and_contents(opt, o, a, b, path,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    opt->priv->call_depth * 2, mfi))\n-\t\treturn -1;\n-\n-\t/*\n-\t * We can skip updating the working tree file iff:\n-\t *   a) The merge is clean\n-\t *   b) The merge matches what was in HEAD (content, mode, pathname)\n-\t *   c) The target path is usable (i.e. not involved in D/F conflict)\n-\t */\n-\tif (mfi->clean && was_tracked_and_matches(opt, path, &mfi->blob) &&\n-\t    !df_conflict_remains) {\n-\t\tint pos;\n-\t\tstruct cache_entry *ce;\n-\n-\t\toutput(opt, 3, _(\"Skipped %s (merged same as existing)\"), path);\n-\t\tif (add_cacheinfo(opt, &mfi->blob, path,\n-\t\t\t\t  0, (!opt->priv->call_depth && !is_dirty), 0))\n-\t\t\treturn -1;\n-\t\t/*\n-\t\t * However, add_cacheinfo() will delete the old cache entry\n-\t\t * and add a new one.  We need to copy over any skip_worktree\n-\t\t * flag to avoid making the file appear as if it were\n-\t\t * deleted by the user.\n-\t\t */\n-\t\tpos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\t\tce = opt->priv->orig_index.cache[pos];\n-\t\tif (ce_skip_worktree(ce)) {\n-\t\t\tpos = index_name_pos(opt->repo->index, path, strlen(path));\n-\t\t\tce = opt->repo->index->cache[pos];\n-\t\t\tce->ce_flags |= CE_SKIP_WORKTREE;\n-\t\t}\n-\t\treturn mfi->clean;\n-\t}\n-\n-\tif (!mfi->clean) {\n-\t\tif (S_ISGITLINK(mfi->blob.mode))\n-\t\t\treason = _(\"submodule\");\n-\t\toutput(opt, 1, _(\"CONFLICT (%s): Merge conflict in %s\"),\n-\t\t\t\treason, path);\n-\t\tif (ci && !df_conflict_remains)\n-\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\treturn -1;\n-\t}\n-\n-\tif (df_conflict_remains || is_dirty) {\n-\t\tchar *new_path;\n-\t\tif (opt->priv->call_depth) {\n-\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t} else {\n-\t\t\tif (!mfi->clean) {\n-\t\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\t\treturn -1;\n-\t\t\t} else {\n-\t\t\t\tint file_from_stage2 = was_tracked(opt, path);\n-\n-\t\t\t\tif (update_stages(opt, path, NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? &mfi->blob : NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? NULL : &mfi->blob))\n-\t\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t}\n-\t\tnew_path = unique_path(opt, path, ci->ren1->branch);\n-\t\tif (is_dirty) {\n-\t\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t\t       path);\n-\t\t}\n-\t\toutput(opt, 1, _(\"Adding as %s instead\"), new_path);\n-\t\tif (update_file(opt, 0, &mfi->blob, new_path)) {\n-\t\t\tfree(new_path);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tfree(new_path);\n-\t\tmfi->clean = 0;\n-\t} else if (update_file(opt, mfi->clean, &mfi->blob, path))\n-\t\treturn -1;\n-\treturn !is_dirty && mfi->clean;\n-}\n-\n-static int handle_rename_normal(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tstruct rename *ren = ci->ren1;\n-\tstruct merge_file_info mfi;\n-\tint clean;\n-\n-\t/* Merge the content and write it out */\n-\tclean = handle_content_merge(&mfi, opt, path, was_dirty(opt, path),\n-\t\t\t\t     o, a, b, ci);\n-\n-\tif (clean &&\n-\t    opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t    ren->dir_rename_original_dest) {\n-\t\tif (update_stages(opt, path,\n-\t\t\t\t  &mfi.blob, &mfi.blob, &mfi.blob))\n-\t\t\treturn -1;\n-\t\tclean = 0; /* not clean, but conflicted */\n-\t}\n-\treturn clean;\n-}\n-\n-static void dir_rename_warning(const char *msg,\n-\t\t\t       int is_add,\n-\t\t\t       int clean,\n-\t\t\t       struct merge_options *opt,\n-\t\t\t       struct rename *ren)\n-{\n-\tconst char *other_branch;\n-\tother_branch = (ren->branch == opt->branch1 ?\n-\t\t\topt->branch2 : opt->branch1);\n-\tif (is_add) {\n-\t\toutput(opt, clean ? 2 : 1, msg,\n-\t\t       ren->pair->one->path, ren->branch,\n-\t\t       other_branch, ren->pair->two->path);\n-\t\treturn;\n-\t}\n-\toutput(opt, clean ? 2 : 1, msg,\n-\t       ren->pair->one->path, ren->dir_rename_original_dest, ren->branch,\n-\t       other_branch, ren->pair->two->path);\n-}\n-static int warn_about_dir_renamed_entries(struct merge_options *opt,\n-\t\t\t\t\t  struct rename *ren)\n-{\n-\tconst char *msg;\n-\tint clean = 1, is_add;\n-\n-\tif (!ren)\n-\t\treturn clean;\n-\n-\t/* Return early if ren was not affected/created by a directory rename */\n-\tif (!ren->dir_rename_original_dest)\n-\t\treturn clean;\n-\n-\t/* Sanity checks */\n-\tassert(opt->detect_directory_renames > MERGE_DIRECTORY_RENAMES_NONE);\n-\tassert(ren->dir_rename_original_type == 'A' ||\n-\t       ren->dir_rename_original_type == 'R');\n-\n-\t/* Check whether to treat directory renames as a conflict */\n-\tclean = (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE);\n-\n-\tis_add = (ren->dir_rename_original_type == 'A');\n-\tif (ren->dir_rename_original_type == 'A' && clean) {\n-\t\tmsg = _(\"Path updated: %s added in %s inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'A' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s added in %s \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && clean) {\n-\t\tmsg = _(\"Path updated: %s renamed to %s in %s, inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s renamed to %s in %s, \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else {\n-\t\tBUG(\"Impossible dir_rename_original_type/clean combination\");\n-\t}\n-\tdir_rename_warning(msg, is_add, clean, opt, ren);\n-\n-\treturn clean;\n-}\n-\n-/* Per entry merge function */\n-static int process_entry(struct merge_options *opt,\n-\t\t\t const char *path, struct stage_data *entry)\n-{\n-\tint clean_merge = 1;\n-\tint normalize = opt->renormalize;\n-\n-\tstruct diff_filespec *o = &entry->stages[1];\n-\tstruct diff_filespec *a = &entry->stages[2];\n-\tstruct diff_filespec *b = &entry->stages[3];\n-\tint o_valid = is_valid(o);\n-\tint a_valid = is_valid(a);\n-\tint b_valid = is_valid(b);\n-\to->path = a->path = b->path = (char*)path;\n-\n-\tentry->processed = 1;\n-\tif (entry->rename_conflict_info) {\n-\t\tstruct rename_conflict_info *ci = entry->rename_conflict_info;\n-\t\tstruct diff_filespec *temp;\n-\t\tint path_clean;\n-\n-\t\tpath_clean = warn_about_dir_renamed_entries(opt, ci->ren1);\n-\t\tpath_clean &= warn_about_dir_renamed_entries(opt, ci->ren2);\n-\n-\t\t/*\n-\t\t * For cases with a single rename, {o,a,b}->path have all been\n-\t\t * set to the rename target path; we need to set two of these\n-\t\t * back to the rename source.\n-\t\t * For rename/rename conflicts, we'll manually fix paths below.\n-\t\t */\n-\t\ttemp = (opt->branch1 == ci->ren1->branch) ? b : a;\n-\t\to->path = temp->path = ci->ren1->pair->one->path;\n-\t\tif (ci->ren2) {\n-\t\t\tassert(opt->branch1 == ci->ren1->branch);\n-\t\t}\n-\n-\t\tswitch (ci->rename_type) {\n-\t\tcase RENAME_NORMAL:\n-\t\tcase RENAME_ONE_FILE_TO_ONE:\n-\t\t\tclean_merge = handle_rename_normal(opt, path, o, a, b,\n-\t\t\t\t\t\t\t   ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_VIA_DIR:\n-\t\t\tclean_merge = handle_rename_via_dir(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_ADD:\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the renamed file\n-\t\t\t * merges cleanly and the result can then be\n-\t\t\t * two-way merged cleanly with the added file, I\n-\t\t\t * guess it's a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_add(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_DELETE:\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_delete(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_ONE_FILE_TO_TWO:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note:\n-\t\t\t * ren[12]->pair->one->path are equal.\n-\t\t\t */\n-\t\t\to->path = ci->ren1->pair->one->path;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_rename_1to2(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_TWO_FILES_TO_ONE:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note,\n-\t\t\t * ren[12]->pair->two->path are actually equal.\n-\t\t\t */\n-\t\t\to->path = NULL;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the two renamed\n-\t\t\t * files merge cleanly and the two resulting files\n-\t\t\t * can then be two-way merged cleanly, I guess it's\n-\t\t\t * a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_rename_2to1(opt, ci);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tentry->processed = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (path_clean < clean_merge)\n-\t\t\tclean_merge = path_clean;\n-\t} else if (o_valid && (!a_valid || !b_valid)) {\n-\t\t/* Case A: Deleted in one */\n-\t\tif ((!a_valid && !b_valid) ||\n-\t\t    (!b_valid && blob_unchanged(opt, o, a, normalize, path)) ||\n-\t\t    (!a_valid && blob_unchanged(opt, o, b, normalize, path))) {\n-\t\t\t/* Deleted in both or deleted in one and\n-\t\t\t * unchanged in the other */\n-\t\t\tif (a_valid)\n-\t\t\t\toutput(opt, 2, _(\"Removing %s\"), path);\n-\t\t\t/* do not touch working file if it did not exist */\n-\t\t\tremove_file(opt, 1, path, !a_valid);\n-\t\t} else {\n-\t\t\t/* Modify/delete; deleted side may have put a directory in the way */\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_modify_delete(opt, path, o, a, b))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if ((!o_valid && a_valid && !b_valid) ||\n-\t\t   (!o_valid && !a_valid && b_valid)) {\n-\t\t/* Case B: Added in one. */\n-\t\t/* [nothing|directory] -> ([nothing|directory], file) */\n-\n-\t\tconst char *add_branch;\n-\t\tconst char *other_branch;\n-\t\tconst char *conf;\n-\t\tconst struct diff_filespec *contents;\n-\n-\t\tif (a_valid) {\n-\t\t\tadd_branch = opt->branch1;\n-\t\t\tother_branch = opt->branch2;\n-\t\t\tcontents = a;\n-\t\t\tconf = _(\"file/directory\");\n-\t\t} else {\n-\t\t\tadd_branch = opt->branch2;\n-\t\t\tother_branch = opt->branch1;\n-\t\t\tcontents = b;\n-\t\t\tconf = _(\"directory/file\");\n-\t\t}\n-\t\tif (dir_in_way(opt->repo->index, path,\n-\t\t\t       !opt->priv->call_depth && !S_ISGITLINK(a->mode),\n-\t\t\t       0)) {\n-\t\t\tchar *new_path = unique_path(opt, path, add_branch);\n-\t\t\tclean_merge = 0;\n-\t\t\toutput(opt, 1, _(\"CONFLICT (%s): There is a directory with name %s in %s. \"\n-\t\t\t       \"Adding %s as %s\"),\n-\t\t\t       conf, path, other_branch, path, new_path);\n-\t\t\tif (update_file(opt, 0, contents, new_path))\n-\t\t\t\tclean_merge = -1;\n-\t\t\telse if (opt->priv->call_depth)\n-\t\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t\tfree(new_path);\n-\t\t} else {\n-\t\t\toutput(opt, 2, _(\"Adding %s\"), path);\n-\t\t\t/* do not overwrite file if already present */\n-\t\t\tif (update_file_flags(opt, contents, path, 1, !a_valid))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if (a_valid && b_valid) {\n-\t\tif (!o_valid) {\n-\t\t\t/* Case C: Added in both (check for same permissions) */\n-\t\t\toutput(opt, 1,\n-\t\t\t       _(\"CONFLICT (add/add): Merge conflict in %s\"),\n-\t\t\t       path);\n-\t\t\tclean_merge = handle_file_collision(opt,\n-\t\t\t\t\t\t\t    path, NULL, NULL,\n-\t\t\t\t\t\t\t    opt->branch1,\n-\t\t\t\t\t\t\t    opt->branch2,\n-\t\t\t\t\t\t\t    a, b);\n-\t\t} else {\n-\t\t\t/* case D: Modified in both, but differently. */\n-\t\t\tstruct merge_file_info mfi;\n-\t\t\tint is_dirty = 0; /* unpack_trees would have bailed if dirty */\n-\t\t\tclean_merge = handle_content_merge(&mfi, opt, path,\n-\t\t\t\t\t\t\t   is_dirty,\n-\t\t\t\t\t\t\t   o, a, b, NULL);\n-\t\t}\n-\t} else if (!o_valid && !a_valid && !b_valid) {\n-\t\t/*\n-\t\t * this entry was deleted altogether. a_mode == 0 means\n-\t\t * we had that path and want to actively remove it.\n-\t\t */\n-\t\tremove_file(opt, 1, path, !a->mode);\n-\t} else\n-\t\tBUG(\"fatal merge failure, shouldn't happen.\");\n-\n-\treturn clean_merge;\n-}\n-\n-static int merge_trees_internal(struct merge_options *opt,\n-\t\t\t\tstruct tree *head,\n-\t\t\t\tstruct tree *merge,\n-\t\t\t\tstruct tree *merge_base,\n-\t\t\t\tstruct tree **result)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tint code, clean;\n-\n-\tif (opt->subtree_shift) {\n-\t\tmerge = shift_tree_object(opt->repo, head, merge,\n-\t\t\t\t\t  opt->subtree_shift);\n-\t\tmerge_base = shift_tree_object(opt->repo, head, merge_base,\n-\t\t\t\t\t       opt->subtree_shift);\n-\t}\n-\n-\tif (oideq(&merge_base->object.oid, &merge->object.oid)) {\n-\t\toutput(opt, 0, _(\"Already up to date.\"));\n-\t\t*result = head;\n-\t\treturn 1;\n-\t}\n-\n-\tcode = unpack_trees_start(opt, merge_base, head, merge);\n-\n-\tif (code != 0) {\n-\t\tif (show(opt, 4) || opt->priv->call_depth)\n-\t\t\terr(opt, _(\"merging of trees %s and %s failed\"),\n-\t\t\t    oid_to_hex(&head->object.oid),\n-\t\t\t    oid_to_hex(&merge->object.oid));\n-\t\tunpack_trees_finish(opt);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unmerged_index(istate)) {\n-\t\tstruct string_list *entries;\n-\t\tstruct rename_info re_info;\n-\t\tint i;\n-\t\t/*\n-\t\t * Only need the hashmap while processing entries, so\n-\t\t * initialize it here and free it when we are done running\n-\t\t * through the entries. Keeping it in the merge_options as\n-\t\t * opposed to decaring a local hashmap is for convenience\n-\t\t * so that we don't have to pass it to around.\n-\t\t */\n-\t\thashmap_init(&opt->priv->current_file_dir_set, path_hashmap_cmp,\n-\t\t\t     NULL, 512);\n-\t\tget_files_dirs(opt, head);\n-\t\tget_files_dirs(opt, merge);\n-\n-\t\tentries = get_unmerged(opt->repo->index);\n-\t\tclean = detect_and_process_renames(opt, merge_base, head, merge,\n-\t\t\t\t\t\t   entries, &re_info);\n-\t\trecord_df_conflict_files(opt, entries);\n-\t\tif (clean < 0)\n-\t\t\tgoto cleanup;\n-\t\tfor (i = entries->nr-1; 0 <= i; i--) {\n-\t\t\tconst char *path = entries->items[i].string;\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed) {\n-\t\t\t\tint ret = process_entry(opt, path, e);\n-\t\t\t\tif (!ret)\n-\t\t\t\t\tclean = 0;\n-\t\t\t\telse if (ret < 0) {\n-\t\t\t\t\tclean = ret;\n-\t\t\t\t\tgoto cleanup;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t\tfor (i = 0; i < entries->nr; i++) {\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed)\n-\t\t\t\tBUG(\"unprocessed path??? %s\",\n-\t\t\t\t    entries->items[i].string);\n-\t\t}\n-\n-\tcleanup:\n-\t\tfinal_cleanup_renames(&re_info);\n-\n-\t\tstring_list_clear(entries, 1);\n-\t\tfree(entries);\n-\n-\t\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t\t\tstruct path_hashmap_entry, e);\n-\n-\t\tif (clean < 0) {\n-\t\t\tunpack_trees_finish(opt);\n-\t\t\treturn clean;\n-\t\t}\n-\t}\n-\telse\n-\t\tclean = 1;\n-\n-\tunpack_trees_finish(opt);\n-\n-\tif (opt->priv->call_depth &&\n-\t    !(*result = write_in_core_index_as_tree(opt->repo)))\n-\t\treturn -1;\n-\n-\treturn clean;\n-}\n-\n-/*\n- * Merge the commits h1 and h2, returning a flag (int) indicating the\n- * cleanness of the merge.  Also, if opt->priv->call_depth, create a\n- * virtual commit and write its location to *result.\n- */\n-static int merge_recursive_internal(struct merge_options *opt,\n-\t\t\t\t    struct commit *h1,\n-\t\t\t\t    struct commit *h2,\n-\t\t\t\t    const struct commit_list *_merge_bases,\n-\t\t\t\t    struct commit **result)\n-{\n-\tstruct commit_list *merge_bases = copy_commit_list(_merge_bases);\n-\tstruct commit_list *iter;\n-\tstruct commit *merged_merge_bases;\n-\tstruct tree *result_tree;\n-\tconst char *ancestor_name;\n-\tstruct strbuf merge_base_abbrev = STRBUF_INIT;\n-\tint ret;\n-\n-\tif (show(opt, 4)) {\n-\t\toutput(opt, 4, _(\"Merging:\"));\n-\t\toutput_commit_title(opt, h1);\n-\t\toutput_commit_title(opt, h2);\n-\t}\n-\n-\tif (!merge_bases) {\n-\t\tif (repo_get_merge_bases(the_repository, h1, h2,\n-\t\t\t\t\t &merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tmerge_bases = reverse_commit_list(merge_bases);\n-\t}\n-\n-\tif (show(opt, 5)) {\n-\t\tunsigned cnt = commit_list_count(merge_bases);\n-\n-\t\toutput(opt, 5, Q_(\"found %u common ancestor:\",\n-\t\t\t\t\"found %u common ancestors:\", cnt), cnt);\n-\t\tfor (iter = merge_bases; iter; iter = iter->next)\n-\t\t\toutput_commit_title(opt, iter->item);\n-\t}\n-\n-\tmerged_merge_bases = pop_commit(&merge_bases);\n-\tif (!merged_merge_bases) {\n-\t\t/* if there is no common ancestor, use an empty tree */\n-\t\tstruct tree *tree;\n-\n-\t\ttree = lookup_tree(opt->repo, opt->repo->hash_algo->empty_tree);\n-\t\tmerged_merge_bases = make_virtual_commit(opt->repo, tree,\n-\t\t\t\t\t\t\t \"ancestor\");\n-\t\tancestor_name = \"empty tree\";\n-\t} else if (opt->ancestor && !opt->priv->call_depth) {\n-\t\tancestor_name = opt->ancestor;\n-\t} else if (merge_bases) {\n-\t\tancestor_name = \"merged common ancestors\";\n-\t} else {\n-\t\tstrbuf_add_unique_abbrev(&merge_base_abbrev,\n-\t\t\t\t\t &merged_merge_bases->object.oid,\n-\t\t\t\t\t DEFAULT_ABBREV);\n-\t\tancestor_name = merge_base_abbrev.buf;\n-\t}\n-\n-\tfor (iter = merge_bases; iter; iter = iter->next) {\n-\t\tconst char *saved_b1, *saved_b2;\n-\t\topt->priv->call_depth++;\n-\t\t/*\n-\t\t * When the merge fails, the result contains files\n-\t\t * with conflict markers. The cleanness flag is\n-\t\t * ignored (unless indicating an error), it was never\n-\t\t * actually used, as result of merge_trees has always\n-\t\t * overwritten it: the committed \"conflicts\" were\n-\t\t * already resolved.\n-\t\t */\n-\t\tdiscard_index(opt->repo->index);\n-\t\tsaved_b1 = opt->branch1;\n-\t\tsaved_b2 = opt->branch2;\n-\t\topt->branch1 = \"Temporary merge branch 1\";\n-\t\topt->branch2 = \"Temporary merge branch 2\";\n-\t\tif (merge_recursive_internal(opt, merged_merge_bases, iter->item,\n-\t\t\t\t\t     NULL, &merged_merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\topt->branch1 = saved_b1;\n-\t\topt->branch2 = saved_b2;\n-\t\topt->priv->call_depth--;\n-\n-\t\tif (!merged_merge_bases) {\n-\t\t\tret = err(opt, _(\"merge returned no commit\"));\n-\t\t\tgoto out;\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * FIXME: Since merge_recursive_internal() is only ever called by\n-\t * places that ensure the index is loaded first\n-\t * (e.g. builtin/merge.c, rebase/sequencer, etc.), in the common\n-\t * case where the merge base was unique that means when we get here\n-\t * we immediately discard the index and re-read it, which is a\n-\t * complete waste of time.  We should only be discarding and\n-\t * re-reading if we were forced to recurse.\n-\t */\n-\tdiscard_index(opt->repo->index);\n-\tif (!opt->priv->call_depth)\n-\t\trepo_read_index(opt->repo);\n-\n-\topt->ancestor = ancestor_name;\n-\tret = merge_trees_internal(opt,\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h1),\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h2),\n-\t\t\t\t   repo_get_commit_tree(opt->repo,\n-\t\t\t\t\t\t\tmerged_merge_bases),\n-\t\t\t\t   &result_tree);\n-\topt->ancestor = NULL;  /* avoid accidental re-use of opt->ancestor */\n-\tif (ret < 0) {\n-\t\tflush_output(opt);\n-\t\tgoto out;\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t*result = make_virtual_commit(opt->repo, result_tree,\n-\t\t\t\t\t      \"merged tree\");\n-\t\tcommit_list_insert(h1, &(*result)->parents);\n-\t\tcommit_list_insert(h2, &(*result)->parents->next);\n-\t}\n-\n-out:\n-\tstrbuf_release(&merge_base_abbrev);\n-\tfree_commit_list(merge_bases);\n-\treturn ret;\n-}\n-\n-static int merge_start(struct merge_options *opt, struct tree *head)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* Sanity checks on opt */\n-\tassert(opt->repo);\n-\n-\tassert(opt->branch1 && opt->branch2);\n-\n-\tassert(opt->detect_renames >= -1 &&\n-\t       opt->detect_renames <= DIFF_DETECT_COPY);\n-\tassert(opt->detect_directory_renames >= MERGE_DIRECTORY_RENAMES_NONE &&\n-\t       opt->detect_directory_renames <= MERGE_DIRECTORY_RENAMES_TRUE);\n-\tassert(opt->rename_limit >= -1);\n-\tassert(opt->rename_score >= 0 && opt->rename_score <= MAX_SCORE);\n-\tassert(opt->show_rename_progress >= 0 && opt->show_rename_progress <= 1);\n-\n-\tassert(opt->xdl_opts >= 0);\n-\tassert(opt->recursive_variant >= MERGE_VARIANT_NORMAL &&\n-\t       opt->recursive_variant <= MERGE_VARIANT_THEIRS);\n-\n-\tassert(opt->verbosity >= 0 && opt->verbosity <= 5);\n-\tassert(opt->buffer_output <= 2);\n-\tassert(opt->obuf.len == 0);\n-\n-\tassert(opt->priv == NULL);\n-\n-\t/* Not supported; option specific to merge-ort */\n-\tassert(!opt->record_conflict_msgs_as_headers);\n-\tassert(!opt->msg_header_prefix);\n-\n-\t/* Sanity check on repo state; index must match head */\n-\tif (repo_index_has_changes(opt->repo, head, &sb)) {\n-\t\terr(opt, _(\"Your local changes to the following files would be overwritten by merge:\\n  %s\"),\n-\t\t    sb.buf);\n-\t\tstrbuf_release(&sb);\n-\t\treturn -1;\n-\t}\n-\n-\tCALLOC_ARRAY(opt->priv, 1);\n-\tstring_list_init_dup(&opt->priv->df_conflict_file_set);\n-\treturn 0;\n-}\n-\n-static void merge_finalize(struct merge_options *opt)\n-{\n-\tflush_output(opt);\n-\tif (!opt->priv->call_depth && opt->buffer_output < 2)\n-\t\tstrbuf_release(&opt->obuf);\n-\tif (show(opt, 2))\n-\t\tdiff_warn_rename_limit(\"merge.renamelimit\",\n-\t\t\t\t       opt->priv->needed_rename_limit, 0);\n-\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t       struct path_hashmap_entry, e);\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 0);\n-\tFREE_AND_NULL(opt->priv);\n-}\n-\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base)\n-{\n-\tint clean;\n-\tstruct tree *ignored;\n-\n-\tassert(opt->ancestor != NULL);\n-\n-\tif (merge_start(opt, head))\n-\t\treturn -1;\n-\tclean = merge_trees_internal(opt, head, merge, merge_base, &ignored);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result)\n-{\n-\tint clean;\n-\n-\tassert(opt->ancestor == NULL ||\n-\t       !strcmp(opt->ancestor, \"constructed merge base\"));\n-\n-\tprepare_repo_settings(opt->repo);\n-\topt->repo->settings.command_requires_full_index = 1;\n-\n-\tif (merge_start(opt, repo_get_commit_tree(opt->repo, h1)))\n-\t\treturn -1;\n-\tclean = merge_recursive_internal(opt, h1, h2, merge_bases, result);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-static struct commit *get_ref(struct repository *repo,\n-\t\t\t      const struct object_id *oid,\n-\t\t\t      const char *name)\n-{\n-\tstruct object *object;\n-\n-\tobject = deref_tag(repo, parse_object(repo, oid),\n-\t\t\t   name, strlen(name));\n-\tif (!object)\n-\t\treturn NULL;\n-\tif (object->type == OBJ_TREE)\n-\t\treturn make_virtual_commit(repo, (struct tree*)object, name);\n-\tif (object->type != OBJ_COMMIT)\n-\t\treturn NULL;\n-\tif (repo_parse_commit(repo, (struct commit *)object))\n-\t\treturn NULL;\n-\treturn (struct commit *)object;\n-}\n-\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result)\n-{\n-\tint clean;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct commit *head_commit = get_ref(opt->repo, head, opt->branch1);\n-\tstruct commit *next_commit = get_ref(opt->repo, merge, opt->branch2);\n-\tstruct commit_list *ca = NULL;\n-\n-\tif (merge_bases) {\n-\t\tint i;\n-\t\tfor (i = 0; i < num_merge_bases; ++i) {\n-\t\t\tstruct commit *base;\n-\t\t\tif (!(base = get_ref(opt->repo, &merge_bases[i],\n-\t\t\t\t\t     oid_to_hex(&merge_bases[i]))))\n-\t\t\t\treturn err(opt, _(\"Could not parse object '%s'\"),\n-\t\t\t\t\t   oid_to_hex(&merge_bases[i]));\n-\t\t\tcommit_list_insert(base, &ca);\n-\t\t}\n-\t\tif (num_merge_bases == 1)\n-\t\t\topt->ancestor = \"constructed merge base\";\n-\t}\n-\n-\trepo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);\n-\tclean = merge_recursive(opt, head_commit, next_commit, ca,\n-\t\t\t\tresult);\n-\tfree_commit_list(ca);\n-\tif (clean < 0) {\n-\t\trollback_lock_file(&lock);\n-\t\treturn clean;\n-\t}\n-\n-\tif (write_locked_index(opt->repo->index, &lock,\n-\t\t\t       COMMIT_LOCK | SKIP_IF_UNCHANGED))\n-\t\treturn err(opt, _(\"Unable to write index.\"));\n-\n-\treturn clean ? 0 : 1;\n-}\n-\n-static void merge_recursive_config(struct merge_options *opt, int ui)\n-{\n-\tchar *value = NULL;\n-\tint renormalize = 0;\n-\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n-\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n-\topt->renormalize = renormalize;\n-\tif (!git_config_get_string(\"diff.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n-\t\tint boolval = git_parse_maybe_bool(value);\n-\t\tif (0 <= boolval) {\n-\t\t\topt->detect_directory_renames = boolval ?\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n-\t\t} else if (!strcasecmp(value, \"conflict\")) {\n-\t\t\topt->detect_directory_renames =\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n-\t\t} /* avoid erroring on values from future versions of git */\n-\t\tfree(value);\n-\t}\n-\tif (ui) {\n-\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n-\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n-\t\t\tif (diff_algorithm < 0)\n-\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n-\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n-\t\t\tfree(value);\n-\t\t}\n-\t}\n-\tgit_config(git_xmerge_config, NULL);\n-}\n-\n-static void init_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo, int ui)\n-{\n-\tconst char *merge_verbosity;\n-\tmemset(opt, 0, sizeof(struct merge_options));\n-\n-\topt->repo = repo;\n-\n-\topt->detect_renames = -1;\n-\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n-\topt->rename_limit = -1;\n-\n-\topt->verbosity = 2;\n-\topt->buffer_output = 1;\n-\tstrbuf_init(&opt->obuf, 0);\n-\n-\topt->renormalize = 0;\n-\n-\topt->conflict_style = -1;\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n-\tmerge_recursive_config(opt, ui);\n-\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-\tif (merge_verbosity)\n-\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n-\tif (opt->verbosity >= 5)\n-\t\topt->buffer_output = 0;\n-}\n-\n-void init_ui_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 1);\n-}\n-\n-void init_basic_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 0);\n-}\n-\n-/*\n- * For now, members of merge_options do not need deep copying, but\n- * it may change in the future, in which case we would need to update\n- * this, and also make a matching change to clear_merge_options() to\n- * release the resources held by a copied instance.\n- */\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n-{\n-\t*dst = *src;\n-}\n-\n-void clear_merge_options(struct merge_options *opt UNUSED)\n-{\n-\t; /* no-op as our copy is shallow right now */\n-}\n-\n-int parse_merge_opt(struct merge_options *opt, const char *s)\n-{\n-\tconst char *arg;\n-\n-\tif (!s || !*s)\n-\t\treturn -1;\n-\tif (!strcmp(s, \"ours\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n-\telse if (!strcmp(s, \"theirs\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n-\telse if (!strcmp(s, \"subtree\"))\n-\t\topt->subtree_shift = \"\";\n-\telse if (skip_prefix(s, \"subtree=\", &arg))\n-\t\topt->subtree_shift = arg;\n-\telse if (!strcmp(s, \"patience\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n-\telse if (!strcmp(s, \"histogram\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n-\t\tlong value = parse_algorithm_value(arg);\n-\t\tif (value < 0)\n-\t\t\treturn -1;\n-\t\t/* clear out previous settings */\n-\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n-\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n-\t\topt->xdl_opts |= value;\n-\t}\n-\telse if (!strcmp(s, \"ignore-space-change\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n-\telse if (!strcmp(s, \"ignore-all-space\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n-\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n-\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n-\telse if (!strcmp(s, \"renormalize\"))\n-\t\topt->renormalize = 1;\n-\telse if (!strcmp(s, \"no-renormalize\"))\n-\t\topt->renormalize = 0;\n-\telse if (!strcmp(s, \"no-renames\"))\n-\t\topt->detect_renames = 0;\n-\telse if (!strcmp(s, \"find-renames\")) {\n-\t\topt->detect_renames = 1;\n-\t\topt->rename_score = 0;\n-\t}\n-\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n-\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n-\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n-\t\t\treturn -1;\n-\t\topt->detect_renames = 1;\n-\t}\n-\t/*\n-\t * Please update $__git_merge_strategy_options in\n-\t * git-completion.bash when you add new options\n-\t */\n-\telse\n-\t\treturn -1;\n-\treturn 0;\n-}\ndiff --git a/merge-recursive.h b/merge-recursive.h\ndeleted file mode 100644\nindex 0b91f28f902..00000000000\n--- a/merge-recursive.h\n+++ /dev/null\n@@ -1,132 +0,0 @@\n-#ifndef MERGE_RECURSIVE_H\n-#define MERGE_RECURSIVE_H\n-\n-#include \"strbuf.h\"\n-\n-struct commit;\n-struct commit_list;\n-struct object_id;\n-struct repository;\n-struct tree;\n-\n-struct merge_options_internal;\n-struct merge_options {\n-\tstruct repository *repo;\n-\n-\t/* ref names used in console messages and conflict markers */\n-\tconst char *ancestor;\n-\tconst char *branch1;\n-\tconst char *branch2;\n-\n-\t/* rename related options */\n-\tint detect_renames;\n-\tenum {\n-\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n-\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n-\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n-\t} detect_directory_renames;\n-\tint rename_limit;\n-\tint rename_score;\n-\tint show_rename_progress;\n-\n-\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n-\tlong xdl_opts;\n-\tint conflict_style;\n-\tenum {\n-\t\tMERGE_VARIANT_NORMAL = 0,\n-\t\tMERGE_VARIANT_OURS,\n-\t\tMERGE_VARIANT_THEIRS\n-\t} recursive_variant;\n-\n-\t/* console output related options */\n-\tint verbosity;\n-\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n-\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n-\t\t\t\t * must handle and call strbuf_release */\n-\n-\t/* miscellaneous control options */\n-\tconst char *subtree_shift;\n-\tunsigned renormalize : 1;\n-\tunsigned record_conflict_msgs_as_headers : 1;\n-\tconst char *msg_header_prefix;\n-\n-\t/* internal fields used by the implementation */\n-\tstruct merge_options_internal *priv;\n-};\n-\n-/* for use by porcelain commands */\n-void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n-/* for use by plumbing commands */\n-void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n-\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n-void clear_merge_options(struct merge_options *opt);\n-\n-/* parse the option in s and update the relevant field of opt */\n-int parse_merge_opt(struct merge_options *opt, const char *s);\n-\n-/*\n- * RETURN VALUES: All the merge_* functions below return a value as follows:\n- *   > 0     Merge was clean\n- *   = 0     Merge had conflicts\n- *   < 0     Merge hit an unexpected and unrecoverable problem (e.g. disk\n- *             full) and aborted merge part-way through.\n- */\n-\n-/*\n- * rename-detecting three-way merge, no recursion.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base);\n-\n-/*\n- * merge_recursive is like merge_trees() but with recursive ancestor\n- * consolidation.\n- *\n- * NOTE: empirically, about a decade ago it was determined that with more\n- *       than two merge bases, optimal behavior was found when the\n- *       merge_bases were passed in the order of oldest commit to newest\n- *       commit.  Also, merge_bases will be consumed (emptied) so make a\n- *       copy if you need it.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result);\n-\n-/*\n- * merge_recursive_generic can operate on trees instead of commits, by\n- * wrapping the trees into virtual commits, and calling merge_recursive().\n- * It also writes out the in-memory index to disk if the merge is successful.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index also written to $GIT_INDEX_FILE on disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result);\n-\n-#endif\ndiff --git a/meson.build b/meson.build\nindex e98cfa4909f..8448df9d15e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -338,7 +338,6 @@ libgit_sources = [\n   'merge-ll.c',\n   'merge-ort.c',\n   'merge-ort-wrappers.c',\n-  'merge-recursive.c',\n   'merge.c',\n   'midx.c',\n   'midx-write.c',\n-- \ngitgitgadget\n\n"},{"id":"515799","messageId":"xmqqiknfn36y.fsf@gitster.g","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/8] Debug merge-recursive.[ch]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-07T20:09:57Z","receivedAt":"2025-04-07T20:10:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Elijah Newren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> This series does some preparation, then moves the code shared between\n> merge-recursive and merge-ort from the former to the latter, and then debugs\n> the remainder of merge-recursive.[ch].\n\nHelp unconfusing me.  When we have bugs in our code, the action we\ntake consists of two parts, i.e. first we find them, and then we fix\nthem.  To me, the verb \"debug\" refers only to the earlier half, and\nnever the latter.\n\nBut the code in the later part of this series is not only to find or\nexpose existing bugs, but also fixing them, right?\n\nI've already named the topic with \"debug\" in its name while queuing\nthe original iteration of this series, as I was on vacation and did\nnot want to spend more than minimum braincycles on naming, but now I\nam back, I sense that the use of the word, and the proposed log\nmessage for 6/8, are overly suboptimal.  If you are referring to\nfixing remaining bugs, \"Debug the remainder of merge-recursive.[ch]\"\nis not how we usually describe our fixes.\n\nI suspect that the overall sentiment behind this series is ...\n\n        Such and such bugs existed in the older backend, but now the\n        newer backend is used when the older one is asked, and the\n        newer backend does not share these bugs, we can simply\n        remove the buggy code specific to the older backend.\n\n... but I find it somewhat disturbing to stay totally silent about\n\"such and such bugs existed\" part.\n\nThanks.\n"},{"id":"515807","messageId":"CABPp-BGN2JCt9BJ0wQqtgNLhD6Qf19PMzYWpjgpJ6O2OcyRCXg@mail.gmail.com","threadId":"63226","inReplyTo":"xmqqiknfn36y.fsf@gitster.g","subject":"Re: [PATCH v2 0/8] Debug merge-recursive.[ch]","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-04-07T22:23:40Z","receivedAt":"2025-04-07T22:23:52Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Apr 7, 2025 at 1:10 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"Elijah Newren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n> > This series does some preparation, then moves the code shared between\n> > merge-recursive and merge-ort from the former to the latter, and then debugs\n> > the remainder of merge-recursive.[ch].\n>\n> Help unconfusing me.\n\nIt was an attempt at humor, which importantly relied on the sentence\nyou stripped out immediately before this part you quoted, namely:\n\n> > As a wise man once told me, \"Deleted code is debugged code!\"\n\nWith this sentence as context, \"debug the code\" was a funny way of\nsaying \"delete the code\".  Because if it's deleted, we are no longer\naffected by any bugs contained within it (and that'd be true for both\nknown bugs and latent ones we hadn't triggered yet).\n\n> I've already named the topic with \"debug\" in its name while queuing\n> the original iteration of this series, as I was on vacation and did\n> not want to spend more than minimum braincycles on naming, but now I\n> am back, I sense that the use of the word, and the proposed log\n> message for 6/8, are overly suboptimal.  If you are referring to\n> fixing remaining bugs, \"Debug the remainder of merge-recursive.[ch]\"\n> is not how we usually describe our fixes.\n>\n> I suspect that the overall sentiment behind this series is ...\n>\n>         Such and such bugs existed in the older backend, but now the\n>         newer backend is used when the older one is asked, and the\n>         newer backend does not share these bugs, we can simply\n>         remove the buggy code specific to the older backend.\n\nI'd say the sentiment is more:\n\n   merge-ort was always meant to be a replacement for merge-recursive\n   (and has various advantages -- worktree-less and index-less\n   operation, faster, fixes some bugs); let's convert the rest of the\n   callers over and then clean up by deleting merge-recursive (as\n   well as removing the extra test scaffolding added long ago to aid\n   in the conversion).\n\nIn other words the bug fixes, while real, were not the thrust of the\nstory.  I showed a handful of people my existing commit message and\ncover letter, all of whom found it a humorous way of stating that\nwe're finally replacing merge-recursive.  But, since this intent\nwasn't obvious to everyone, I can re-roll with some clarification.\n"},{"id":"515880","messageId":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v2.git.1743891374.gitgitgadget@gmail.com","subject":"[PATCH v3 0/8] Debug merge-recursive.[ch]","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:34Z","receivedAt":"2025-04-08T15:48:46Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Changes since v1:\n\n * fixed a couple of typos in commit messages\n\nChanges since v2.\n\n * clarified the commit message for patch 6, and the cover letter\n\nClarified cover letter:\n\nAs a wise man once told me, \"Deleted code is debugged code!\"\n\nThis series does some preparation, then moves the code shared between\nmerge-recursive and merge-ort from the former to the latter, and then\n\"debugs\" the remainder of merge-recursive.[ch].\n\nJoking aside, merge-ort was always intended to replace merge-recursive. It\ndid replace it as the default years ago in commit 6a5fb966720f (Change\ndefault merge backend from recursive to ort, 2021-08-04), and was noted to\nbe better on correctness, extensibility, and performance issues. In this\nseries, we convert the remaining callers of merge-recursive over to\nmerge-ort equivalents, move the shared code between merge-recursive and\nmerge-ort from the former to the latter, and then delete the remainder of\nmerge-recursive.[ch] as it has now been fully replaced. We then clean up\nsome test framework scaffolding that was put into place to allow us to reuse\nthe recursive tests as ort tests.\n\nSeries overview:\n\n * Patches 1-5: Preparation; switch remaining callers of\n   merge-recursive.[ch] functions to merge-ort equivalents, and add sole\n   remaining missing feature (diff-algorithm selection)\n * Patch 6: Nuke merge-recursive.[ch]\n * Patch 7-8: Cleanup testsuite; we don't need GIT_TEST_MERGE_ALGORITHM\n   anymore\n\nWhile the diffstat might look large, the non-test code changes are actually\npretty small. The drivers of the big diffstat are:\n\n * We move a significant chunk of shared code from merge-recursive.[ch] to\n   merge-ort.[ch], without modifying it\n * We delete (the remainder of) merge-recursive.[ch]\n * We rip out all the temporary GIT_TEST_MERGE_ALGORITHM stuff designed to\n   let us reuse tests between recursive and ort\n\nElijah Newren (8):\n  checkout: replace merge_trees() with merge_ort_nonrecursive()\n  builtin/merge-recursive: switch to using merge_ort_generic()\n  merge-ort: enable diff-algorithms other than histogram\n  sequencer: switch non-recursive merges over to ort\n  merge, sequencer: switch recursive merges over to ort\n  merge-recursive.[ch]: thoroughly debug these\n  tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n  builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM\n\n Documentation/merge-strategies.adoc           |   51 +-\n Documentation/technical/sparse-checkout.adoc  |    2 -\n Makefile                                      |    1 -\n builtin/checkout.c                            |   10 +-\n builtin/merge-recursive.c                     |    4 +-\n builtin/merge.c                               |   23 +-\n builtin/rebase.c                              |    5 -\n builtin/revert.c                              |    2 -\n ci/run-build-and-tests.sh                     |    1 -\n merge-ort-wrappers.h                          |    2 +-\n merge-ort.c                                   |  162 +-\n merge-ort.h                                   |   60 +-\n merge-recursive.c                             | 4079 -----------------\n merge-recursive.h                             |  132 -\n meson.build                                   |    1 -\n sequencer.c                                   |   58 +-\n t/lib-merge.sh                                |   13 -\n t/t1092-sparse-checkout-compatibility.sh      |    2 -\n t/t2501-cwd-empty.sh                          |    2 -\n t/t3512-cherry-pick-submodule.sh              |    5 -\n t/t3513-revert-submodule.sh                   |    4 -\n t/t4069-remerge-diff.sh                       |    7 -\n t/t4301-merge-tree-write-tree.sh              |    7 -\n t/t5572-pull-submodule.sh                     |    5 -\n t/t6400-merge-df.sh                           |   14 +-\n t/t6402-merge-rename.sh                       |  125 +-\n t/t6404-recursive-merge.sh                    |   21 +-\n t/t6406-merge-attr.sh                         |    7 +-\n t/t6416-recursive-corner-cases.sh             |  194 +-\n t/t6421-merge-partial-clone.sh                |    7 +-\n t/t6422-merge-rename-corner-cases.sh          |   31 +-\n t/t6423-merge-rename-directories.sh           |  517 +--\n t/t6424-merge-unrelated-index-changes.sh      |    8 +-\n t/t6426-merge-skip-unneeded-updates.sh        |    4 +-\n t/t6428-merge-conflicts-sparse.sh             |    2 -\n t/t6430-merge-recursive.sh                    |   46 +-\n t/t6434-merge-recursive-rename-options.sh     |   16 +-\n t/t6436-merge-overwrite.sh                    |   17 +-\n t/t6437-submodule-merge.sh                    |   65 +-\n t/t6438-submodule-directory-file-conflicts.sh |    5 -\n t/t6439-merge-co-error-msgs.sh                |    2 +-\n t/t7402-submodule-rebase.sh                   |    7 +-\n t/t7602-merge-octopus-many.sh                 |    9 +-\n t/t7610-mergetool.sh                          |   40 +-\n t/t7615-diff-algo-with-mergy-operations.sh    |    2 -\n t/test-lib.sh                                 |    2 -\n 46 files changed, 538 insertions(+), 5241 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n delete mode 100644 t/lib-merge.sh\n\n\nbase-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1898%2Fnewren%2Fendit-quote-debugging-unquote-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1898/newren/endit-quote-debugging-unquote-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/1898\n\nRange-diff vs v2:\n\n 1:  0e150ee9065 = 1:  0e150ee9065 checkout: replace merge_trees() with merge_ort_nonrecursive()\n 2:  b093d74968b = 2:  b093d74968b builtin/merge-recursive: switch to using merge_ort_generic()\n 3:  cf774437123 = 3:  cf774437123 merge-ort: enable diff-algorithms other than histogram\n 4:  6203589ac17 = 4:  6203589ac17 sequencer: switch non-recursive merges over to ort\n 5:  8821f22d5ea = 5:  8821f22d5ea merge, sequencer: switch recursive merges over to ort\n 6:  770f611c2b6 ! 6:  e696cb472bd merge-recursive.[ch]: thoroughly debug these\n     @@ Commit message\n          the former to the latter, and then debug the remainder of\n          merge-recursive.[ch].\n      \n     +    Joking aside, merge-ort was always intended to replace merge-recursive.\n     +    It has numerous advantages over merge-recursive (operates much faster,\n     +    can operate without a worktree or index, and fixes a number of known\n     +    bugs and suboptimal merges).  Since we have now replaced all callers of\n     +    merge-recursive with equivalent functions from merge-ort, move the\n     +    shared functions from the former to the latter, and delete the remainder\n     +    of merge-recursive.[ch].\n     +\n          Signed-off-by: Elijah Newren <newren@gmail.com>\n      \n       ## Documentation/merge-strategies.adoc ##\n 7:  a6501ee85fa = 7:  5dce9096e23 tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm\n 8:  d1dea986646 = 8:  bf2d462c4e5 builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM\n\n-- \ngitgitgadget\n"},{"id":"515881","messageId":"0e150ee90659c89399bec614902077729cb2c917.1744127322.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 1/8] checkout: replace merge_trees() with merge_ort_nonrecursive()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:35Z","receivedAt":"2025-04-08T15:48:47Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nReplace the use of merge_trees() from merge-recursive.[ch] with the\nmerge-ort equivalent.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/checkout.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 01ea9ff8b28..67879e72362 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -17,7 +17,7 @@\n #include \"merge-ll.h\"\n #include \"lockfile.h\"\n #include \"mem-pool.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n #include \"object-store-ll.h\"\n #include \"parse-options.h\"\n@@ -907,10 +907,10 @@ static int merge_working_tree(const struct checkout_opts *opts,\n \t\t\to.branch1 = new_branch_info->name;\n \t\t\to.branch2 = \"local\";\n \t\t\to.conflict_style = opts->conflict_style;\n-\t\t\tret = merge_trees(&o,\n-\t\t\t\t\t  new_tree,\n-\t\t\t\t\t  work,\n-\t\t\t\t\t  old_tree);\n+\t\t\tret = merge_ort_nonrecursive(&o,\n+\t\t\t\t\t\t     new_tree,\n+\t\t\t\t\t\t     work,\n+\t\t\t\t\t\t     old_tree);\n \t\t\tif (ret < 0)\n \t\t\t\texit(128);\n \t\t\tret = reset_tree(new_tree,\n-- \ngitgitgadget\n\n"},{"id":"515882","messageId":"b093d74968b146987fd7ea2373c3879d69fdf448.1744127322.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 2/8] builtin/merge-recursive: switch to using merge_ort_generic()","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:36Z","receivedAt":"2025-04-08T15:48:49Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nSwitch from merge-recursive to merge-ort.  Adjust the following\ntestcases due to the switch:\n\n* t6430: most of the test differences here were due to improved D/F\n  conflict handling explained in more detail in ef527787089c (merge\n  tests: expect improved directory/file conflict handling in ort,\n  2020-10-26).  These changes weren't made to this test back in that\n  commit simply because I had been looking at `git merge` rather than\n  `git merge-recursive`.  The final test in this testsuite, though, was\n  expunged because it was looking for specific output, and the calls to\n  output_commit_title() were discarded from merge_ort_internal() in its\n  adaptation from merge_recursive_internal(); see 8119214f4e70\n  (merge-ort: implement merge_incore_recursive(), 2020-12-16).\n\n* t6434: This test is built entirely around rename/delete conflicts,\n  which had a suboptimal handling under merge-recursive.  As explained\n  in more detail in commits 1f3c9ba707 (\"t6425: be more flexible with\n  rename/delete conflict messages\", 2020-08-10) and 727c75b23f (\"t6404,\n  t6423: expect improved rename/delete handling in ort backend\",\n  2020-10-26), rename/delete conflicts should each have two entries in\n  the index rather than just one.  Adjust the expectations for all the\n  tests in this testcase to see the two entries per rename/delete\n  conflict.\n\n* t6424: merge-recursive had a special check-if-toplevel-trees-match\n  check that it ran at the beginning on both the merge-base and the\n  other side being merged in.  In such a case, it exited early and\n  printed an \"Already up to date.\" message.  merge-ort got rid of\n  this, and instead checks the merge base tree matching the other\n  side throughout the tree instead of just at the toplevel, allowing\n  it to avoid recursing into various subtrees.  As part of that, it\n  got rid of the specialty toplevel message.  That message hasn't\n  been missed for years from `git merge`, so I don't think it is\n  necessary to keep it just for `git merge-recursive`, especially\n  since the latter is rarely used.  (git itself only references it\n  in the testsuite, whereas it used to power one of the three\n  rebase backends that existed once upon a time.)\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge-recursive.c                 |  4 +--\n t/t6424-merge-unrelated-index-changes.sh  |  4 ++-\n t/t6430-merge-recursive.sh                | 43 +++++------------------\n t/t6434-merge-recursive-rename-options.sh | 16 +++++----\n 4 files changed, 22 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c\nindex abfc060e28a..03b5100cfae 100644\n--- a/builtin/merge-recursive.c\n+++ b/builtin/merge-recursive.c\n@@ -3,7 +3,7 @@\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hash.h\"\n-#include \"merge-recursive.h\"\n+#include \"merge-ort-wrappers.h\"\n #include \"object-name.h\"\n \n static const char builtin_merge_recursive_usage[] =\n@@ -89,7 +89,7 @@ int cmd_merge_recursive(int argc,\n \tif (o.verbosity >= 3)\n \t\tprintf(_(\"Merging %s with %s\\n\"), o.branch1, o.branch2);\n \n-\tfailed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);\n+\tfailed = merge_ort_generic(&o, &h1, &h2, bases_count, bases, &result);\n \n \tfree(better1);\n \tfree(better2);\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 7677c5f08d0..084bfe7e6ce 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -176,9 +176,11 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' '\n \t# Make index match B\n \tgit diff C B -- | git apply --cached &&\n \ttest_when_finished \"git clean -fd\" &&  # Do not leave untracked around\n+\tgit write-tree >index-before &&\n \t# Merge B & F, with B as \"head\"\n \tgit merge-recursive A -- B F > out &&\n-\ttest_grep \"Already up to date\" out\n+\tgit write-tree >index-after &&\n+\ttest_cmp index-before index-after\n '\n \n test_expect_success 'recursive, when file has staged changes not matching HEAD nor what a merge would give' '\ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex ca15e6dd6da..c539a68fd07 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -373,9 +373,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 2\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 2\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -397,9 +397,9 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '\n \n \tgit ls-files -s >actual &&\n \t(\n-\t\techo \"100644 $o0 1\ta\" &&\n-\t\techo \"100644 $o1 3\ta\" &&\n \t\techo \"100644 $o4 0\ta/c\" &&\n+\t\techo \"100644 $o0 1\ta~$c1\" &&\n+\t\techo \"100644 $o1 3\ta~$c1\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n \t\techo \"100644 $o1 0\td/e\"\n@@ -424,9 +424,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 3\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 2\td/e\"\n+\t\techo \"100644 $o1 2\td/e\" &&\n+\t\techo \"100644 $o6 3\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -448,9 +448,9 @@ test_expect_success 'merge-recursive d/f conflict result' '\n \t\techo \"100644 $o1 0\ta\" &&\n \t\techo \"100644 $o0 0\tb\" &&\n \t\techo \"100644 $o0 0\tc\" &&\n-\t\techo \"100644 $o6 2\td\" &&\n \t\techo \"100644 $o0 1\td/e\" &&\n-\t\techo \"100644 $o1 3\td/e\"\n+\t\techo \"100644 $o1 3\td/e\" &&\n+\t\techo \"100644 $o6 2\td~$c6\"\n \t) >expected &&\n \ttest_cmp expected actual\n \n@@ -696,33 +696,6 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n \tgit merge other\n '\n \n-test_expect_success 'merge-recursive remembers the names of all base trees' '\n-\tgit reset --hard HEAD &&\n-\n-\t# make the index match $c1 so that merge-recursive below does not\n-\t# fail early\n-\tgit diff --binary HEAD $c1 -- | git apply --cached &&\n-\n-\t# more trees than static slots used by oid_to_hex()\n-\tfor commit in $c0 $c2 $c4 $c5 $c6 $c7\n-\tdo\n-\t\tgit rev-parse \"$commit^{tree}\" || return 1\n-\tdone >trees &&\n-\n-\t# ignore the return code; it only fails because the input is weird...\n-\ttest_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&\n-\n-\t# ...but make sure it fails in the expected way\n-\ttest_grep CONFLICT.*rename/rename out &&\n-\n-\t# merge-recursive prints in reverse order, but we do not care\n-\tsort <trees >expect &&\n-\tsed -n \"s/^virtual //p\" out | sort >actual &&\n-\ttest_cmp expect actual &&\n-\n-\tgit clean -fd\n-'\n-\n test_expect_success 'merge-recursive internal merge resolves to the sameness' '\n \tgit reset --hard HEAD &&\n \ndiff --git a/t/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh\nindex 6e913c30a13..5a6f74839cb 100755\n--- a/t/t6434-merge-recursive-rename-options.sh\n+++ b/t/t6434-merge-recursive-rename-options.sh\n@@ -34,7 +34,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n get_expected_stages () {\n \tgit checkout rename -- $1-new &&\n \tgit ls-files --stage $1-new >expected-stages-undetected-$1 &&\n-\tsed \"s/ 0\t/ 2\t/\" <expected-stages-undetected-$1 \\\n+\tgit ls-tree HEAD^ $1-old >tmp &&\n+\tgit ls-tree HEAD  $1-new >>tmp &&\n+\tcat tmp | awk '{print $1 \" \" $3 \" \" NR \"\\t\" '$1'\"-new\"}' \\\n \t\t>expected-stages-detected-$1 &&\n \tgit read-tree -u --reset HEAD\n }\n@@ -51,11 +53,11 @@ rename_undetected () {\n \n check_common () {\n \tgit ls-files --stage >stages-actual &&\n-\ttest_line_count = 4 stages-actual\n+\ttest_line_count = $1 stages-actual\n }\n \n check_threshold_0 () {\n-\tcheck_common &&\n+\tcheck_common 8 &&\n \trename_detected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -63,7 +65,7 @@ check_threshold_0 () {\n }\n \n check_threshold_1 () {\n-\tcheck_common &&\n+\tcheck_common 7 &&\n \trename_undetected 0 &&\n \trename_detected 1 &&\n \trename_detected 2 &&\n@@ -71,7 +73,7 @@ check_threshold_1 () {\n }\n \n check_threshold_2 () {\n-\tcheck_common &&\n+\tcheck_common 6 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_detected 2 &&\n@@ -79,7 +81,7 @@ check_threshold_2 () {\n }\n \n check_exact_renames () {\n-\tcheck_common &&\n+\tcheck_common 5 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n@@ -87,7 +89,7 @@ check_exact_renames () {\n }\n \n check_no_renames () {\n-\tcheck_common &&\n+\tcheck_common 4 &&\n \trename_undetected 0 &&\n \trename_undetected 1 &&\n \trename_undetected 2 &&\n-- \ngitgitgadget\n\n"},{"id":"515883","messageId":"cf774437123722d6065139573b49c3e09c6c135a.1744127322.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 3/8] merge-ort: enable diff-algorithms other than histogram","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:37Z","receivedAt":"2025-04-08T15:48:49Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe ort merge strategy has always used the histogram diff algorithm.\nThe recursive merge strategy, in contrast, defaults to the myers\ndiff algorithm, while allowing it to be changed.\n\nChange the ort merge strategy to allow different diff algorithms, by\nremoving the hard coded value in merge_start() and instead just making\nit a default in init_merge_options().  Technically, this also changes\nthe default diff algorithm for the recursive backend too, but we're\ngoing to remove the final callers of the recursive backend in the next\ntwo commits.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc | 29 +++++++++++++++--------------\n merge-ort.c                         |  3 ---\n merge-recursive.c                   |  1 +\n 3 files changed, 16 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 59f5ae36ccb..8c87dd70210 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -87,6 +87,20 @@ no-renames;;\n \tconfiguration variable.\n \tSee also linkgit:git-diff[1] `--no-renames`.\n \n+histogram;;\n+\tDeprecated synonym for `diff-algorithm=histogram`.\n+\n+patience;;\n+\tDeprecated synonym for `diff-algorithm=patience`.\n+\n+diff-algorithm=[histogram|minimal|myers|patience];;\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`.  Note that `ort`\n+\tdefaults to `diff-algorithm=histogram`, while regular diffs\n+\tcurrently default to the `diff.algorithm` config setting.\n+\n subtree[=<path>];;\n \tThis option is a more advanced form of 'subtree' strategy, where\n \tthe strategy makes a guess on how two trees must be shifted to\n@@ -111,20 +125,7 @@ recursive::\n For a path that is a submodule, the same caution as 'ort' applies to this\n strategy.\n +\n-The 'recursive' strategy takes the same options as 'ort'.  However,\n-there are two additional options that 'ort' ignores (not documented\n-above) that are potentially useful with the 'recursive' strategy:\n-\n-patience;;\n-\tDeprecated synonym for `diff-algorithm=patience`.\n-\n-diff-algorithm=[patience|minimal|histogram|myers];;\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`.  Note that `ort`\n-\tspecifically uses `diff-algorithm=histogram`, while `recursive`\n-\tdefaults to the `diff.algorithm` config setting.\n+The 'recursive' strategy takes the same options as 'ort'.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 2b7d86aa4ec..14a7ae4a6bf 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -4957,9 +4957,6 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)\n \t}\n \ttrace2_region_leave(\"merge\", \"sanity checks\", opt->repo);\n \n-\t/* Default to histogram diff.  Actually, just hardcode it...for now. */\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n \t/* Handle attr direction stuff for renormalization */\n \tif (opt->renormalize)\n \t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 884ccf99a58..f3df127ad9b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -3981,6 +3981,7 @@ static void init_merge_options(struct merge_options *opt,\n \topt->renormalize = 0;\n \n \topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n \n \tmerge_recursive_config(opt, ui);\n \tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-- \ngitgitgadget\n\n"},{"id":"515884","messageId":"6203589ac17be5571a175e92326f688c118313db.1744127322.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 4/8] sequencer: switch non-recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:38Z","receivedAt":"2025-04-08T15:48:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThe do_recursive_merge() function, which is somewhat misleadingly named\nsince its purpose in life is to do a *non*-recursive merge, had code to\nallow either using the recursive or ort backends.  The default has been\nort for a very long time, let's just remove the code path for allowing\nthe recursive backend to be selected.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n sequencer.c | 35 +++++++++++++----------------------\n 1 file changed, 13 insertions(+), 22 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ad0ab75c8d4..b5d91fd3515 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -781,28 +781,19 @@ static int do_recursive_merge(struct repository *r,\n \tfor (i = 0; i < opts->xopts.nr; i++)\n \t\tparse_merge_opt(&o, opts->xopts.v[i]);\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\tmemset(&result, 0, sizeof(result));\n-\t\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,\n-\t\t\t\t\t    &result);\n-\t\tshow_output = !is_rebase_i(opts) || !result.clean;\n-\t\t/*\n-\t\t * TODO: merge_switch_to_result will update index/working tree;\n-\t\t * we only really want to do that if !result.clean || this is\n-\t\t * the final patch to be picked.  But determining this is the\n-\t\t * final patch would take some work, and \"head_tree\" would need\n-\t\t * to be replace with the tree the index matched before we\n-\t\t * started doing any picks.\n-\t\t */\n-\t\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n-\t\tclean = result.clean;\n-\t} else {\n-\t\tensure_full_index(r->index);\n-\t\tclean = merge_trees(&o, head_tree, next_tree, base_tree);\n-\t\tif (is_rebase_i(opts) && clean <= 0)\n-\t\t\tfputs(o.obuf.buf, stdout);\n-\t\tstrbuf_release(&o.obuf);\n-\t}\n+\tmemset(&result, 0, sizeof(result));\n+\tmerge_incore_nonrecursive(&o, base_tree, head_tree, next_tree, &result);\n+\tshow_output = !is_rebase_i(opts) || !result.clean;\n+\t/*\n+\t * TODO: merge_switch_to_result will update index/working tree;\n+\t * we only really want to do that if !result.clean || this is\n+\t * the final patch to be picked.  But determining this is the\n+\t * final patch would take some work, and \"head_tree\" would need\n+\t * to be replace with the tree the index matched before we\n+\t * started doing any picks.\n+\t */\n+\tmerge_switch_to_result(&o, head_tree, &result, 1, show_output);\n+\tclean = result.clean;\n \tif (clean < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn clean;\n-- \ngitgitgadget\n\n"},{"id":"515885","messageId":"8821f22d5eac351cbf05505668b1bdff9705a982.1744127323.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 5/8] merge, sequencer: switch recursive merges over to ort","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:39Z","receivedAt":"2025-04-08T15:48:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nMore precisely, replace calls to merge_recursive() with\nmerge_ort_recursive().\n\nAlso change t7615 to quit calling out recursive; it is not needed\nanymore, and we are in fact using ort now.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c                            |  9 ++-------\n sequencer.c                                | 23 ++++++++--------------\n t/t7615-diff-algo-with-mergy-operations.sh |  2 --\n 3 files changed, 10 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex ba9faf126aa..c0bbdab7104 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -39,7 +39,6 @@\n #include \"rerere.h\"\n #include \"help.h\"\n #include \"merge.h\"\n-#include \"merge-recursive.h\"\n #include \"merge-ort-wrappers.h\"\n #include \"resolve-undo.h\"\n #include \"remote.h\"\n@@ -750,12 +749,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \n \t\trepo_hold_locked_index(the_repository, &lock,\n \t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (!strcmp(strategy, \"ort\"))\n-\t\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\t    reversed, &result);\n-\t\telse\n-\t\t\tclean = merge_recursive(&o, head, remoteheads->item,\n-\t\t\t\t\t\treversed, &result);\n+\t\tclean = merge_ort_recursive(&o, head, remoteheads->item,\n+\t\t\t\t\t    reversed, &result);\n \t\tfree_commit_list(reversed);\n \t\tstrbuf_release(&o.obuf);\n \ndiff --git a/sequencer.c b/sequencer.c\nindex b5d91fd3515..8bb49735891 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4319,20 +4319,13 @@ static int do_merge(struct repository *r,\n \to.branch2 = ref_name.buf;\n \to.buffer_output = 2;\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"ort\")) {\n-\t\t/*\n-\t\t * TODO: Should use merge_incore_recursive() and\n-\t\t * merge_switch_to_result(), skipping the call to\n-\t\t * merge_switch_to_result() when we don't actually need to\n-\t\t * update the index and working copy immediately.\n-\t\t */\n-\t\tret = merge_ort_recursive(&o,\n-\t\t\t\t\t  head_commit, merge_commit, bases,\n-\t\t\t\t\t  &i);\n-\t} else {\n-\t\tret = merge_recursive(&o, head_commit, merge_commit, bases,\n-\t\t\t\t      &i);\n-\t}\n+\t/*\n+\t * TODO: Should use merge_incore_recursive() and\n+\t * merge_switch_to_result(), skipping the call to\n+\t * merge_switch_to_result() when we don't actually need to\n+\t * update the index and working copy immediately.\n+\t */\n+\tret = merge_ort_recursive(&o, head_commit, merge_commit, bases, &i);\n \tif (ret <= 0)\n \t\tfputs(o.obuf.buf, stdout);\n \tstrbuf_release(&o.obuf);\n@@ -4343,7 +4336,7 @@ static int do_merge(struct repository *r,\n \t\tgoto leave_merge;\n \t}\n \t/*\n-\t * The return value of merge_recursive() is 1 on clean, and 0 on\n+\t * The return value of merge_ort_recursive() is 1 on clean, and 0 on\n \t * unclean merge.\n \t *\n \t * Let's reverse that, so that do_merge() returns 0 upon success and\ndiff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh\nindex ac5863e788c..5822d02d517 100755\n--- a/t/t7615-diff-algo-with-mergy-operations.sh\n+++ b/t/t7615-diff-algo-with-mergy-operations.sh\n@@ -22,8 +22,6 @@ test_expect_success 'setup' '\n \tgit tag c2\n '\n \n-GIT_TEST_MERGE_ALGORITHM=recursive\n-\n test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '\n \tgit reset --hard c1 &&\n \ttest_must_fail git merge -s recursive -Xdiff-algorithm=myers c2\n-- \ngitgitgadget\n\n"},{"id":"515886","messageId":"bf2d462c4e5bbb1e44ebb1162d7204d205527208.1744127323.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 8/8] builtin/{merge,rebase,revert}: remove GIT_TEST_MERGE_ALGORITHM","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:42Z","receivedAt":"2025-04-08T15:48:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nThis environment variable existed to allow the testsuite to reuse all\nthe merge-related tests in the testsuite while easily flipping between\nthe 'recursive' and the 'ort' backends.  Now that we have removed\nmerge-recursive and remapped 'recursive' to mean 'ort', we don't need\nthis scaffolding anymore.  Remove it from these three builtins.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n builtin/merge.c  | 14 +-------------\n builtin/rebase.c |  5 -----\n builtin/revert.c |  2 --\n 3 files changed, 1 insertion(+), 20 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex c0bbdab7104..9efd585842f 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -170,7 +170,7 @@ static struct strategy *get_strategy(const char *name)\n \tstruct strategy *ret;\n \tstatic struct cmdnames main_cmds = {0}, other_cmds = {0};\n \tstatic int loaded;\n-\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n+\tchar *default_strategy = NULL;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -1311,12 +1311,6 @@ int cmd_merge(int argc,\n \tif (branch)\n \t\tskip_prefix(branch, \"refs/heads/\", &branch);\n \n-\tif (!pull_twohead) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy && !strcmp(default_strategy, \"ort\"))\n-\t\t\tpull_twohead = xstrdup(\"ort\");\n-\t}\n-\n \tinit_diff_ui_defaults();\n \tgit_config(git_merge_config, NULL);\n \n@@ -1517,12 +1511,6 @@ int cmd_merge(int argc,\n \t\t\tfast_forward = FF_NO;\n \t}\n \n-\tif (!use_strategies && !pull_twohead &&\n-\t    remoteheads && !remoteheads->next) {\n-\t\tchar *default_strategy = getenv(\"GIT_TEST_MERGE_ALGORITHM\");\n-\t\tif (default_strategy)\n-\t\t\tappend_strategy(get_strategy(default_strategy));\n-\t}\n \tif (!use_strategies) {\n \t\tif (!remoteheads)\n \t\t\t; /* already up-to-date */\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex d4715ed35d7..e83193ac73e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1575,11 +1575,6 @@ int cmd_rebase(int argc,\n \t\t\t    options.default_backend);\n \t}\n \n-\tif (options.type == REBASE_MERGE &&\n-\t    !options.strategy &&\n-\t    getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\toptions.strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n-\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \t\toptions.state_dir = merge_dir();\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex aca6c293cdf..2654f769a88 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -252,8 +252,6 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,\n \t\tfree(opts->strategy);\n \t\topts->strategy = xstrdup_or_null(strategy);\n \t}\n-\tif (!opts->strategy && getenv(\"GIT_TEST_MERGE_ALGORITHM\"))\n-\t\topts->strategy = xstrdup(getenv(\"GIT_TEST_MERGE_ALGORITHM\"));\n \tfree(options);\n \n \tif (cmd == 'q') {\n-- \ngitgitgadget\n"},{"id":"515887","messageId":"5dce9096e236c5f9880fb07d96bde2719f314e1a.1744127323.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 7/8] tests: remove GIT_TEST_MERGE_ALGORITHM and test_expect_merge_algorithm","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:41Z","receivedAt":"2025-04-08T15:48:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nBoth of these existed to allow us to reuse all the merge-related tests\nin the testsuite while easily flipping between the 'recursive' and the\n'ort' backends.  Now that we have removed merge-recursive and remapped\n'recursive' to mean 'ort', we don't need this scaffolding anymore.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n ci/run-build-and-tests.sh                     |   1 -\n t/lib-merge.sh                                |  13 -\n t/t1092-sparse-checkout-compatibility.sh      |   2 -\n t/t2501-cwd-empty.sh                          |   2 -\n t/t3512-cherry-pick-submodule.sh              |   5 -\n t/t3513-revert-submodule.sh                   |   4 -\n t/t4069-remerge-diff.sh                       |   7 -\n t/t4301-merge-tree-write-tree.sh              |   7 -\n t/t5572-pull-submodule.sh                     |   5 -\n t/t6400-merge-df.sh                           |  14 +-\n t/t6402-merge-rename.sh                       | 125 +----\n t/t6404-recursive-merge.sh                    |  21 +-\n t/t6406-merge-attr.sh                         |   7 +-\n t/t6416-recursive-corner-cases.sh             | 194 ++-----\n t/t6421-merge-partial-clone.sh                |   7 +-\n t/t6422-merge-rename-corner-cases.sh          |  31 +-\n t/t6423-merge-rename-directories.sh           | 517 ++++--------------\n t/t6424-merge-unrelated-index-changes.sh      |   4 +-\n t/t6426-merge-skip-unneeded-updates.sh        |   4 +-\n t/t6428-merge-conflicts-sparse.sh             |   2 -\n t/t6430-merge-recursive.sh                    |   3 +-\n t/t6436-merge-overwrite.sh                    |  17 +-\n t/t6437-submodule-merge.sh                    |  65 +--\n t/t6438-submodule-directory-file-conflicts.sh |   5 -\n t/t6439-merge-co-error-msgs.sh                |   2 +-\n t/t7402-submodule-rebase.sh                   |   7 +-\n t/t7602-merge-octopus-many.sh                 |   9 +-\n t/t7610-mergetool.sh                          |  40 +-\n t/test-lib.sh                                 |   2 -\n 29 files changed, 248 insertions(+), 874 deletions(-)\n delete mode 100644 t/lib-merge.sh\n\ndiff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh\nindex 1c698467235..f99b7db2ee8 100755\n--- a/ci/run-build-and-tests.sh\n+++ b/ci/run-build-and-tests.sh\n@@ -20,7 +20,6 @@ linux-breaking-changes)\n linux-TEST-vars)\n \texport OPENSSL_SHA1_UNSAFE=YesPlease\n \texport GIT_TEST_SPLIT_INDEX=yes\n-\texport GIT_TEST_MERGE_ALGORITHM=recursive\n \texport GIT_TEST_FULL_IN_PACK_ARRAY=true\n \texport GIT_TEST_OE_SIZE=10\n \texport GIT_TEST_OE_DELTA_SIZE=5\ndiff --git a/t/lib-merge.sh b/t/lib-merge.sh\ndeleted file mode 100644\nindex 8734ebfc17f..00000000000\n--- a/t/lib-merge.sh\n+++ /dev/null\n@@ -1,13 +0,0 @@\n-# Helper functions used by merge tests.\n-\n-test_expect_merge_algorithm () {\n-\tstatus_for_recursive=$1 status_for_ort=$2\n-\tshift 2\n-\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_expect_${status_for_ort} \"$@\"\n-\telse\n-\t\ttest_expect_${status_for_recursive} \"$@\"\n-\tfi\n-}\ndiff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh\nindex a4c7c41fc00..f9b448792cb 100755\n--- a/t/t1092-sparse-checkout-compatibility.sh\n+++ b/t/t1092-sparse-checkout-compatibility.sh\n@@ -1486,7 +1486,6 @@ test_expect_success 'sparse-index is not expanded' '\n \tensure_not_expanded checkout -f update-deep &&\n \ttest_config -C sparse-index pull.twohead ort &&\n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tfor OPERATION in \"merge -m merge\" cherry-pick rebase\n \t\tdo\n \t\t\tensure_not_expanded merge -m merge update-folder1 &&\n@@ -1506,7 +1505,6 @@ test_expect_success 'sparse-index is not expanded: merge conflict in cone' '\n \tdone &&\n \n \t(\n-\t\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n \t\tgit -C sparse-index config pull.twohead ort &&\n \t\tensure_not_expanded ! merge -m merged expand-right\n \t)\ndiff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh\nindex f6d8d7d03d7..be9140bbaa4 100755\n--- a/t/t2501-cwd-empty.sh\n+++ b/t/t2501-cwd-empty.sh\n@@ -117,8 +117,6 @@ test_expect_success 'merge fails if cwd needs to be removed; recursive friendly'\n \tgrep \"Refusing to remove the current working directory\" error\n '\n \n-GIT_TEST_MERGE_ALGORITHM=ort\n-\n test_expect_success 'merge fails if cwd needs to be removed' '\n \ttest_required_dir_removal git merge fd_conflict\n '\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nindex f22d1ddead1..85a79326977 100755\n--- a/t/t3512-cherry-pick-submodule.sh\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -8,11 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"cherry-pick\"\n \n test_expect_success 'unrelated submodule/file conflict is ignored' '\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nindex 8bfe3ed2467..32e15c72eee 100755\n--- a/t/t3513-revert-submodule.sh\n+++ b/t/t3513-revert-submodule.sh\n@@ -30,10 +30,6 @@ git_revert () {\n \tgit revert HEAD\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-fi\n test_submodule_switch_func \"git_revert\"\n \n test_done\ndiff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh\nindex c6c94aef14d..966882ce912 100755\n--- a/t/t4069-remerge-diff.sh\n+++ b/t/t4069-remerge-diff.sh\n@@ -4,13 +4,6 @@ test_description='remerge-diff handling'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"${GIT_TEST_MERGE_ALGORITHM}\" != ort\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success 'setup basic merges' '\n \ttest_write_lines 1 2 3 4 5 6 7 8 9 >numbers &&\n \tgit add numbers &&\ndiff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh\nindex 44f7d077593..f9c5883a7f7 100755\n--- a/t/t4301-merge-tree-write-tree.sh\n+++ b/t/t4301-merge-tree-write-tree.sh\n@@ -4,13 +4,6 @@ test_description='git merge-tree --write-tree'\n \n . ./test-lib.sh\n \n-# This test is ort-specific\n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != \"ort\"\n-then\n-\tskip_all=\"GIT_TEST_MERGE_ALGORITHM != ort\"\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \ttest_write_lines 1 2 3 4 5 >numbers &&\n \techo hello >greeting &&\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nindex f7650e8475e..45f384dd328 100755\n--- a/t/t5572-pull-submodule.sh\n+++ b/t/t5572-pull-submodule.sh\n@@ -45,11 +45,6 @@ git_pull_noff () {\n \t$2 git pull --no-ff\n }\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch_func \"git_pull_noff\"\n \n test_expect_success 'setup' '\ndiff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh\nindex 3de4ef6bd9e..b46fe494409 100755\n--- a/t/t6400-merge-df.sh\n+++ b/t/t6400-merge-df.sh\n@@ -84,12 +84,7 @@ test_expect_success 'modify/delete + directory/file conflict' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\n@@ -105,12 +100,7 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '\n \n \ttest_stdout_line_count = 5 git ls-files -s &&\n \ttest_stdout_line_count = 4 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file letters/file &&\n \ttest_path_is_file letters.txt &&\ndiff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh\nindex 2738b50c2a9..ff00b74e9c1 100755\n--- a/t/t6402-merge-rename.sh\n+++ b/t/t6402-merge-rename.sh\n@@ -313,12 +313,7 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '\n \n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~HEAD instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~HEAD instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~HEAD instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -340,12 +335,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \t! grep \"error: refusing to lose untracked file at\" errors &&\n \ttest_grep \"CONFLICT (modify/delete): dir/file-in-the-way\" output &&\n \ttest_grep \"Auto-merging dir\" output &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output\n-\telse\n-\t\ttest_grep \"Adding as dir~renamed-file-has-no-conflicts instead\" output\n-\tfi &&\n+\ttest_grep \"moving it to dir~renamed-file-has-no-conflicts instead\" output &&\n \n \ttest_stdout_line_count = 3 git ls-files -u &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n@@ -400,14 +390,7 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t\n \ttest_must_fail git merge --strategy=recursive dir-in-way &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~HEAD &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -425,14 +408,7 @@ test_expect_success 'Same as previous, but merged other way' '\n \ttest_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&\n \n \ttest_stdout_line_count = 5 git ls-files -u &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts\n-\telse\n-\t\tgit ls-files -u dir >out &&\n-\t\ttest 3 -eq $(grep -v file-in-the-way out | wc -l) &&\n-\t\trm -f out\n-\tfi &&\n+\ttest_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts &&\n \ttest_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&\n \n \ttest_must_fail git diff --quiet &&\n@@ -488,12 +464,7 @@ test_expect_success 'both rename source and destination involved in D/F conflict\n \tgit checkout -q rename-dest^0 &&\n \ttest_must_fail git merge --strategy=recursive source-conflict &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 2 git ls-files -u\n-\telse\n-\t\ttest_stdout_line_count = 1 git ls-files -u\n-\tfi &&\n+\ttest_stdout_line_count = 2 git ls-files -u &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -527,63 +498,33 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '\n \tgit commit -m \"Rename one/file -> two\"\n '\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-then\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n-\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two &&\n-\n-\t\ttest_must_fail git diff --quiet &&\n-\n-\t\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n-\n-\t\ttest_path_is_file one &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-else\n-\ttest_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n-\t\tgit checkout -q rename-one^0 &&\n-\t\tmkdir one &&\n-\t\ttest_must_fail git merge --strategy=recursive rename-two &&\n+test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '\n+\tgit checkout -q rename-one^0 &&\n+\tmkdir one &&\n+\ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n-\t\ttest_must_fail git diff --quiet &&\n+\ttest_must_fail git diff --quiet &&\n \n-\t\ttest 4 -eq $(find . | grep -v .git | wc -l) &&\n+\ttest 3 -eq $(find . | grep -v .git | wc -l) &&\n \n-\t\ttest_path_is_dir one &&\n-\t\ttest_path_is_file one~rename-two &&\n-\t\ttest_path_is_file two &&\n-\t\ttest \"other\" = $(cat one~rename-two) &&\n-\t\ttest \"stuff\" = $(cat two)\n-\t'\n-fi\n+\ttest_path_is_file one &&\n+\ttest_path_is_file two &&\n+\ttest \"other\" = $(cat one) &&\n+\ttest \"stuff\" = $(cat two)\n+'\n \n test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '\n \tgit reset --hard &&\n \tgit clean -fdqx &&\n \ttest_must_fail git merge --strategy=recursive rename-two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 4 git ls-files -u &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 2 git ls-files -u two\n-\telse\n-\t\ttest_stdout_line_count = 2 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two\n-\tfi &&\n+\ttest_stdout_line_count = 4 git ls-files -u &&\n+\ttest_stdout_line_count = 2 git ls-files -u one &&\n+\ttest_stdout_line_count = 2 git ls-files -u two &&\n \n \ttest_must_fail git diff --quiet &&\n \n@@ -623,22 +564,12 @@ test_expect_success 'check handling of differently renamed file with D/F conflic\n \tgit checkout -q first-rename^0 &&\n \ttest_must_fail git merge --strategy=recursive second-rename &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 0 git ls-files -o\n-\telse\n-\t\ttest_stdout_line_count = 5 git ls-files -s &&\n-\t\ttest_stdout_line_count = 3 git ls-files -u &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u one &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u two &&\n-\t\ttest_stdout_line_count = 1 git ls-files -u original &&\n-\t\ttest_stdout_line_count = 2 git ls-files -o\n-\tfi &&\n+\ttest_stdout_line_count = 5 git ls-files -s &&\n+\ttest_stdout_line_count = 3 git ls-files -u &&\n+\ttest_stdout_line_count = 1 git ls-files -u one~HEAD &&\n+\ttest_stdout_line_count = 1 git ls-files -u two~second-rename &&\n+\ttest_stdout_line_count = 1 git ls-files -u original &&\n+\ttest_stdout_line_count = 0 git ls-files -o &&\n \n \ttest_path_is_file one/file &&\n \ttest_path_is_file two/file &&\ndiff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh\nindex ae687f2ce54..346f3608b98 100755\n--- a/t/t6404-recursive-merge.sh\n+++ b/t/t6404-recursive-merge.sh\n@@ -108,12 +108,7 @@ test_expect_success 'refuse to merge binary files' '\n \tprintf \"\\0\\0\" >binary-file &&\n \tgit add binary-file &&\n \tgit commit -m binary2 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge F >merge_output\n-\telse\n-\t\ttest_must_fail git merge F 2>merge_output\n-\tfi &&\n+\ttest_must_fail git merge F >merge_output &&\n \tgrep \"Cannot merge binary files: binary-file (HEAD vs. F)\" merge_output\n '\n \n@@ -129,22 +124,12 @@ test_expect_success 'mark rename/delete as unmerged' '\n \ttest_tick &&\n \tgit commit -m rename &&\n \ttest_must_fail git merge delete &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \tgit rev-parse --verify :2:a2 &&\n \ttest_must_fail git rev-parse --verify :3:a2 &&\n \tgit checkout -f delete &&\n \ttest_must_fail git merge rename &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest 2 = $(git ls-files --unmerged | wc -l)\n-\telse\n-\t\ttest 1 = $(git ls-files --unmerged | wc -l)\n-\tfi &&\n+\ttest 2 = $(git ls-files --unmerged | wc -l) &&\n \ttest_must_fail git rev-parse --verify :2:a2 &&\n \tgit rev-parse --verify :3:a2\n '\ndiff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh\nindex 66e01464b5e..8f6fbef0024 100755\n--- a/t/t6406-merge-attr.sh\n+++ b/t/t6406-merge-attr.sh\n@@ -259,12 +259,7 @@ test_expect_success 'binary files with union attribute' '\n \tprintf \"two\\0\" >bin.txt &&\n \tgit commit -am two &&\n \n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge bin-main >output\n-\telse\n-\t\ttest_must_fail git merge bin-main 2>output\n-\tfi &&\n+\ttest_must_fail git merge bin-main >output &&\n \tgrep -i \"warning.*cannot merge.*HEAD vs. bin-main\" output\n '\n \ndiff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh\nindex 17b54d625d0..ed20de8ea22 100755\n--- a/t/t6416-recursive-corner-cases.sh\n+++ b/t/t6416-recursive-corner-cases.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n #  L1  L2\n@@ -529,15 +528,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git merge C^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~HEAD\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~HEAD &&\n \t\tgit cat-file -p B:a >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m D2 &&\n@@ -556,12 +548,7 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd\n-\t\tfi &&\n+\t\tgit rm a~B^0 &&\n \t\tgit rm -rf a/ &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a &&\n \t\tgit add a &&\n@@ -570,15 +557,8 @@ test_expect_success 'setup differently handled merges of directory/file conflict\n \n \t\tgit checkout C^0 &&\n \t\ttest_must_fail git merge B^0 &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a~B^0\n-\t\telse\n-\t\t\tgit clean -fd &&\n-\t\t\tgit rm -rf a/ &&\n-\t\t\tgit rm a\n-\t\tfi &&\n+\t\tgit rm -rf a/ &&\n+\t\tgit rm a~B^0 &&\n \t\ttest_write_lines 1 2 3 4 5 6 7 8 >a2 &&\n \t\tgit add a2 &&\n \t\tgit commit -m E4 &&\n@@ -596,34 +576,16 @@ test_expect_success 'merge of D1 & E1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :2:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    A:ignore-me  B:a D1:a &&\n+\t\tgit rev-parse >actual   :0:ignore-me :1:a :2:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -637,34 +599,18 @@ test_expect_success 'merge of E1 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a  D1:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :1:a :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tA:ignore-me  B:a &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:0:ignore-me :3:a &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tA:ignore-me  B:a  D1:a &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:0:ignore-me :1:a :3:a &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n@@ -678,32 +624,17 @@ test_expect_success 'merge of D1 & E2 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive E2^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a    E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:2:a   :3:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~HEAD :2:a~HEAD :3:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~HEAD\n@@ -720,32 +651,17 @@ test_expect_success 'merge of E2 & D1 fails but has appropriate contents' '\n \n \t\ttest_must_fail git merge -s recursive D1^0 &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >expect    \\\n-\t\t\t\tB:a   E2:a/file  C:a/file   A:ignore-me &&\n-\t\t\tgit rev-parse   >actual   \\\n-\t\t\t\t:3:a  :2:a/file  :1:a/file  :0:ignore-me\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >expect    \\\n+\t\t\tB:a       D1:a      E2:a/file  C:a/file   A:ignore-me &&\n+\t\tgit rev-parse   >actual   \\\n+\t\t\t:1:a~D1^0 :3:a~D1^0 :2:a/file  :1:a/file  :0:ignore-me &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file a~D1^0\n@@ -777,7 +693,7 @@ test_expect_success 'merge of D1 & E3 succeeds' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n+test_expect_success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' '\n \ttest_when_finished \"git -C directory-file reset --hard\" &&\n \ttest_when_finished \"git -C directory-file clean -fdqx\" &&\n \t(\n@@ -1140,7 +1056,7 @@ test_expect_success 'setup symlink modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink modify/modify' '\n+test_expect_success 'check symlink modify/modify' '\n \t(\n \t\tcd symlink-modify-modify &&\n \n@@ -1206,7 +1122,7 @@ test_expect_success 'setup symlink add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check symlink add/add' '\n+test_expect_success 'check symlink add/add' '\n \t(\n \t\tcd symlink-add-add &&\n \n@@ -1294,7 +1210,7 @@ test_expect_success 'setup submodule modify/modify' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule modify/modify' '\n+test_expect_success 'check submodule modify/modify' '\n \t(\n \t\tcd submodule-modify-modify &&\n \n@@ -1382,7 +1298,7 @@ test_expect_success 'setup submodule add/add' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check submodule add/add' '\n+test_expect_success 'check submodule add/add' '\n \t(\n \t\tcd submodule-add-add &&\n \n@@ -1457,7 +1373,7 @@ test_expect_success 'setup conflicting entry types (submodule vs symlink)' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'check conflicting entry types (submodule vs symlink)' '\n+test_expect_success 'check conflicting entry types (submodule vs symlink)' '\n \t(\n \t\tcd submodule-symlink-add-add &&\n \ndiff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh\nindex b99f29ef9ba..6eb51285a0c 100755\n--- a/t/t6421-merge-partial-clone.sh\n+++ b/t/t6421-merge-partial-clone.sh\n@@ -27,7 +27,6 @@ test_description=\"limiting blob downloads when merging with partial clones\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_repo () {\n \ttest -d server && return\n@@ -207,7 +206,7 @@ test_setup_repo () {\n #\n #   Summary: 2 fetches (1 for 2 objects, 1 for 1 object)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded for single relevant rename' '\n+test_expect_success 'Objects downloaded for single relevant rename' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-single &&\n \t(\n@@ -297,7 +296,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded for single relev\n #      this are not all that common.)\n #   Summary: 1 fetches for 6 objects\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded when a directory rename triggered' '\n+test_expect_success 'Objects downloaded when a directory rename triggered' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-dir &&\n \t(\n@@ -399,7 +398,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory\n #\n #   Summary: 4 fetches (1 for 6 objects, 1 for 8, 1 for 3, 1 for 2)\n #\n-test_expect_merge_algorithm failure success 'Objects downloaded with lots of renames and modifications' '\n+test_expect_success 'Objects downloaded with lots of renames and modifications' '\n \ttest_setup_repo &&\n \tgit clone --sparse --filter=blob:none \"file://$(pwd)/server\" objects-many &&\n \t(\ndiff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh\nindex 62b49c67e22..9cbe7ca7824 100755\n--- a/t/t6422-merge-rename-corner-cases.sh\n+++ b/t/t6422-merge-rename-corner-cases.sh\n@@ -7,7 +7,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_setup_rename_delete_untracked () {\n \tgit init rename-delete-untracked &&\n@@ -316,12 +315,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\techo 0 >expect &&\n \t\tgit cat-file -p base:file >>expect &&\n@@ -350,12 +344,7 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 3 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out\n-\t\telse\n-\t\t\ttest_line_count = 2 out\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n \n \t\tgit cat-file -p left-conflict:newfile >left &&\n \t\tgit cat-file -p base:file    >base &&\n@@ -369,14 +358,8 @@ test_expect_success 'rename/directory conflict + content merge conflict' '\n \n \t\tgit rev-parse >expect   \\\n \t\t\tbase:file       left-conflict:newfile right:file &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD\n-\t\telse\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:1:newfile      :2:newfile      :3:newfile\n-\t\tfi &&\n+\t\tgit rev-parse >actual \\\n+\t\t\t:1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD &&\n \t\ttest_cmp expect actual &&\n \n \t\ttest_path_is_file newfile/realfile &&\n@@ -896,7 +879,7 @@ test_setup_rad () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rad-check: rename/add/delete conflict' '\n+test_expect_success 'rad-check: rename/add/delete conflict' '\n \ttest_setup_rad &&\n \t(\n \t\tcd rad &&\n@@ -969,7 +952,7 @@ test_setup_rrdd () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n+test_expect_success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '\n \ttest_setup_rrdd &&\n \t(\n \t\tcd rrdd &&\n@@ -1058,7 +1041,7 @@ test_setup_mod6 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n+test_expect_success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '\n \ttest_setup_mod6 &&\n \t(\n \t\tcd mod6 &&\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex e0785410cd9..f48ed6d0353 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -26,8 +26,6 @@ test_description=\"recursive merge with directory renames\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Basic cases we should be able to handle\n@@ -302,20 +300,11 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'\n \t\tgit cat-file -p :2:x/wham >expect &&\n \t\tgit cat-file -p :3:x/wham >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/wham\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/wham\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/wham\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/wham\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect x/wham\n \t)\n '\n@@ -1186,18 +1175,10 @@ test_expect_success '5d: Directory/file/file conflict due to directory rename' '\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 1 out &&\n \t\tgit ls-files -o >out &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e\n-\t\telse\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d      :0:y/d/e\n-\t\tfi &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t    :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e &&\n \t\tgit rev-parse >expect \\\n \t\t\t O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&\n \t\ttest_cmp expect actual &&\n@@ -1280,32 +1261,17 @@ test_expect_success '6a: Tricky rename/delete' '\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*z/c.*y/c\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :1:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:z/c\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 3 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :1:y/c :3:y/c &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:z/c &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -1372,7 +1338,7 @@ test_setup_6b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b1: Same renames done on both sides, plus another rename' '\n+test_expect_success '6b1: Same renames done on both sides, plus another rename' '\n \ttest_setup_6b1 &&\n \t(\n \t\tcd 6b1 &&\n@@ -1445,7 +1411,7 @@ test_setup_6b2 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '6b2: Same rename done on both sides' '\n+test_expect_success '6b2: Same rename done on both sides' '\n \ttest_setup_6b2 &&\n \t(\n \t\tcd 6b2 &&\n@@ -1832,20 +1798,11 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'\n \t\tgit cat-file -p :2:y/d >expect &&\n \t\tgit cat-file -p :3:y/d >other &&\n \t\t>empty &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD:y/d\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0:z/d\" \\\n-\t\t\t\texpect empty other\n-\t\telse\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other\n-\t\tfi &&\n+\t\ttest_must_fail git merge-file \\\n+\t\t\t-L \"HEAD:y/d\" \\\n+\t\t\t-L \"\" \\\n+\t\t\t-L \"B^0:z/d\" \\\n+\t\t\texpect empty other &&\n \t\ttest_cmp expect y/d\n \t)\n '\n@@ -1967,32 +1924,17 @@ test_expect_success '7d: transitive rename involved in rename/delete; how is it\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d  O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:y/b :0:y/c :1:y/d :3:y/d &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t O:z/b  O:z/c  O:x/d  O:x/d &&\n \t\ttest_cmp expect actual\n \t)\n '\n@@ -2073,32 +2015,17 @@ test_expect_success '7e: transitive rename in rename/delete AND dirs in the way'\n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&\n \t\ttest_grep \"CONFLICT (rename/delete).*x/d.*y/d\" out &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d\n-\t\telse\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d\n-\t\tfi &&\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 2 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 1 out &&\n+\n+\t\tgit rev-parse >actual \\\n+\t\t\t:0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&\n+\t\tgit rev-parse >expect \\\n+\t\t\t A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d &&\n \t\ttest_cmp expect actual &&\n \n \t\tgit hash-object y/d~B^0 >actual &&\n@@ -3284,34 +3211,15 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '\n \t\techo contents >y/e &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/delete).*Version B\\^0 of y/d left in tree at y/d~B\\^0\" out &&\n-\t\t\ttest_grep \"Error: Refusing to lose untracked file at y/e; writing to y/e~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 5 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/b :3:y/d :3:y/e &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\tO:z/b  O:z/c  B:z/e &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 1 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 5 out &&\n \n \t\techo very >expect &&\n \t\ttest_cmp expect y/c &&\n@@ -3374,38 +3282,15 @@ test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~B\\^0 instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~B^0 >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3425,38 +3310,15 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth\n \t\techo important >y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/c; adding as y/c~HEAD instead\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse O:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 4 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/c\n@@ -3514,47 +3376,15 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '\n \t\techo important >y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose untracked file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 6 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: The following untracked working tree files would be overwritten by merge\" err &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 6 out &&\n+\t\tgit ls-files -u >out &&\n+\t\ttest_line_count = 0 out &&\n+\t\tgit ls-files -o >out &&\n+\t\ttest_line_count = 3 out &&\n \n \t\techo important >expect &&\n \t\ttest_cmp expect y/wham\n@@ -3596,7 +3426,7 @@ test_setup_10e () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '10e: Does git complain about untracked file that is not really in the way?' '\n+test_expect_success '10e: Does git complain about untracked file that is not really in the way?' '\n \ttest_setup_10e &&\n \t(\n \t\tcd 10e &&\n@@ -3687,30 +3517,8 @@ test_expect_success '11a: Avoid losing dirty contents with simple rename' '\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:z/a :2:z/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  B:z/b &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object z/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:z/b >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo stuff >>expected &&\n@@ -3766,34 +3574,9 @@ test_expect_success '11b: Avoid losing dirty file involved in directory rename'\n \t\tgit checkout A^0 &&\n \t\techo stuff >>z/c &&\n \n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\tgit -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -m >out &&\n-\t\t\ttest_line_count = 0 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3850,13 +3633,8 @@ test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"following files would be overwritten by merge\" err\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff y/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -3924,30 +3702,8 @@ test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict'\n \t\techo stuff >>z/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"Refusing to lose dirty file at z/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 1 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:x/b :0:y/a :0:y/c/d :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:x/b  O:z/a  B:y/c/d  B:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\tgit hash-object y/c~HEAD >actual &&\n-\t\t\tgit rev-parse B:x/c >expect &&\n-\t\t\ttest_cmp expect actual\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\tgrep -q stuff z/c &&\n \t\ttest_seq 1 10 >expected &&\n@@ -4010,39 +3766,8 @@ test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to\n \t\techo mods >>y/c &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/c\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 7 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# See if y/c~merged has expected contents; requires manually\n-\t\t\t# doing the expected file merge\n-\t\t\tgit cat-file -p A:y/c >c1 &&\n-\t\t\tgit cat-file -p B:z/c >c2 &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\tc1 empty c2 &&\n-\t\t\ttest_cmp c1 y/c~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\techo different >expected &&\n \t\techo mods >>expected &&\n@@ -4099,40 +3824,8 @@ test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to\n \t\techo important >>y/wham &&\n \n \t\ttest_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&\n-\t\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t\tthen\n-\t\t\ttest_path_is_missing .git/MERGE_HEAD &&\n-\t\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err\n-\t\telse\n-\t\t\ttest_grep \"CONFLICT (rename/rename)\" out &&\n-\t\t\ttest_grep \"Refusing to lose dirty file at y/wham\" out &&\n-\n-\t\t\tgit ls-files -s >out &&\n-\t\t\ttest_line_count = 4 out &&\n-\t\t\tgit ls-files -u >out &&\n-\t\t\ttest_line_count = 2 out &&\n-\t\t\tgit ls-files -o >out &&\n-\t\t\ttest_line_count = 3 out &&\n-\n-\t\t\ttest_must_fail git rev-parse :1:y/wham &&\n-\n-\t\t\tgit rev-parse >actual \\\n-\t\t\t\t:0:y/a :0:y/b :2:y/wham :3:y/wham &&\n-\t\t\tgit rev-parse >expect \\\n-\t\t\t\t O:z/a  O:z/b  O:x/c     O:x/d &&\n-\t\t\ttest_cmp expect actual &&\n-\n-\t\t\t# Test that two-way merge in y/wham~merged is as expected\n-\t\t\tgit cat-file -p :2:y/wham >expect &&\n-\t\t\tgit cat-file -p :3:y/wham >other &&\n-\t\t\t>empty &&\n-\t\t\ttest_must_fail git merge-file \\\n-\t\t\t\t-L \"HEAD\" \\\n-\t\t\t\t-L \"\" \\\n-\t\t\t\t-L \"B^0\" \\\n-\t\t\t\texpect empty other &&\n-\t\t\ttest_cmp expect y/wham~merged\n-\t\tfi &&\n+\t\ttest_path_is_missing .git/MERGE_HEAD &&\n+\t\ttest_grep \"error: Your local changes to the following files would be overwritten by merge\" err &&\n \n \t\ttest_seq 1 10 >expected &&\n \t\techo important >>expected &&\n@@ -4267,7 +3960,7 @@ test_setup_12b1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12b1: Moving two directory hierarchies into each other' '\n+test_expect_success '12b1: Moving two directory hierarchies into each other' '\n \ttest_setup_12b1 &&\n \t(\n \t\tcd 12b1 &&\n@@ -4435,7 +4128,7 @@ test_setup_12c1 () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12c1: Moving one directory hierarchy into another w/ content merge' '\n+test_expect_success '12c1: Moving one directory hierarchy into another w/ content merge' '\n \ttest_setup_12c1 &&\n \t(\n \t\tcd 12c1 &&\n@@ -4797,7 +4490,7 @@ test_setup_12f () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '\n+test_expect_success '12f: Trivial directory resolve, caching, all kinds of fun' '\n \ttest_setup_12f &&\n \t(\n \t\tcd 12f &&\n@@ -5253,7 +4946,7 @@ test_setup_12l () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12l (B into A): Rename into each other + add/add conflict' '\n+test_expect_success '12l (B into A): Rename into each other + add/add conflict' '\n \ttest_setup_12l BintoA &&\n \t(\n \t\tcd 12l_BintoA &&\n@@ -5280,7 +4973,7 @@ test_expect_merge_algorithm failure success '12l (B into A): Rename into each ot\n \t)\n '\n \n-test_expect_merge_algorithm failure success '12l (A into B): Rename into each other + add/add conflict' '\n+test_expect_success '12l (A into B): Rename into each other + add/add conflict' '\n \ttest_setup_12l AintoB &&\n \t(\n \t\tcd 12l_AintoB &&\n@@ -5348,7 +5041,7 @@ test_setup_12m () {\n \t)\n }\n \n-test_expect_merge_algorithm failure success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\ndiff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh\nindex 084bfe7e6ce..ddc7524f6c1 100755\n--- a/t/t6424-merge-unrelated-index-changes.sh\n+++ b/t/t6424-merge-unrelated-index-changes.sh\n@@ -296,10 +296,8 @@ test_expect_success 'with multiple strategies, recursive or ort failure do not e\n \tgit add a &&\n \tgit rev-parse :a >expect &&\n \n-\tsane_unset GIT_TEST_MERGE_ALGORITHM &&\n-\ttest_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&\n+\ttest_must_fail git merge -s ort -s octopus C^0 >output 2>&1 &&\n \n-\tgrep \"Trying merge strategy recursive...\" output &&\n \tgrep \"Trying merge strategy ort...\" output &&\n \tgrep \"Trying merge strategy octopus...\" output &&\n \tgrep \"No merge strategy handled the merge.\" output &&\ndiff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh\nindex b059475ed03..404cd3f2ca1 100755\n--- a/t/t6426-merge-skip-unneeded-updates.sh\n+++ b/t/t6426-merge-skip-unneeded-updates.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n ###########################################################################\n # SECTION 1: Cases involving no renames (one side has subset of changes of\n@@ -663,7 +661,7 @@ test_setup_4a () {\n #   correct requires doing the merge in-memory first, then realizing that no\n #   updates to the file are necessary, and thus that we can just leave the path\n #   alone.\n-test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '\n+test_expect_success '4a: Change on A, change on B subset of A, dirty mods present' '\n \ttest_setup_4a &&\n \t(\n \t\tcd 4a &&\ndiff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh\nindex 9919c3fa7cd..c86e02c6e23 100755\n--- a/t/t6428-merge-conflicts-sparse.sh\n+++ b/t/t6428-merge-conflicts-sparse.sh\n@@ -23,8 +23,6 @@ test_description=\"merge cases\"\n #                     files that might be renamed into each other's paths.)\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n-\n \n # Testcase basic, conflicting changes in 'numerals'\n \ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex c539a68fd07..e59560a5dd9 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -6,7 +6,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n test_expect_success 'setup 1' '\n \n@@ -645,7 +644,7 @@ test_expect_success 'merge-recursive copy vs. rename' '\n \ttest_cmp expected actual\n '\n \n-test_expect_merge_algorithm failure success 'merge-recursive rename vs. rename/symlink' '\n+test_expect_success 'merge-recursive rename vs. rename/symlink' '\n \n \tgit checkout -f rename &&\n \tgit merge rename-ln &&\ndiff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh\nindex 4f4376421e7..70b5d2d6944 100755\n--- a/t/t6436-merge-overwrite.sh\n+++ b/t/t6436-merge-overwrite.sh\n@@ -101,19 +101,10 @@ test_expect_success 'will not overwrite unstaged changes in renamed file' '\n \tgit mv c1.c other.c &&\n \tgit commit -m rename &&\n \tcp important other.c &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\ttest_must_fail git merge c1a >out 2>err &&\n-\t\ttest_grep \"would be overwritten by merge\" err &&\n-\t\ttest_cmp important other.c &&\n-\t\ttest_path_is_missing .git/MERGE_HEAD\n-\telse\n-\t\ttest_must_fail git merge c1a >out &&\n-\t\ttest_grep \"Refusing to lose dirty file at other.c\" out &&\n-\t\ttest_path_is_file other.c~HEAD &&\n-\t\ttest $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&\n-\t\ttest_cmp important other.c\n-\tfi\n+\ttest_must_fail git merge c1a >out 2>err &&\n+\ttest_grep \"would be overwritten by merge\" err &&\n+\ttest_cmp important other.c &&\n+\ttest_path_is_missing .git/MERGE_HEAD\n '\n \n test_expect_success 'will not overwrite untracked subtree' '\ndiff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\nindex 4815559157b..a564758f528 100755\n--- a/t/t6437-submodule-merge.sh\n+++ b/t/t6437-submodule-merge.sh\n@@ -9,7 +9,6 @@ GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1\n export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB\n \n . ./test-lib.sh\n-. \"$TEST_DIRECTORY\"/lib-merge.sh\n \n #\n # history\n@@ -110,14 +109,10 @@ test_expect_success 'merging should conflict for non fast-forward' '\n \ttest_when_finished \"git -C merge-search reset --hard\" &&\n \t(cd merge-search &&\n \t git checkout -b test-nonforward-a b &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c 2>actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi)\n+\t test_must_fail git merge c 2>actual &&\n+\t sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t grep \"$sub_expect\" actual\n+\t )\n '\n \n test_expect_success 'finish setup for merge-search' '\n@@ -151,14 +146,9 @@ test_expect_success 'merging should conflict for non fast-forward (resolution ex\n \t git checkout -b test-nonforward-b b &&\n \t (cd sub &&\n \t  git rev-parse --short sub-d > ../expect) &&\n-\t  if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t  then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t  else\n-\t\ttest_must_fail git merge c 2> actual\n-\t  fi &&\n+\t  test_must_fail git merge c >actual 2>sub-actual &&\n+\t  sub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\t  grep \"$sub_expect\" sub-actual &&\n \t grep $(cat expect) actual > /dev/null &&\n \t git reset --hard)\n '\n@@ -169,23 +159,12 @@ test_expect_success 'merging should fail for ambiguous common parent' '\n \t(cd sub &&\n \t git checkout -b ambiguous sub-b &&\n \t git merge sub-c &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\tgit rev-parse --short sub-d >../expect1 &&\n-\t\tgit rev-parse --short ambiguous >../expect2\n-\t else\n-\t\tgit rev-parse sub-d > ../expect1 &&\n-\t\tgit rev-parse ambiguous > ../expect2\n-\t fi\n+\t git rev-parse --short sub-d >../expect1 &&\n+\t git rev-parse --short ambiguous >../expect2\n \t ) &&\n-\t if test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\t then\n-\t\ttest_must_fail git merge c >actual 2>sub-actual &&\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n-\t\tgrep \"$sub_expect\" sub-actual\n-\t else\n-\t\ttest_must_fail git merge c 2> actual\n-\t fi &&\n+\ttest_must_fail git merge c >actual 2>sub-actual &&\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)\" &&\n+\tgrep \"$sub_expect\" sub-actual &&\n \tgrep $(cat expect1) actual > /dev/null &&\n \tgrep $(cat expect2) actual > /dev/null &&\n \tgit reset --hard)\n@@ -227,11 +206,9 @@ test_expect_success 'merging should fail for changes that are backwards' '\n \n \tgit checkout -b test-backward e &&\n \ttest_must_fail git merge f 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n \n@@ -358,7 +335,7 @@ test_expect_success 'setup file/submodule conflict' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success 'file/submodule conflict' '\n+test_expect_success 'file/submodule conflict' '\n \ttest_when_finished \"git -C file-submodule reset --hard\" &&\n \t(\n \t\tcd file-submodule &&\n@@ -467,7 +444,7 @@ test_expect_failure 'directory/submodule conflict; keep submodule clean' '\n \t)\n '\n \n-test_expect_merge_algorithm failure success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n+test_expect_success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '\n \ttest_when_finished \"git -C directory-submodule/path reset --hard\" &&\n \ttest_when_finished \"git -C directory-submodule reset --hard\" &&\n \t(\n@@ -535,11 +512,9 @@ test_expect_success 'merging should fail with no merge base' '\n \tgit add sub &&\n \tgit commit -m \"b\" &&\n \ttest_must_fail git merge a 2>actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n-\t\tgrep \"$sub_expect\" actual\n-\tfi)\n+\tsub_expect=\"go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)\" &&\n+\tgrep \"$sub_expect\" actual\n+\t)\n '\n \n test_done\ndiff --git a/t/t6438-submodule-directory-file-conflicts.sh b/t/t6438-submodule-directory-file-conflicts.sh\nindex 8df67a0ef99..53d83c828a7 100755\n--- a/t/t6438-submodule-directory-file-conflicts.sh\n+++ b/t/t6438-submodule-directory-file-conflicts.sh\n@@ -12,11 +12,6 @@ test_submodule_switch \"merge --ff\"\n \n test_submodule_switch \"merge --ff-only\"\n \n-if test \"$GIT_TEST_MERGE_ALGORITHM\" != ort\n-then\n-\tKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n-\tKNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n-fi\n test_submodule_switch \"merge --no-ff\"\n \n test_done\ndiff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh\nindex 55bd744a3f4..643c9368e0e 100755\n--- a/t/t6439-merge-co-error-msgs.sh\n+++ b/t/t6439-merge-co-error-msgs.sh\n@@ -47,7 +47,7 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for\n \t\texport GIT_MERGE_VERBOSITY &&\n \t\ttest_must_fail git merge branch 2>out2\n \t) &&\n-\techo \"Merge with strategy ${GIT_TEST_MERGE_ALGORITHM:-ort} failed.\" >>expect &&\n+\techo \"Merge with strategy ort failed.\" >>expect &&\n \ttest_cmp out2 expect &&\n \tgit reset --hard HEAD^\n '\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex 25b33a1e875..06cee3432fe 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -124,11 +124,8 @@ test_expect_success 'rebasing submodule that should conflict' '\n \t\techo \"160000 $(git rev-parse HEAD) 3\tsubmodule\"\n \t) >expect &&\n \ttest_cmp expect actual &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-    then\n-\t\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n-\t\tgrep \"$sub_expect\" actual_output\n-\tfi\n+\tsub_expect=\"go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)\" &&\n+\tgrep \"$sub_expect\" actual_output\n '\n \n test_done\ndiff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh\nindex ff085b086cc..42f675b7399 100755\n--- a/t/t7602-merge-octopus-many.sh\n+++ b/t/t7602-merge-octopus-many.sh\n@@ -77,12 +77,9 @@ Merge made by the 'recursive' strategy.\n EOF\n \n test_expect_success 'merge reduces irrelevant remote heads' '\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv expected expected.tmp &&\n-\t\tsed s/recursive/ort/ expected.tmp >expected &&\n-\t\trm expected.tmp\n-\tfi &&\n+\tmv expected expected.tmp &&\n+\tsed s/recursive/ort/ expected.tmp >expected &&\n+\trm expected.tmp &&\n \tGIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&\n \ttest_cmp expected actual\n '\ndiff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh\nindex c077aba7ced..957f8e20ba3 100755\n--- a/t/t7610-mergetool.sh\n+++ b/t/t7610-mergetool.sh\n@@ -535,14 +535,9 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"c\" | git mergetool submod~HEAD &&\n-\t\tgit rm submod &&\n-\t\tgit mv submod~HEAD submod\n-\telse\n-\t\tyes \"l\" | git mergetool submod\n-\tfi &&\n+\tyes \"c\" | git mergetool submod~HEAD &&\n+\tgit rm submod &&\n+\tgit mv submod~HEAD submod &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod &&\n@@ -559,15 +554,10 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool file1 file2 spaced\\ name subdir/file3 &&\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tmv submod submod.orig &&\n-\t\tgit rm --cached submod &&\n-\t\tyes \"c\" | git mergetool submod~test19 &&\n-\t\tgit mv submod~test19 submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tmv submod submod.orig &&\n+\tgit rm --cached submod &&\n+\tyes \"c\" | git mergetool submod~test19 &&\n+\tgit mv submod~test19 submod &&\n \ttest -d submod.orig &&\n \tgit submodule update -N &&\n \techo \"not a submodule\" >expect &&\n@@ -585,10 +575,7 @@ test_expect_success 'file vs modified submodule' '\n \tyes \"\" | git mergetool both &&\n \tyes \"d\" | git mergetool file11 file12 &&\n \tyes \"l\" | git mergetool submod &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"d\" | git mergetool submod~test19\n-\tfi &&\n+\tyes \"d\" | git mergetool submod~test19 &&\n \techo \"main submodule\" >expect &&\n \ttest_cmp expect submod/bar &&\n \tgit submodule update -N &&\n@@ -686,14 +673,9 @@ test_expect_success 'directory vs modified submodule' '\n \ttest_must_fail git merge main &&\n \ttest -n \"$(git ls-files -u)\" &&\n \ttest ! -e submod.orig &&\n-\tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\n-\tthen\n-\t\tyes \"r\" | git mergetool submod~main &&\n-\t\tgit mv submod submod.orig &&\n-\t\tgit mv submod~main submod\n-\telse\n-\t\tyes \"r\" | git mergetool submod\n-\tfi &&\n+\tyes \"r\" | git mergetool submod~main &&\n+\tgit mv submod submod.orig &&\n+\tgit mv submod~main submod &&\n \ttest -d submod.orig &&\n \techo \"not a submodule\" >expect &&\n \ttest_cmp expect submod.orig/file16 &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..5952eb56e27 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -544,8 +544,6 @@ GIT_DEFAULT_HASH=\"${GIT_TEST_DEFAULT_HASH:-sha1}\"\n export GIT_DEFAULT_HASH\n GIT_DEFAULT_REF_FORMAT=\"${GIT_TEST_DEFAULT_REF_FORMAT:-files}\"\n export GIT_DEFAULT_REF_FORMAT\n-GIT_TEST_MERGE_ALGORITHM=\"${GIT_TEST_MERGE_ALGORITHM:-ort}\"\n-export GIT_TEST_MERGE_ALGORITHM\n \n # Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output\n GIT_TRACE_BARE=1\n-- \ngitgitgadget\n\n"},{"id":"515888","messageId":"e696cb472bdc69c20c3d01ef2f19f2e5fe8d8791.1744127323.git.gitgitgadget@gmail.com","threadId":"63226","inReplyTo":"pull.1898.v3.git.1744127322.gitgitgadget@gmail.com","subject":"[PATCH v3 6/8] merge-recursive.[ch]: thoroughly debug these","fromName":"Elijah Newren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-08T15:48:40Z","receivedAt":"2025-04-08T15:48:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nAs a wise man once told me, \"Deleted code is debugged code!\"  So, move\nthe functions that are shared between merge-recursive and merge-ort from\nthe former to the latter, and then debug the remainder of\nmerge-recursive.[ch].\n\nJoking aside, merge-ort was always intended to replace merge-recursive.\nIt has numerous advantages over merge-recursive (operates much faster,\ncan operate without a worktree or index, and fixes a number of known\nbugs and suboptimal merges).  Since we have now replaced all callers of\nmerge-recursive with equivalent functions from merge-ort, move the\nshared functions from the former to the latter, and delete the remainder\nof merge-recursive.[ch].\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/merge-strategies.adoc          |   24 +-\n Documentation/technical/sparse-checkout.adoc |    2 -\n Makefile                                     |    1 -\n merge-ort-wrappers.h                         |    2 +-\n merge-ort.c                                  |  159 +\n merge-ort.h                                  |   60 +-\n merge-recursive.c                            | 4080 ------------------\n merge-recursive.h                            |  132 -\n meson.build                                  |    1 -\n 9 files changed, 225 insertions(+), 4236 deletions(-)\n delete mode 100644 merge-recursive.c\n delete mode 100644 merge-recursive.h\n\ndiff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc\nindex 8c87dd70210..9e034f447e7 100644\n--- a/Documentation/merge-strategies.adoc\n+++ b/Documentation/merge-strategies.adoc\n@@ -109,23 +109,11 @@ subtree[=<path>];;\n \ttwo trees to match.\n \n recursive::\n-\tThis can only resolve two heads using a 3-way merge\n-\talgorithm.  When there is more than one common\n-\tancestor that can be used for 3-way merge, it creates a\n-\tmerged tree of the common ancestors and uses that as\n-\tthe reference tree for the 3-way merge.  This has been\n-\treported to result in fewer merge conflicts without\n-\tcausing mismerges by tests done on actual merge commits\n-\ttaken from Linux 2.6 kernel development history.\n-\tAdditionally this can detect and handle merges involving\n-\trenames.  It does not make use of detected copies.  This was\n-\tthe default strategy for resolving two heads from Git v0.99.9k\n-\tuntil v2.33.0.\n-+\n-For a path that is a submodule, the same caution as 'ort' applies to this\n-strategy.\n-+\n-The 'recursive' strategy takes the same options as 'ort'.\n+\tThis is now a synonym for `ort`.  It was an alternative\n+\timplementation until v2.49.0, but was redirected to mean `ort`\n+\tin v2.50.0.  The previous recursive strategy was the default\n+\tstrategy for resolving two heads from Git v0.99.9k until\n+\tv2.33.0.\n \n resolve::\n \tThis can only resolve two heads (i.e. the current branch\n@@ -146,7 +134,7 @@ ours::\n \tignoring all changes from all other branches.  It is meant to\n \tbe used to supersede old development history of side\n \tbranches.  Note that this is different from the -Xours option to\n-\tthe 'recursive' merge strategy.\n+\tthe 'ort' merge strategy.\n \n subtree::\n \tThis is a modified `ort` strategy. When merging trees A and\ndiff --git a/Documentation/technical/sparse-checkout.adoc b/Documentation/technical/sparse-checkout.adoc\nindex d9686593548..dc2e763bbec 100644\n--- a/Documentation/technical/sparse-checkout.adoc\n+++ b/Documentation/technical/sparse-checkout.adoc\n@@ -356,8 +356,6 @@ understanding these differences can be beneficial.\n     The behavior for these commands somewhat depends upon the merge\n     strategy being used:\n       * `ort` behaves as described above\n-      * `recursive` tries to not vivify files unnecessarily, but does sometimes\n-\tvivify files without conflicts.\n       * `octopus` and `resolve` will always vivify any file changed in the merge\n \trelative to the first parent, which is rather suboptimal.\n \ndiff --git a/Makefile b/Makefile\nindex ac32d2d0bda..4fbd29cc7e9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1069,7 +1069,6 @@ LIB_OBJS += merge-blobs.o\n LIB_OBJS += merge-ll.o\n LIB_OBJS += merge-ort.o\n LIB_OBJS += merge-ort-wrappers.o\n-LIB_OBJS += merge-recursive.o\n LIB_OBJS += merge.o\n LIB_OBJS += midx.o\n LIB_OBJS += midx-write.o\ndiff --git a/merge-ort-wrappers.h b/merge-ort-wrappers.h\nindex aeffa1c87b4..b7e1ced9d7f 100644\n--- a/merge-ort-wrappers.h\n+++ b/merge-ort-wrappers.h\n@@ -1,7 +1,7 @@\n #ifndef MERGE_ORT_WRAPPERS_H\n #define MERGE_ORT_WRAPPERS_H\n \n-#include \"merge-recursive.h\"\n+#include \"merge-ort.h\"\n \n /*\n  * rename-detecting three-way merge, no recursion.\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 14a7ae4a6bf..f943f5ddcba 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -26,6 +26,7 @@\n #include \"cache-tree.h\"\n #include \"commit.h\"\n #include \"commit-reach.h\"\n+#include \"config.h\"\n #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"dir.h\"\n@@ -5322,3 +5323,161 @@ void merge_incore_recursive(struct merge_options *opt,\n \tmerge_ort_internal(opt, merge_bases, side1, side2, result);\n \ttrace2_region_leave(\"merge\", \"incore_recursive\", opt->repo);\n }\n+\n+static void merge_recursive_config(struct merge_options *opt, int ui)\n+{\n+\tchar *value = NULL;\n+\tint renormalize = 0;\n+\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n+\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n+\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n+\topt->renormalize = renormalize;\n+\tif (!git_config_get_string(\"diff.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.renames\", &value)) {\n+\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n+\t\tfree(value);\n+\t}\n+\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n+\t\tint boolval = git_parse_maybe_bool(value);\n+\t\tif (0 <= boolval) {\n+\t\t\topt->detect_directory_renames = boolval ?\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n+\t\t} else if (!strcasecmp(value, \"conflict\")) {\n+\t\t\topt->detect_directory_renames =\n+\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n+\t\t} /* avoid erroring on values from future versions of git */\n+\t\tfree(value);\n+\t}\n+\tif (ui) {\n+\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n+\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n+\t\t\tif (diff_algorithm < 0)\n+\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n+\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n+\t\t\tfree(value);\n+\t\t}\n+\t}\n+\tgit_config(git_xmerge_config, NULL);\n+}\n+\n+static void init_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo, int ui)\n+{\n+\tconst char *merge_verbosity;\n+\tmemset(opt, 0, sizeof(struct merge_options));\n+\n+\topt->repo = repo;\n+\n+\topt->detect_renames = -1;\n+\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n+\topt->rename_limit = -1;\n+\n+\topt->verbosity = 2;\n+\topt->buffer_output = 1;\n+\tstrbuf_init(&opt->obuf, 0);\n+\n+\topt->renormalize = 0;\n+\n+\topt->conflict_style = -1;\n+\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\n+\tmerge_recursive_config(opt, ui);\n+\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n+\tif (merge_verbosity)\n+\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n+\tif (opt->verbosity >= 5)\n+\t\topt->buffer_output = 0;\n+}\n+\n+void init_ui_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 1);\n+}\n+\n+void init_basic_merge_options(struct merge_options *opt,\n+\t\t\tstruct repository *repo)\n+{\n+\tinit_merge_options(opt, repo, 0);\n+}\n+\n+/*\n+ * For now, members of merge_options do not need deep copying, but\n+ * it may change in the future, in which case we would need to update\n+ * this, and also make a matching change to clear_merge_options() to\n+ * release the resources held by a copied instance.\n+ */\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n+{\n+\t*dst = *src;\n+}\n+\n+void clear_merge_options(struct merge_options *opt UNUSED)\n+{\n+\t; /* no-op as our copy is shallow right now */\n+}\n+\n+int parse_merge_opt(struct merge_options *opt, const char *s)\n+{\n+\tconst char *arg;\n+\n+\tif (!s || !*s)\n+\t\treturn -1;\n+\tif (!strcmp(s, \"ours\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n+\telse if (!strcmp(s, \"theirs\"))\n+\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n+\telse if (!strcmp(s, \"subtree\"))\n+\t\topt->subtree_shift = \"\";\n+\telse if (skip_prefix(s, \"subtree=\", &arg))\n+\t\topt->subtree_shift = arg;\n+\telse if (!strcmp(s, \"patience\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n+\telse if (!strcmp(s, \"histogram\"))\n+\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n+\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n+\t\tlong value = parse_algorithm_value(arg);\n+\t\tif (value < 0)\n+\t\t\treturn -1;\n+\t\t/* clear out previous settings */\n+\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n+\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n+\t\topt->xdl_opts |= value;\n+\t}\n+\telse if (!strcmp(s, \"ignore-space-change\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n+\telse if (!strcmp(s, \"ignore-all-space\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n+\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n+\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n+\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n+\telse if (!strcmp(s, \"renormalize\"))\n+\t\topt->renormalize = 1;\n+\telse if (!strcmp(s, \"no-renormalize\"))\n+\t\topt->renormalize = 0;\n+\telse if (!strcmp(s, \"no-renames\"))\n+\t\topt->detect_renames = 0;\n+\telse if (!strcmp(s, \"find-renames\")) {\n+\t\topt->detect_renames = 1;\n+\t\topt->rename_score = 0;\n+\t}\n+\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n+\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n+\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n+\t\t\treturn -1;\n+\t\topt->detect_renames = 1;\n+\t}\n+\t/*\n+\t * Please update $__git_merge_strategy_options in\n+\t * git-completion.bash when you add new options\n+\t */\n+\telse\n+\t\treturn -1;\n+\treturn 0;\n+}\ndiff --git a/merge-ort.h b/merge-ort.h\nindex b63bc5424e7..30750c03962 100644\n--- a/merge-ort.h\n+++ b/merge-ort.h\n@@ -1,10 +1,11 @@\n #ifndef MERGE_ORT_H\n #define MERGE_ORT_H\n \n-#include \"merge-recursive.h\"\n #include \"hash.h\"\n+#include \"strbuf.h\"\n \n struct commit;\n+struct commit_list;\n struct tree;\n struct strmap;\n \n@@ -44,6 +45,51 @@ struct merge_result {\n \tunsigned _properly_initialized;\n };\n \n+struct merge_options_internal;\n+struct merge_options {\n+\tstruct repository *repo;\n+\n+\t/* ref names used in console messages and conflict markers */\n+\tconst char *ancestor;\n+\tconst char *branch1;\n+\tconst char *branch2;\n+\n+\t/* rename related options */\n+\tint detect_renames;\n+\tenum {\n+\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n+\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n+\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n+\t} detect_directory_renames;\n+\tint rename_limit;\n+\tint rename_score;\n+\tint show_rename_progress;\n+\n+\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n+\tlong xdl_opts;\n+\tint conflict_style;\n+\tenum {\n+\t\tMERGE_VARIANT_NORMAL = 0,\n+\t\tMERGE_VARIANT_OURS,\n+\t\tMERGE_VARIANT_THEIRS\n+\t} recursive_variant;\n+\n+\t/* console output related options */\n+\tint verbosity;\n+\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n+\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n+\t\t\t\t * must handle and call strbuf_release */\n+\n+\t/* miscellaneous control options */\n+\tconst char *subtree_shift;\n+\tunsigned renormalize : 1;\n+\tunsigned record_conflict_msgs_as_headers : 1;\n+\tconst char *msg_header_prefix;\n+\n+\t/* internal fields used by the implementation */\n+\tstruct merge_options_internal *priv;\n+};\n+\n /* Mostly internal function also used by merge-ort-wrappers.c */\n struct commit *make_virtual_commit(struct repository *repo,\n \t\t\t\t   struct tree *tree,\n@@ -119,4 +165,16 @@ void merge_get_conflicted_files(struct merge_result *result,\n void merge_finalize(struct merge_options *opt,\n \t\t    struct merge_result *result);\n \n+\n+/* for use by porcelain commands */\n+void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n+/* for use by plumbing commands */\n+void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n+\n+void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n+void clear_merge_options(struct merge_options *opt);\n+\n+/* parse the option in s and update the relevant field of opt */\n+int parse_merge_opt(struct merge_options *opt, const char *s);\n+\n #endif\ndiff --git a/merge-recursive.c b/merge-recursive.c\ndeleted file mode 100644\nindex f3df127ad9b..00000000000\n--- a/merge-recursive.c\n+++ /dev/null\n@@ -1,4080 +0,0 @@\n-/*\n- * Recursive Merge algorithm stolen from git-merge-recursive.py by\n- * Fredrik Kuivinen.\n- * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006\n- */\n-\n-#define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n-\n-#include \"git-compat-util.h\"\n-#include \"merge-recursive.h\"\n-\n-#include \"alloc.h\"\n-#include \"cache-tree.h\"\n-#include \"commit.h\"\n-#include \"commit-reach.h\"\n-#include \"config.h\"\n-#include \"diff.h\"\n-#include \"diffcore.h\"\n-#include \"dir.h\"\n-#include \"environment.h\"\n-#include \"gettext.h\"\n-#include \"hex.h\"\n-#include \"merge-ll.h\"\n-#include \"lockfile.h\"\n-#include \"match-trees.h\"\n-#include \"name-hash.h\"\n-#include \"object-file.h\"\n-#include \"object-name.h\"\n-#include \"object-store-ll.h\"\n-#include \"path.h\"\n-#include \"repository.h\"\n-#include \"revision.h\"\n-#include \"sparse-index.h\"\n-#include \"string-list.h\"\n-#include \"symlinks.h\"\n-#include \"tag.h\"\n-#include \"tree-walk.h\"\n-#include \"unpack-trees.h\"\n-#include \"xdiff-interface.h\"\n-\n-struct merge_options_internal {\n-\tint call_depth;\n-\tint needed_rename_limit;\n-\tstruct hashmap current_file_dir_set;\n-\tstruct string_list df_conflict_file_set;\n-\tstruct unpack_trees_options unpack_opts;\n-\tstruct index_state orig_index;\n-};\n-\n-struct path_hashmap_entry {\n-\tstruct hashmap_entry e;\n-\tchar path[FLEX_ARRAY];\n-};\n-\n-static int path_hashmap_cmp(const void *cmp_data UNUSED,\n-\t\t\t    const struct hashmap_entry *eptr,\n-\t\t\t    const struct hashmap_entry *entry_or_key,\n-\t\t\t    const void *keydata)\n-{\n-\tconst struct path_hashmap_entry *a, *b;\n-\tconst char *key = keydata;\n-\n-\ta = container_of(eptr, const struct path_hashmap_entry, e);\n-\tb = container_of(entry_or_key, const struct path_hashmap_entry, e);\n-\n-\treturn fspathcmp(a->path, key ? key : b->path);\n-}\n-\n-/*\n- * For dir_rename_entry, directory names are stored as a full path from the\n- * toplevel of the repository and do not include a trailing '/'.  Also:\n- *\n- *   dir:                original name of directory being renamed\n- *   non_unique_new_dir: if true, could not determine new_dir\n- *   new_dir:            final name of directory being renamed\n- *   possible_new_dirs:  temporary used to help determine new_dir; see comments\n- *                       in get_directory_renames() for details\n- */\n-struct dir_rename_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *dir;\n-\tunsigned non_unique_new_dir:1;\n-\tstruct strbuf new_dir;\n-\tstruct string_list possible_new_dirs;\n-};\n-\n-static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t      char *dir)\n-{\n-\tstruct dir_rename_entry key;\n-\n-\tif (!dir)\n-\t\treturn NULL;\n-\thashmap_entry_init(&key.ent, strhash(dir));\n-\tkey.dir = dir;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int dir_rename_cmp(const void *cmp_data UNUSED,\n-\t\t\t  const struct hashmap_entry *eptr,\n-\t\t\t  const struct hashmap_entry *entry_or_key,\n-\t\t\t  const void *keydata UNUSED)\n-{\n-\tconst struct dir_rename_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct dir_rename_entry, ent);\n-\te2 = container_of(entry_or_key, const struct dir_rename_entry, ent);\n-\n-\treturn strcmp(e1->dir, e2->dir);\n-}\n-\n-static void dir_rename_init(struct hashmap *map)\n-{\n-\thashmap_init(map, dir_rename_cmp, NULL, 0);\n-}\n-\n-static void dir_rename_entry_init(struct dir_rename_entry *entry,\n-\t\t\t\t  char *directory)\n-{\n-\thashmap_entry_init(&entry->ent, strhash(directory));\n-\tentry->dir = directory;\n-\tentry->non_unique_new_dir = 0;\n-\tstrbuf_init(&entry->new_dir, 0);\n-\tstring_list_init_nodup(&entry->possible_new_dirs);\n-}\n-\n-struct collision_entry {\n-\tstruct hashmap_entry ent;\n-\tchar *target_file;\n-\tstruct string_list source_files;\n-\tunsigned reported_already:1;\n-};\n-\n-static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n-\t\t\t\t\t\t    char *target_file)\n-{\n-\tstruct collision_entry key;\n-\n-\thashmap_entry_init(&key.ent, strhash(target_file));\n-\tkey.target_file = target_file;\n-\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n-}\n-\n-static int collision_cmp(const void *cmp_data UNUSED,\n-\t\t\t const struct hashmap_entry *eptr,\n-\t\t\t const struct hashmap_entry *entry_or_key,\n-\t\t\t const void *keydata UNUSED)\n-{\n-\tconst struct collision_entry *e1, *e2;\n-\n-\te1 = container_of(eptr, const struct collision_entry, ent);\n-\te2 = container_of(entry_or_key, const struct collision_entry, ent);\n-\n-\treturn strcmp(e1->target_file, e2->target_file);\n-}\n-\n-static void collision_init(struct hashmap *map)\n-{\n-\thashmap_init(map, collision_cmp, NULL, 0);\n-}\n-\n-static void flush_output(struct merge_options *opt)\n-{\n-\tif (opt->buffer_output < 2 && opt->obuf.len) {\n-\t\tfputs(opt->obuf.buf, stdout);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-}\n-\n-__attribute__((format (printf, 2, 3)))\n-static int err(struct merge_options *opt, const char *err, ...)\n-{\n-\tva_list params;\n-\n-\tif (opt->buffer_output < 2)\n-\t\tflush_output(opt);\n-\telse {\n-\t\tstrbuf_complete(&opt->obuf, '\\n');\n-\t\tstrbuf_addstr(&opt->obuf, \"error: \");\n-\t}\n-\tva_start(params, err);\n-\tstrbuf_vaddf(&opt->obuf, err, params);\n-\tva_end(params);\n-\tif (opt->buffer_output > 1)\n-\t\tstrbuf_addch(&opt->obuf, '\\n');\n-\telse {\n-\t\terror(\"%s\", opt->obuf.buf);\n-\t\tstrbuf_reset(&opt->obuf);\n-\t}\n-\n-\treturn -1;\n-}\n-\n-static struct tree *shift_tree_object(struct repository *repo,\n-\t\t\t\t      struct tree *one, struct tree *two,\n-\t\t\t\t      const char *subtree_shift)\n-{\n-\tstruct object_id shifted;\n-\n-\tif (!*subtree_shift) {\n-\t\tshift_tree(repo, &one->object.oid, &two->object.oid, &shifted, 0);\n-\t} else {\n-\t\tshift_tree_by(repo, &one->object.oid, &two->object.oid, &shifted,\n-\t\t\t      subtree_shift);\n-\t}\n-\tif (oideq(&two->object.oid, &shifted))\n-\t\treturn two;\n-\treturn lookup_tree(repo, &shifted);\n-}\n-\n-static inline void set_commit_tree(struct commit *c, struct tree *t)\n-{\n-\tc->maybe_tree = t;\n-}\n-\n-static struct commit *make_virtual_commit(struct repository *repo,\n-\t\t\t\t\t  struct tree *tree,\n-\t\t\t\t\t  const char *comment)\n-{\n-\tstruct commit *commit = alloc_commit_node(repo);\n-\n-\tset_merge_remote_desc(commit, comment, (struct object *)commit);\n-\tset_commit_tree(commit, tree);\n-\tcommit->object.parsed = 1;\n-\treturn commit;\n-}\n-\n-enum rename_type {\n-\tRENAME_NORMAL = 0,\n-\tRENAME_VIA_DIR,\n-\tRENAME_ADD,\n-\tRENAME_DELETE,\n-\tRENAME_ONE_FILE_TO_ONE,\n-\tRENAME_ONE_FILE_TO_TWO,\n-\tRENAME_TWO_FILES_TO_ONE\n-};\n-\n-/*\n- * Since we want to write the index eventually, we cannot reuse the index\n- * for these (temporary) data.\n- */\n-struct stage_data {\n-\tstruct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */\n-\tstruct rename_conflict_info *rename_conflict_info;\n-\tunsigned processed:1,\n-\t\t rename_conflict_info_owned:1;\n-};\n-\n-struct rename {\n-\tunsigned processed:1;\n-\tstruct diff_filepair *pair;\n-\tconst char *branch; /* branch that the rename occurred on */\n-\t/*\n-\t * If directory rename detection affected this rename, what was its\n-\t * original type ('A' or 'R') and it's original destination before\n-\t * the directory rename (otherwise, '\\0' and NULL for these two vars).\n-\t */\n-\tchar dir_rename_original_type;\n-\tchar *dir_rename_original_dest;\n-\t/*\n-\t * Purpose of src_entry and dst_entry:\n-\t *\n-\t * If 'before' is renamed to 'after' then src_entry will contain\n-\t * the versions of 'before' from the merge_base, HEAD, and MERGE in\n-\t * stages 1, 2, and 3; dst_entry will contain the respective\n-\t * versions of 'after' in corresponding locations.  Thus, we have a\n-\t * total of six modes and oids, though some will be null.  (Stage 0\n-\t * is ignored; we're interested in handling conflicts.)\n-\t *\n-\t * Since we don't turn on break-rewrites by default, neither\n-\t * src_entry nor dst_entry can have all three of their stages have\n-\t * non-null oids, meaning at most four of the six will be non-null.\n-\t * Also, since this is a rename, both src_entry and dst_entry will\n-\t * have at least one non-null oid, meaning at least two will be\n-\t * non-null.  Of the six oids, a typical rename will have three be\n-\t * non-null.  Only two implies a rename/delete, and four implies a\n-\t * rename/add.\n-\t */\n-\tstruct stage_data *src_entry;\n-\tstruct stage_data *dst_entry;\n-};\n-\n-struct rename_conflict_info {\n-\tenum rename_type rename_type;\n-\tstruct rename *ren1;\n-\tstruct rename *ren2;\n-};\n-\n-static inline void setup_rename_conflict_info(enum rename_type rename_type,\n-\t\t\t\t\t      struct merge_options *opt,\n-\t\t\t\t\t      struct rename *ren1,\n-\t\t\t\t\t      struct rename *ren2)\n-{\n-\tstruct rename_conflict_info *ci;\n-\n-\t/*\n-\t * When we have two renames involved, it's easiest to get the\n-\t * correct things into stage 2 and 3, and to make sure that the\n-\t * content merge puts HEAD before the other branch if we just\n-\t * ensure that branch1 == opt->branch1.  So, simply flip arguments\n-\t * around if we don't have that.\n-\t */\n-\tif (ren2 && ren1->branch != opt->branch1) {\n-\t\tsetup_rename_conflict_info(rename_type, opt, ren2, ren1);\n-\t\treturn;\n-\t}\n-\n-\tCALLOC_ARRAY(ci, 1);\n-\tci->rename_type = rename_type;\n-\tci->ren1 = ren1;\n-\tci->ren2 = ren2;\n-\n-\tci->ren1->dst_entry->processed = 0;\n-\tci->ren1->dst_entry->rename_conflict_info = ci;\n-\tci->ren1->dst_entry->rename_conflict_info_owned = 1;\n-\tif (ren2) {\n-\t\tci->ren2->dst_entry->rename_conflict_info = ci;\n-\t}\n-}\n-\n-static int show(struct merge_options *opt, int v)\n-{\n-\treturn (!opt->priv->call_depth && opt->verbosity >= v) ||\n-\t\topt->verbosity >= 5;\n-}\n-\n-__attribute__((format (printf, 3, 4)))\n-static void output(struct merge_options *opt, int v, const char *fmt, ...)\n-{\n-\tva_list ap;\n-\n-\tif (!show(opt, v))\n-\t\treturn;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\n-\tva_start(ap, fmt);\n-\tstrbuf_vaddf(&opt->obuf, fmt, ap);\n-\tva_end(ap);\n-\n-\tstrbuf_addch(&opt->obuf, '\\n');\n-\tif (!opt->buffer_output)\n-\t\tflush_output(opt);\n-}\n-\n-static void repo_output_commit_title(struct merge_options *opt,\n-\t\t\t\t     struct repository *repo,\n-\t\t\t\t     struct commit *commit)\n-{\n-\tstruct merge_remote_desc *desc;\n-\n-\tstrbuf_addchars(&opt->obuf, ' ', opt->priv->call_depth * 2);\n-\tdesc = merge_remote_util(commit);\n-\tif (desc)\n-\t\tstrbuf_addf(&opt->obuf, \"virtual %s\\n\", desc->name);\n-\telse {\n-\t\tstrbuf_repo_add_unique_abbrev(&opt->obuf, repo,\n-\t\t\t\t\t      &commit->object.oid,\n-\t\t\t\t\t      DEFAULT_ABBREV);\n-\t\tstrbuf_addch(&opt->obuf, ' ');\n-\t\tif (repo_parse_commit(repo, commit) != 0)\n-\t\t\tstrbuf_addstr(&opt->obuf, _(\"(bad commit)\\n\"));\n-\t\telse {\n-\t\t\tconst char *title;\n-\t\t\tconst char *msg = repo_get_commit_buffer(repo, commit, NULL);\n-\t\t\tint len = find_commit_subject(msg, &title);\n-\t\t\tif (len)\n-\t\t\t\tstrbuf_addf(&opt->obuf, \"%.*s\\n\", len, title);\n-\t\t\trepo_unuse_commit_buffer(repo, commit, msg);\n-\t\t}\n-\t}\n-\tflush_output(opt);\n-}\n-\n-static void output_commit_title(struct merge_options *opt, struct commit *commit)\n-{\n-\trepo_output_commit_title(opt, the_repository, commit);\n-}\n-\n-static int add_cacheinfo(struct merge_options *opt,\n-\t\t\t const struct diff_filespec *blob,\n-\t\t\t const char *path, int stage, int refresh, int options)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tstruct cache_entry *ce;\n-\tint ret;\n-\n-\tce = make_cache_entry(istate, blob->mode, &blob->oid, path, stage, 0);\n-\tif (!ce)\n-\t\treturn err(opt, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n-\n-\tret = add_index_entry(istate, ce, options);\n-\tif (refresh) {\n-\t\tstruct cache_entry *nce;\n-\n-\t\tnce = refresh_cache_entry(istate, ce,\n-\t\t\t\t\t  CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);\n-\t\tif (!nce)\n-\t\t\treturn err(opt, _(\"add_cacheinfo failed to refresh for path '%s'; merge aborting.\"), path);\n-\t\tif (nce != ce)\n-\t\t\tret = add_index_entry(istate, nce, options);\n-\t}\n-\treturn ret;\n-}\n-\n-static inline int merge_detect_rename(struct merge_options *opt)\n-{\n-\treturn (opt->detect_renames >= 0) ? opt->detect_renames : 1;\n-}\n-\n-static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)\n-{\n-\tif (parse_tree(tree) < 0)\n-\t\texit(128);\n-\tinit_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size);\n-}\n-\n-static int unpack_trees_start(struct merge_options *opt,\n-\t\t\t      struct tree *common,\n-\t\t\t      struct tree *head,\n-\t\t\t      struct tree *merge)\n-{\n-\tint rc;\n-\tstruct tree_desc t[3];\n-\tstruct index_state tmp_index = INDEX_STATE_INIT(opt->repo);\n-\n-\tmemset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));\n-\tif (opt->priv->call_depth)\n-\t\topt->priv->unpack_opts.index_only = 1;\n-\telse {\n-\t\topt->priv->unpack_opts.update = 1;\n-\t\t/* FIXME: should only do this if !overwrite_ignore */\n-\t\topt->priv->unpack_opts.preserve_ignored = 0;\n-\t}\n-\topt->priv->unpack_opts.merge = 1;\n-\topt->priv->unpack_opts.head_idx = 2;\n-\topt->priv->unpack_opts.fn = threeway_merge;\n-\topt->priv->unpack_opts.src_index = opt->repo->index;\n-\topt->priv->unpack_opts.dst_index = &tmp_index;\n-\topt->priv->unpack_opts.aggressive = !merge_detect_rename(opt);\n-\tsetup_unpack_trees_porcelain(&opt->priv->unpack_opts, \"merge\");\n-\n-\tinit_tree_desc_from_tree(t+0, common);\n-\tinit_tree_desc_from_tree(t+1, head);\n-\tinit_tree_desc_from_tree(t+2, merge);\n-\n-\trc = unpack_trees(3, t, &opt->priv->unpack_opts);\n-\tcache_tree_free(&opt->repo->index->cache_tree);\n-\n-\t/*\n-\t * Update opt->repo->index to match the new results, AFTER saving a\n-\t * copy in opt->priv->orig_index.  Update src_index to point to the\n-\t * saved copy.  (verify_uptodate() checks src_index, and the original\n-\t * index is the one that had the necessary modification timestamps.)\n-\t */\n-\topt->priv->orig_index = *opt->repo->index;\n-\t*opt->repo->index = tmp_index;\n-\topt->priv->unpack_opts.src_index = &opt->priv->orig_index;\n-\n-\treturn rc;\n-}\n-\n-static void unpack_trees_finish(struct merge_options *opt)\n-{\n-\tdiscard_index(&opt->priv->orig_index);\n-\tclear_unpack_trees_porcelain(&opt->priv->unpack_opts);\n-}\n-\n-static int save_files_dirs(const struct object_id *oid UNUSED,\n-\t\t\t   struct strbuf *base, const char *path,\n-\t\t\t   unsigned int mode, void *context)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tint baselen = base->len;\n-\tstruct merge_options *opt = context;\n-\n-\tstrbuf_addstr(base, path);\n-\n-\tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\n-\tstrbuf_setlen(base, baselen);\n-\treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n-}\n-\n-static void get_files_dirs(struct merge_options *opt, struct tree *tree)\n-{\n-\tstruct pathspec match_all;\n-\tmemset(&match_all, 0, sizeof(match_all));\n-\tread_tree(opt->repo, tree,\n-\t\t  &match_all, save_files_dirs, opt);\n-}\n-\n-static int get_tree_entry_if_blob(struct repository *r,\n-\t\t\t\t  const struct object_id *tree,\n-\t\t\t\t  const char *path,\n-\t\t\t\t  struct diff_filespec *dfs)\n-{\n-\tint ret;\n-\n-\tret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);\n-\tif (S_ISDIR(dfs->mode)) {\n-\t\toidcpy(&dfs->oid, null_oid());\n-\t\tdfs->mode = 0;\n-\t}\n-\treturn ret;\n-}\n-\n-/*\n- * Returns an index_entry instance which doesn't have to correspond to\n- * a real cache entry in Git's index.\n- */\n-static struct stage_data *insert_stage_data(struct repository *r,\n-\t\tconst char *path,\n-\t\tstruct tree *o, struct tree *a, struct tree *b,\n-\t\tstruct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tstruct stage_data *e = xcalloc(1, sizeof(struct stage_data));\n-\tget_tree_entry_if_blob(r, &o->object.oid, path, &e->stages[1]);\n-\tget_tree_entry_if_blob(r, &a->object.oid, path, &e->stages[2]);\n-\tget_tree_entry_if_blob(r, &b->object.oid, path, &e->stages[3]);\n-\titem = string_list_insert(entries, path);\n-\titem->util = e;\n-\treturn e;\n-}\n-\n-/*\n- * Create a dictionary mapping file names to stage_data objects. The\n- * dictionary contains one entry for every path with a non-zero stage entry.\n- */\n-static struct string_list *get_unmerged(struct index_state *istate)\n-{\n-\tstruct string_list *unmerged = xmalloc(sizeof(struct string_list));\n-\tint i;\n-\n-\tstring_list_init_dup(unmerged);\n-\n-\t/* TODO: audit for interaction with sparse-index. */\n-\tensure_full_index(istate);\n-\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct stage_data *e;\n-\t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_stage(ce))\n-\t\t\tcontinue;\n-\n-\t\titem = string_list_lookup(unmerged, ce->name);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(unmerged, ce->name);\n-\t\t\titem->util = xcalloc(1, sizeof(struct stage_data));\n-\t\t}\n-\t\te = item->util;\n-\t\te->stages[ce_stage(ce)].mode = ce->ce_mode;\n-\t\toidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid);\n-\t}\n-\n-\treturn unmerged;\n-}\n-\n-static int string_list_df_name_compare(const char *one, const char *two)\n-{\n-\tint onelen = strlen(one);\n-\tint twolen = strlen(two);\n-\t/*\n-\t * Here we only care that entries for D/F conflicts are\n-\t * adjacent, in particular with the file of the D/F conflict\n-\t * appearing before files below the corresponding directory.\n-\t * The order of the rest of the list is irrelevant for us.\n-\t *\n-\t * To achieve this, we sort with df_name_compare and provide\n-\t * the mode S_IFDIR so that D/F conflicts will sort correctly.\n-\t * We use the mode S_IFDIR for everything else for simplicity,\n-\t * since in other cases any changes in their order due to\n-\t * sorting cause no problems for us.\n-\t */\n-\tint cmp = df_name_compare(one, onelen, S_IFDIR,\n-\t\t\t\t  two, twolen, S_IFDIR);\n-\t/*\n-\t * Now that 'foo' and 'foo/bar' compare equal, we have to make sure\n-\t * that 'foo' comes before 'foo/bar'.\n-\t */\n-\tif (cmp)\n-\t\treturn cmp;\n-\treturn onelen - twolen;\n-}\n-\n-static void record_df_conflict_files(struct merge_options *opt,\n-\t\t\t\t     struct string_list *entries)\n-{\n-\t/* If there is a D/F conflict and the file for such a conflict\n-\t * currently exists in the working tree, we want to allow it to be\n-\t * removed to make room for the corresponding directory if needed.\n-\t * The files underneath the directories of such D/F conflicts will\n-\t * be processed before the corresponding file involved in the D/F\n-\t * conflict.  If the D/F directory ends up being removed by the\n-\t * merge, then we won't have to touch the D/F file.  If the D/F\n-\t * directory needs to be written to the working copy, then the D/F\n-\t * file will simply be removed (in make_room_for_path()) to make\n-\t * room for the necessary paths.  Note that if both the directory\n-\t * and the file need to be present, then the D/F file will be\n-\t * reinstated with a new unique name at the time it is processed.\n-\t */\n-\tstruct string_list df_sorted_entries = STRING_LIST_INIT_NODUP;\n-\tconst char *last_file = NULL;\n-\tint last_len = 0;\n-\tint i;\n-\n-\t/*\n-\t * If we're merging merge-bases, we don't want to bother with\n-\t * any working directory changes.\n-\t */\n-\tif (opt->priv->call_depth)\n-\t\treturn;\n-\n-\t/* Ensure D/F conflicts are adjacent in the entries list. */\n-\tfor (i = 0; i < entries->nr; i++) {\n-\t\tstruct string_list_item *next = &entries->items[i];\n-\t\tstring_list_append(&df_sorted_entries, next->string)->util =\n-\t\t\t\t   next->util;\n-\t}\n-\tdf_sorted_entries.cmp = string_list_df_name_compare;\n-\tstring_list_sort(&df_sorted_entries);\n-\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 1);\n-\tfor (i = 0; i < df_sorted_entries.nr; i++) {\n-\t\tconst char *path = df_sorted_entries.items[i].string;\n-\t\tint len = strlen(path);\n-\t\tstruct stage_data *e = df_sorted_entries.items[i].util;\n-\n-\t\t/*\n-\t\t * Check if last_file & path correspond to a D/F conflict;\n-\t\t * i.e. whether path is last_file+'/'+<something>.\n-\t\t * If so, record that it's okay to remove last_file to make\n-\t\t * room for path and friends if needed.\n-\t\t */\n-\t\tif (last_file &&\n-\t\t    len > last_len &&\n-\t\t    memcmp(path, last_file, last_len) == 0 &&\n-\t\t    path[last_len] == '/') {\n-\t\t\tstring_list_insert(&opt->priv->df_conflict_file_set, last_file);\n-\t\t}\n-\n-\t\t/*\n-\t\t * Determine whether path could exist as a file in the\n-\t\t * working directory as a possible D/F conflict.  This\n-\t\t * will only occur when it exists in stage 2 as a\n-\t\t * file.\n-\t\t */\n-\t\tif (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) {\n-\t\t\tlast_file = path;\n-\t\t\tlast_len = len;\n-\t\t} else {\n-\t\t\tlast_file = NULL;\n-\t\t}\n-\t}\n-\tstring_list_clear(&df_sorted_entries, 0);\n-}\n-\n-static int update_stages(struct merge_options *opt, const char *path,\n-\t\t\t const struct diff_filespec *o,\n-\t\t\t const struct diff_filespec *a,\n-\t\t\t const struct diff_filespec *b)\n-{\n-\n-\t/*\n-\t * NOTE: It is usually a bad idea to call update_stages on a path\n-\t * before calling update_file on that same path, since it can\n-\t * sometimes lead to spurious \"refusing to lose untracked file...\"\n-\t * messages from update_file (via make_room_for path via\n-\t * would_lose_untracked).  Instead, reverse the order of the calls\n-\t * (executing update_file first and then update_stages).\n-\t */\n-\tint clear = 1;\n-\tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;\n-\tif (clear)\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\tif (o)\n-\t\tif (add_cacheinfo(opt, o, path, 1, 0, options))\n-\t\t\treturn -1;\n-\tif (a)\n-\t\tif (add_cacheinfo(opt, a, path, 2, 0, options))\n-\t\t\treturn -1;\n-\tif (b)\n-\t\tif (add_cacheinfo(opt, b, path, 3, 0, options))\n-\t\t\treturn -1;\n-\treturn 0;\n-}\n-\n-static void update_entry(struct stage_data *entry,\n-\t\t\t struct diff_filespec *o,\n-\t\t\t struct diff_filespec *a,\n-\t\t\t struct diff_filespec *b)\n-{\n-\tentry->processed = 0;\n-\tentry->stages[1].mode = o->mode;\n-\tentry->stages[2].mode = a->mode;\n-\tentry->stages[3].mode = b->mode;\n-\toidcpy(&entry->stages[1].oid, &o->oid);\n-\toidcpy(&entry->stages[2].oid, &a->oid);\n-\toidcpy(&entry->stages[3].oid, &b->oid);\n-}\n-\n-static int remove_file(struct merge_options *opt, int clean,\n-\t\t       const char *path, int no_wd)\n-{\n-\tint update_cache = opt->priv->call_depth || clean;\n-\tint update_working_directory = !opt->priv->call_depth && !no_wd;\n-\n-\tif (update_cache) {\n-\t\tif (remove_file_from_index(opt->repo->index, path))\n-\t\t\treturn -1;\n-\t}\n-\tif (update_working_directory) {\n-\t\tif (ignore_case) {\n-\t\t\tstruct cache_entry *ce;\n-\t\t\tce = index_file_exists(opt->repo->index, path, strlen(path),\n-\t\t\t\t\t       ignore_case);\n-\t\t\tif (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))\n-\t\t\t\treturn 0;\n-\t\t}\n-\t\tif (remove_path(path))\n-\t\t\treturn -1;\n-\t}\n-\treturn 0;\n-}\n-\n-/* add a string to a strbuf, but converting \"/\" to \"_\" */\n-static void add_flattened_path(struct strbuf *out, const char *s)\n-{\n-\tsize_t i = out->len;\n-\tstrbuf_addstr(out, s);\n-\tfor (; i < out->len; i++)\n-\t\tif (out->buf[i] == '/')\n-\t\t\tout->buf[i] = '_';\n-}\n-\n-static char *unique_path(struct merge_options *opt,\n-\t\t\t const char *path,\n-\t\t\t const char *branch)\n-{\n-\tstruct path_hashmap_entry *entry;\n-\tstruct strbuf newpath = STRBUF_INIT;\n-\tint suffix = 0;\n-\tsize_t base_len;\n-\n-\tstrbuf_addf(&newpath, \"%s~\", path);\n-\tadd_flattened_path(&newpath, branch);\n-\n-\tbase_len = newpath.len;\n-\twhile (hashmap_get_from_hash(&opt->priv->current_file_dir_set,\n-\t\t\t\t     fspathhash(newpath.buf), newpath.buf) ||\n-\t       (!opt->priv->call_depth && file_exists(newpath.buf))) {\n-\t\tstrbuf_setlen(&newpath, base_len);\n-\t\tstrbuf_addf(&newpath, \"_%d\", suffix++);\n-\t}\n-\n-\tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n-\thashmap_entry_init(&entry->e, fspathhash(entry->path));\n-\thashmap_add(&opt->priv->current_file_dir_set, &entry->e);\n-\treturn strbuf_detach(&newpath, NULL);\n-}\n-\n-/**\n- * Check whether a directory in the index is in the way of an incoming\n- * file.  Return 1 if so.  If check_working_copy is non-zero, also\n- * check the working directory.  If empty_ok is non-zero, also return\n- * 0 in the case where the working-tree dir exists but is empty.\n- */\n-static int dir_in_way(struct index_state *istate, const char *path,\n-\t\t      int check_working_copy, int empty_ok)\n-{\n-\tint pos;\n-\tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct stat st;\n-\n-\tstrbuf_addstr(&dirpath, path);\n-\tstrbuf_addch(&dirpath, '/');\n-\n-\tpos = index_name_pos(istate, dirpath.buf, dirpath.len);\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\tif (pos < istate->cache_nr &&\n-\t    !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {\n-\t\tstrbuf_release(&dirpath);\n-\t\treturn 1;\n-\t}\n-\n-\tstrbuf_release(&dirpath);\n-\treturn check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&\n-\t\t!(empty_ok && is_empty_dir(path)) &&\n-\t\t!has_symlink_leading_path(path, strlen(path));\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started,\n- * and its oid and mode match the specified values\n- */\n-static int was_tracked_and_matches(struct merge_options *opt, const char *path,\n-\t\t\t\t   const struct diff_filespec *blob)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\tstruct cache_entry *ce;\n-\n-\tif (0 > pos)\n-\t\t/* we were not tracking this path before the merge */\n-\t\treturn 0;\n-\n-\t/* See if the file we were tracking before matches */\n-\tce = opt->priv->orig_index.cache[pos];\n-\treturn (oideq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);\n-}\n-\n-/*\n- * Returns whether path was tracked in the index before the merge started\n- */\n-static int was_tracked(struct merge_options *opt, const char *path)\n-{\n-\tint pos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\n-\tif (0 <= pos)\n-\t\t/* we were tracking this path before the merge */\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-static int would_lose_untracked(struct merge_options *opt, const char *path)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\n-\t/*\n-\t * This may look like it can be simplified to:\n-\t *   return !was_tracked(opt, path) && file_exists(path)\n-\t * but it can't.  This function needs to know whether path was in\n-\t * the working tree due to EITHER having been tracked in the index\n-\t * before the merge OR having been put into the working copy and\n-\t * index by unpack_trees().  Due to that either-or requirement, we\n-\t * check the current index instead of the original one.\n-\t *\n-\t * Note that we do not need to worry about merge-recursive itself\n-\t * updating the index after unpack_trees() and before calling this\n-\t * function, because we strictly require all code paths in\n-\t * merge-recursive to update the working tree first and the index\n-\t * second.  Doing otherwise would break\n-\t * update_file()/would_lose_untracked(); see every comment in this\n-\t * file which mentions \"update_stages\".\n-\t */\n-\tint pos = index_name_pos(istate, path, strlen(path));\n-\n-\tif (pos < 0)\n-\t\tpos = -1 - pos;\n-\twhile (pos < istate->cache_nr &&\n-\t       !strcmp(path, istate->cache[pos]->name)) {\n-\t\t/*\n-\t\t * If stage #0, it is definitely tracked.\n-\t\t * If it has stage #2 then it was tracked\n-\t\t * before this merge started.  All other\n-\t\t * cases the path was not tracked.\n-\t\t */\n-\t\tswitch (ce_stage(istate->cache[pos])) {\n-\t\tcase 0:\n-\t\tcase 2:\n-\t\t\treturn 0;\n-\t\t}\n-\t\tpos++;\n-\t}\n-\treturn file_exists(path);\n-}\n-\n-static int was_dirty(struct merge_options *opt, const char *path)\n-{\n-\tstruct cache_entry *ce;\n-\tint dirty = 1;\n-\n-\tif (opt->priv->call_depth || !was_tracked(opt, path))\n-\t\treturn !dirty;\n-\n-\tce = index_file_exists(opt->priv->unpack_opts.src_index,\n-\t\t\t       path, strlen(path), ignore_case);\n-\tdirty = verify_uptodate(ce, &opt->priv->unpack_opts) != 0;\n-\treturn dirty;\n-}\n-\n-static int make_room_for_path(struct merge_options *opt, const char *path)\n-{\n-\tint status, i;\n-\tconst char *msg = _(\"failed to create path '%s'%s\");\n-\n-\t/* Unlink any D/F conflict files that are in the way */\n-\tfor (i = 0; i < opt->priv->df_conflict_file_set.nr; i++) {\n-\t\tconst char *df_path = opt->priv->df_conflict_file_set.items[i].string;\n-\t\tsize_t pathlen = strlen(path);\n-\t\tsize_t df_pathlen = strlen(df_path);\n-\t\tif (df_pathlen < pathlen &&\n-\t\t    path[df_pathlen] == '/' &&\n-\t\t    strncmp(path, df_path, df_pathlen) == 0) {\n-\t\t\toutput(opt, 3,\n-\t\t\t       _(\"Removing %s to make room for subdirectory\\n\"),\n-\t\t\t       df_path);\n-\t\t\tunlink(df_path);\n-\t\t\tunsorted_string_list_delete_item(&opt->priv->df_conflict_file_set,\n-\t\t\t\t\t\t\t i, 0);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\t/* Make sure leading directories are created */\n-\tstatus = safe_create_leading_directories_const(path);\n-\tif (status) {\n-\t\tif (status == SCLD_EXISTS)\n-\t\t\t/* something else exists */\n-\t\t\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-\t\treturn err(opt, msg, path, \"\");\n-\t}\n-\n-\t/*\n-\t * Do not unlink a file in the work tree if we are not\n-\t * tracking it.\n-\t */\n-\tif (would_lose_untracked(opt, path))\n-\t\treturn err(opt, _(\"refusing to lose untracked file at '%s'\"),\n-\t\t\t   path);\n-\n-\t/* Successful unlink is good.. */\n-\tif (!unlink(path))\n-\t\treturn 0;\n-\t/* .. and so is no existing file */\n-\tif (errno == ENOENT)\n-\t\treturn 0;\n-\t/* .. but not some other error (who really cares what?) */\n-\treturn err(opt, msg, path, _(\": perhaps a D/F conflict?\"));\n-}\n-\n-static int update_file_flags(struct merge_options *opt,\n-\t\t\t     const struct diff_filespec *contents,\n-\t\t\t     const char *path,\n-\t\t\t     int update_cache,\n-\t\t\t     int update_wd)\n-{\n-\tint ret = 0;\n-\n-\tif (opt->priv->call_depth)\n-\t\tupdate_wd = 0;\n-\n-\tif (update_wd) {\n-\t\tenum object_type type;\n-\t\tvoid *buf;\n-\t\tunsigned long size;\n-\n-\t\tif (S_ISGITLINK(contents->mode)) {\n-\t\t\t/*\n-\t\t\t * We may later decide to recursively descend into\n-\t\t\t * the submodule directory and update its index\n-\t\t\t * and/or work tree, but we do not do that now.\n-\t\t\t */\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto update_index;\n-\t\t}\n-\n-\t\tbuf = repo_read_object_file(the_repository, &contents->oid,\n-\t\t\t\t\t    &type, &size);\n-\t\tif (!buf) {\n-\t\t\tret = err(opt, _(\"cannot read object %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (type != OBJ_BLOB) {\n-\t\t\tret = err(opt, _(\"blob expected for %s '%s'\"),\n-\t\t\t\t  oid_to_hex(&contents->oid), path);\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode)) {\n-\t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(opt->repo->index,\n-\t\t\t\t\t\t    path, buf, size, &strbuf, NULL)) {\n-\t\t\t\tfree(buf);\n-\t\t\t\tsize = strbuf.len;\n-\t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (make_room_for_path(opt, path) < 0) {\n-\t\t\tupdate_wd = 0;\n-\t\t\tgoto free_buf;\n-\t\t}\n-\t\tif (S_ISREG(contents->mode) ||\n-\t\t    (!has_symlinks && S_ISLNK(contents->mode))) {\n-\t\t\tint fd;\n-\t\t\tint mode = (contents->mode & 0100 ? 0777 : 0666);\n-\n-\t\t\tfd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);\n-\t\t\tif (fd < 0) {\n-\t\t\t\tret = err(opt, _(\"failed to open '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\t\tgoto free_buf;\n-\t\t\t}\n-\t\t\twrite_in_full(fd, buf, size);\n-\t\t\tclose(fd);\n-\t\t} else if (S_ISLNK(contents->mode)) {\n-\t\t\tchar *lnk = xmemdupz(buf, size);\n-\t\t\tsafe_create_leading_directories_const(path);\n-\t\t\tunlink(path);\n-\t\t\tif (symlink(lnk, path))\n-\t\t\t\tret = err(opt, _(\"failed to symlink '%s': %s\"),\n-\t\t\t\t\t  path, strerror(errno));\n-\t\t\tfree(lnk);\n-\t\t} else\n-\t\t\tret = err(opt,\n-\t\t\t\t  _(\"do not know what to do with %06o %s '%s'\"),\n-\t\t\t\t  contents->mode, oid_to_hex(&contents->oid), path);\n-\tfree_buf:\n-\t\tfree(buf);\n-\t}\n-update_index:\n-\tif (!ret && update_cache) {\n-\t\tint refresh = (!opt->priv->call_depth &&\n-\t\t\t       contents->mode != S_IFGITLINK);\n-\t\tif (add_cacheinfo(opt, contents, path, 0, refresh,\n-\t\t\t\t  ADD_CACHE_OK_TO_ADD))\n-\t\t\treturn -1;\n-\t}\n-\treturn ret;\n-}\n-\n-static int update_file(struct merge_options *opt,\n-\t\t       int clean,\n-\t\t       const struct diff_filespec *contents,\n-\t\t       const char *path)\n-{\n-\treturn update_file_flags(opt, contents, path,\n-\t\t\t\t opt->priv->call_depth || clean, !opt->priv->call_depth);\n-}\n-\n-/* Low level file merging, update and removal */\n-\n-struct merge_file_info {\n-\tstruct diff_filespec blob; /* mostly use oid & mode; sometimes path */\n-\tunsigned clean:1,\n-\t\t merge:1;\n-};\n-\n-static int merge_3way(struct merge_options *opt,\n-\t\t      mmbuffer_t *result_buf,\n-\t\t      const struct diff_filespec *o,\n-\t\t      const struct diff_filespec *a,\n-\t\t      const struct diff_filespec *b,\n-\t\t      const char *branch1,\n-\t\t      const char *branch2,\n-\t\t      const int extra_marker_size)\n-{\n-\tmmfile_t orig, src1, src2;\n-\tstruct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;\n-\tchar *base, *name1, *name2;\n-\tenum ll_merge_result merge_status;\n-\n-\tll_opts.renormalize = opt->renormalize;\n-\tll_opts.extra_marker_size = extra_marker_size;\n-\tll_opts.xdl_opts = opt->xdl_opts;\n-\tll_opts.conflict_style = opt->conflict_style;\n-\n-\tif (opt->priv->call_depth) {\n-\t\tll_opts.virtual_ancestor = 1;\n-\t\tll_opts.variant = 0;\n-\t} else {\n-\t\tswitch (opt->recursive_variant) {\n-\t\tcase MERGE_VARIANT_OURS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_OURS;\n-\t\t\tbreak;\n-\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\tll_opts.variant = XDL_MERGE_FAVOR_THEIRS;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tll_opts.variant = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tassert(a->path && b->path && o->path && opt->ancestor);\n-\tif (strcmp(a->path, b->path) || strcmp(a->path, o->path) != 0) {\n-\t\tbase  = mkpathdup(\"%s:%s\", opt->ancestor, o->path);\n-\t\tname1 = mkpathdup(\"%s:%s\", branch1, a->path);\n-\t\tname2 = mkpathdup(\"%s:%s\", branch2, b->path);\n-\t} else {\n-\t\tbase  = mkpathdup(\"%s\", opt->ancestor);\n-\t\tname1 = mkpathdup(\"%s\", branch1);\n-\t\tname2 = mkpathdup(\"%s\", branch2);\n-\t}\n-\n-\tread_mmblob(&orig, &o->oid);\n-\tread_mmblob(&src1, &a->oid);\n-\tread_mmblob(&src2, &b->oid);\n-\n-\t/*\n-\t * FIXME: Using a->path for normalization rules in ll_merge could be\n-\t * wrong if we renamed from a->path to b->path.  We should use the\n-\t * target path for where the file will be written.\n-\t */\n-\tmerge_status = ll_merge(result_buf, a->path, &orig, base,\n-\t\t\t\t&src1, name1, &src2, name2,\n-\t\t\t\topt->repo->index, &ll_opts);\n-\tif (merge_status == LL_MERGE_BINARY_CONFLICT)\n-\t\twarning(\"Cannot merge binary files: %s (%s vs. %s)\",\n-\t\t\ta->path, name1, name2);\n-\n-\tfree(base);\n-\tfree(name1);\n-\tfree(name2);\n-\tfree(orig.ptr);\n-\tfree(src1.ptr);\n-\tfree(src2.ptr);\n-\treturn merge_status;\n-}\n-\n-static int find_first_merges(struct repository *repo,\n-\t\t\t     struct object_array *result, const char *path,\n-\t\t\t     struct commit *a, struct commit *b)\n-{\n-\tint i, j;\n-\tstruct object_array merges = OBJECT_ARRAY_INIT;\n-\tstruct commit *commit;\n-\tint contains_another;\n-\n-\tchar merged_revision[GIT_MAX_HEXSZ + 2];\n-\tconst char *rev_args[] = { \"rev-list\", \"--merges\", \"--ancestry-path\",\n-\t\t\t\t   \"--all\", merged_revision, NULL };\n-\tstruct rev_info revs;\n-\tstruct setup_revision_opt rev_opts;\n-\n-\tmemset(result, 0, sizeof(struct object_array));\n-\tmemset(&rev_opts, 0, sizeof(rev_opts));\n-\n-\t/* get all revisions that merge commit a */\n-\txsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n-\t\t  oid_to_hex(&a->object.oid));\n-\trepo_init_revisions(repo, &revs, NULL);\n-\t/* FIXME: can't handle linked worktrees in submodules yet */\n-\trevs.single_worktree = path != NULL;\n-\tsetup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);\n-\n-\t/* save all revisions from the above list that contain b */\n-\tif (prepare_revision_walk(&revs))\n-\t\tdie(\"revision walk setup failed\");\n-\twhile ((commit = get_revision(&revs)) != NULL) {\n-\t\tstruct object *o = &(commit->object);\n-\t\tint ret = repo_in_merge_bases(repo, b, commit);\n-\t\tif (ret < 0) {\n-\t\t\tobject_array_clear(&merges);\n-\t\t\trelease_revisions(&revs);\n-\t\t\treturn ret;\n-\t\t}\n-\t\tif (ret)\n-\t\t\tadd_object_array(o, NULL, &merges);\n-\t}\n-\treset_revision_walk();\n-\n-\t/* Now we've got all merges that contain a and b. Prune all\n-\t * merges that contain another found merge and save them in\n-\t * result.\n-\t */\n-\tfor (i = 0; i < merges.nr; i++) {\n-\t\tstruct commit *m1 = (struct commit *) merges.objects[i].item;\n-\n-\t\tcontains_another = 0;\n-\t\tfor (j = 0; j < merges.nr; j++) {\n-\t\t\tstruct commit *m2 = (struct commit *) merges.objects[j].item;\n-\t\t\tif (i != j) {\n-\t\t\t\tint ret = repo_in_merge_bases(repo, m2, m1);\n-\t\t\t\tif (ret < 0) {\n-\t\t\t\t\tobject_array_clear(&merges);\n-\t\t\t\t\trelease_revisions(&revs);\n-\t\t\t\t\treturn ret;\n-\t\t\t\t}\n-\t\t\t\tif (ret > 0) {\n-\t\t\t\t\tcontains_another = 1;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (!contains_another)\n-\t\t\tadd_object_array(merges.objects[i].item, NULL, result);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-\trelease_revisions(&revs);\n-\treturn result->nr;\n-}\n-\n-static void print_commit(struct repository *repo, struct commit *commit)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tstruct pretty_print_context ctx = {0};\n-\tctx.date_mode.type = DATE_NORMAL;\n-\t/* FIXME: Merge this with output_commit_title() */\n-\tassert(!merge_remote_util(commit));\n-\trepo_format_commit_message(repo, commit, \" %h: %m %s\", &sb, &ctx);\n-\tfprintf(stderr, \"%s\\n\", sb.buf);\n-\tstrbuf_release(&sb);\n-}\n-\n-static int is_valid(const struct diff_filespec *dfs)\n-{\n-\treturn dfs->mode != 0 && !is_null_oid(&dfs->oid);\n-}\n-\n-static int merge_submodule(struct merge_options *opt,\n-\t\t\t   struct object_id *result, const char *path,\n-\t\t\t   const struct object_id *base, const struct object_id *a,\n-\t\t\t   const struct object_id *b)\n-{\n-\tstruct repository subrepo;\n-\tint ret = 0, ret2;\n-\tstruct commit *commit_base, *commit_a, *commit_b;\n-\tint parent_count;\n-\tstruct object_array merges;\n-\n-\tint i;\n-\tint search = !opt->priv->call_depth;\n-\n-\t/* store a in result in case we fail */\n-\t/* FIXME: This is the WRONG resolution for the recursive case when\n-\t * we need to be careful to avoid accidentally matching either side.\n-\t * Should probably use o instead there, much like we do for merging\n-\t * binaries.\n-\t */\n-\toidcpy(result, a);\n-\n-\t/* we can not handle deletion conflicts */\n-\tif (is_null_oid(base))\n-\t\treturn 0;\n-\tif (is_null_oid(a))\n-\t\treturn 0;\n-\tif (is_null_oid(b))\n-\t\treturn 0;\n-\n-\tif (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not checked out)\"), path);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!(commit_base = lookup_commit_reference(&subrepo, base)) ||\n-\t    !(commit_a = lookup_commit_reference(&subrepo, a)) ||\n-\t    !(commit_b = lookup_commit_reference(&subrepo, b))) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits not present)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* check whether both changes are forward */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2 > 0)\n-\t\tret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (!ret2) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (commits don't follow merge-base)\"), path);\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/* Case #1: a is contained in b or vice versa */\n-\tret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, b);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_b);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\tret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);\n-\tif (ret2 < 0) {\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tgoto cleanup;\n-\t}\n-\tif (ret2) {\n-\t\toidcpy(result, a);\n-\t\tif (show(opt, 3)) {\n-\t\t\toutput(opt, 3, _(\"Fast-forwarding submodule %s to the following commit:\"), path);\n-\t\t\trepo_output_commit_title(opt, &subrepo, commit_a);\n-\t\t} else if (show(opt, 2))\n-\t\t\toutput(opt, 2, _(\"Fast-forwarding submodule %s\"), path);\n-\t\telse\n-\t\t\t; /* no output */\n-\n-\t\tret = 1;\n-\t\tgoto cleanup;\n-\t}\n-\n-\t/*\n-\t * Case #2: There are one or more merges that contain a and b in\n-\t * the submodule. If there is only one, then present it as a\n-\t * suggestion to the user, but leave it marked unmerged so the\n-\t * user needs to confirm the resolution.\n-\t */\n-\n-\t/* Skip the search if makes no sense to the calling context.  */\n-\tif (!search)\n-\t\tgoto cleanup;\n-\n-\t/* find commit which merges them */\n-\tparent_count = find_first_merges(&subrepo, &merges, path,\n-\t\t\t\t\t commit_a, commit_b);\n-\tswitch (parent_count) {\n-\tcase -1:\n-\t\toutput(opt, 1,_(\"Failed to merge submodule %s (repository corrupt)\"), path);\n-\t\tret = -1;\n-\t\tbreak;\n-\tcase 0:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (merge following commits not found)\"), path);\n-\t\tbreak;\n-\n-\tcase 1:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (not fast-forward)\"), path);\n-\t\toutput(opt, 2, _(\"Found a possible merge resolution for the submodule:\\n\"));\n-\t\tprint_commit(&subrepo, (struct commit *) merges.objects[0].item);\n-\t\toutput(opt, 2, _(\n-\t\t       \"If this is correct simply add it to the index \"\n-\t\t       \"for example\\n\"\n-\t\t       \"by using:\\n\\n\"\n-\t\t       \"  git update-index --cacheinfo 160000 %s \\\"%s\\\"\\n\\n\"\n-\t\t       \"which will accept this suggestion.\\n\"),\n-\t\t       oid_to_hex(&merges.objects[0].item->oid), path);\n-\t\tbreak;\n-\n-\tdefault:\n-\t\toutput(opt, 1, _(\"Failed to merge submodule %s (multiple merges found)\"), path);\n-\t\tfor (i = 0; i < merges.nr; i++)\n-\t\t\tprint_commit(&subrepo, (struct commit *) merges.objects[i].item);\n-\t}\n-\n-\tobject_array_clear(&merges);\n-cleanup:\n-\trepo_clear(&subrepo);\n-\treturn ret;\n-}\n-\n-static int merge_mode_and_contents(struct merge_options *opt,\n-\t\t\t\t   const struct diff_filespec *o,\n-\t\t\t\t   const struct diff_filespec *a,\n-\t\t\t\t   const struct diff_filespec *b,\n-\t\t\t\t   const char *filename,\n-\t\t\t\t   const char *branch1,\n-\t\t\t\t   const char *branch2,\n-\t\t\t\t   const int extra_marker_size,\n-\t\t\t\t   struct merge_file_info *result)\n-{\n-\tif (opt->branch1 != branch1) {\n-\t\t/*\n-\t\t * It's weird getting a reverse merge with HEAD on the bottom\n-\t\t * side of the conflict markers and the other branch on the\n-\t\t * top.  Fix that.\n-\t\t */\n-\t\treturn merge_mode_and_contents(opt, o, b, a,\n-\t\t\t\t\t       filename,\n-\t\t\t\t\t       branch2, branch1,\n-\t\t\t\t\t       extra_marker_size, result);\n-\t}\n-\n-\tresult->merge = 0;\n-\tresult->clean = 1;\n-\n-\tif ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {\n-\t\tresult->clean = 0;\n-\t\t/*\n-\t\t * FIXME: This is a bad resolution for recursive case; for\n-\t\t * the recursive case we want something that is unlikely to\n-\t\t * accidentally match either side.  Also, while it makes\n-\t\t * sense to prefer regular files over symlinks, it doesn't\n-\t\t * make sense to prefer regular files over submodules.\n-\t\t */\n-\t\tif (S_ISREG(a->mode)) {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t} else {\n-\t\t\tresult->blob.mode = b->mode;\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t}\n-\t} else {\n-\t\tif (!oideq(&a->oid, &o->oid) && !oideq(&b->oid, &o->oid))\n-\t\t\tresult->merge = 1;\n-\n-\t\t/*\n-\t\t * Merge modes\n-\t\t */\n-\t\tif (a->mode == b->mode || a->mode == o->mode)\n-\t\t\tresult->blob.mode = b->mode;\n-\t\telse {\n-\t\t\tresult->blob.mode = a->mode;\n-\t\t\tif (b->mode != o->mode) {\n-\t\t\t\tresult->clean = 0;\n-\t\t\t\tresult->merge = 1;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\telse if (oideq(&b->oid, &o->oid))\n-\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\telse if (S_ISREG(a->mode)) {\n-\t\t\tmmbuffer_t result_buf;\n-\t\t\tint ret = 0, merge_status;\n-\n-\t\t\tmerge_status = merge_3way(opt, &result_buf, o, a, b,\n-\t\t\t\t\t\t  branch1, branch2,\n-\t\t\t\t\t\t  extra_marker_size);\n-\n-\t\t\tif ((merge_status < 0) || !result_buf.ptr)\n-\t\t\t\tret = err(opt, _(\"failed to execute internal merge\"));\n-\n-\t\t\tif (!ret &&\n-\t\t\t    write_object_file(result_buf.ptr, result_buf.size,\n-\t\t\t\t\t      OBJ_BLOB, &result->blob.oid))\n-\t\t\t\tret = err(opt, _(\"unable to add %s to database\"),\n-\t\t\t\t\t  a->path);\n-\n-\t\t\tfree(result_buf.ptr);\n-\t\t\tif (ret)\n-\t\t\t\treturn ret;\n-\t\t\t/* FIXME: bug, what if modes didn't match? */\n-\t\t\tresult->clean = (merge_status == 0);\n-\t\t} else if (S_ISGITLINK(a->mode)) {\n-\t\t\tint clean = merge_submodule(opt, &result->blob.oid,\n-\t\t\t\t\t\t    o->path,\n-\t\t\t\t\t\t    &o->oid,\n-\t\t\t\t\t\t    &a->oid,\n-\t\t\t\t\t\t    &b->oid);\n-\t\t\tif (clean < 0)\n-\t\t\t\treturn -1;\n-\t\t\tresult->clean = clean;\n-\t\t} else if (S_ISLNK(a->mode)) {\n-\t\t\tswitch (opt->recursive_variant) {\n-\t\t\tcase MERGE_VARIANT_NORMAL:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tif (!oideq(&a->oid, &b->oid))\n-\t\t\t\t\tresult->clean = 0;\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_OURS:\n-\t\t\t\toidcpy(&result->blob.oid, &a->oid);\n-\t\t\t\tbreak;\n-\t\t\tcase MERGE_VARIANT_THEIRS:\n-\t\t\t\toidcpy(&result->blob.oid, &b->oid);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t} else\n-\t\t\tBUG(\"unsupported object type in the tree\");\n-\t}\n-\n-\tif (result->merge)\n-\t\toutput(opt, 2, _(\"Auto-merging %s\"), filename);\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_via_dir(struct merge_options *opt,\n-\t\t\t\t struct rename_conflict_info *ci)\n-{\n-\t/*\n-\t * Handle file adds that need to be renamed due to directory rename\n-\t * detection.  This differs from handle_rename_normal, because\n-\t * there is no content merge to do; just move the file into the\n-\t * desired final location.\n-\t */\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tchar *file_path = dest->path;\n-\tint mark_conflicted = (opt->detect_directory_renames ==\n-\t\t\t       MERGE_DIRECTORY_RENAMES_CONFLICT);\n-\tassert(ren->dir_rename_original_dest);\n-\n-\tif (!opt->priv->call_depth && would_lose_untracked(opt, dest->path)) {\n-\t\tmark_conflicted = 1;\n-\t\tfile_path = unique_path(opt, dest->path, ren->branch);\n-\t\toutput(opt, 1, _(\"Error: Refusing to lose untracked file at %s; \"\n-\t\t\t\t \"writing to %s instead.\"),\n-\t\t       dest->path, file_path);\n-\t}\n-\n-\tif (mark_conflicted) {\n-\t\t/*\n-\t\t * Write the file in worktree at file_path.  In the index,\n-\t\t * only record the file at dest->path in the appropriate\n-\t\t * higher stage.\n-\t\t */\n-\t\tif (update_file(opt, 0, dest, file_path))\n-\t\t\treturn -1;\n-\t\tif (file_path != dest->path)\n-\t\t\tfree(file_path);\n-\t\tif (update_stages(opt, dest->path, NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t  ren->branch == opt->branch1 ? NULL : dest))\n-\t\t\treturn -1;\n-\t\treturn 0; /* not clean, but conflicted */\n-\t} else {\n-\t\t/* Update dest->path both in index and in worktree */\n-\t\tif (update_file(opt, 1, dest, dest->path))\n-\t\t\treturn -1;\n-\t\treturn 1; /* clean */\n-\t}\n-}\n-\n-static int handle_change_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path, const char *old_path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *changed,\n-\t\t\t\tconst char *change_branch,\n-\t\t\t\tconst char *delete_branch,\n-\t\t\t\tconst char *change, const char *change_past)\n-{\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = path;\n-\tint ret = 0;\n-\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0) ||\n-\t    (!opt->priv->call_depth && would_lose_untracked(opt, path))) {\n-\t\tupdate_path = alt_path = unique_path(opt, path, change_branch);\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t/*\n-\t\t * We cannot arbitrarily accept either a_sha or b_sha as\n-\t\t * correct; since there is no true \"middle point\" between\n-\t\t * them, simply reuse the base version for virtual merge base.\n-\t\t */\n-\t\tret = remove_file_from_index(opt->repo->index, path);\n-\t\tif (!ret)\n-\t\t\tret = update_file(opt, 0, o, update_path);\n-\t} else {\n-\t\t/*\n-\t\t * Despite the four nearly duplicate messages and argument\n-\t\t * lists below and the ugliness of the nested if-statements,\n-\t\t * having complete messages makes the job easier for\n-\t\t * translators.\n-\t\t *\n-\t\t * The slight variance among the cases is due to the fact\n-\t\t * that:\n-\t\t *   1) directory/file conflicts (in effect if\n-\t\t *      !alt_path) could cause us to need to write the\n-\t\t *      file to a different path.\n-\t\t *   2) renames (in effect if !old_path) could mean that\n-\t\t *      there are two names for the path that the user\n-\t\t *      may know the file by.\n-\t\t */\n-\t\tif (!alt_path) {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path);\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (!old_path) {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, path, delete_branch, change_past,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t} else {\n-\t\t\t\toutput(opt, 1, _(\"CONFLICT (%s/delete): %s deleted in %s \"\n-\t\t\t\t       \"and %s to %s in %s. Version %s of %s left in tree at %s.\"),\n-\t\t\t\t       change, old_path, delete_branch, change_past, path,\n-\t\t\t\t       change_branch, change_branch, path, alt_path);\n-\t\t\t}\n-\t\t}\n-\t\t/*\n-\t\t * No need to call update_file() on path when change_branch ==\n-\t\t * opt->branch1 && !alt_path, since that would needlessly touch\n-\t\t * path.  We could call update_file_flags() with update_cache=0\n-\t\t * and update_wd=0, but that's a no-op.\n-\t\t */\n-\t\tif (change_branch != opt->branch1 || alt_path)\n-\t\t\tret = update_file(opt, 0, changed, update_path);\n-\t}\n-\tfree(alt_path);\n-\n-\treturn ret;\n-}\n-\n-static int handle_rename_delete(struct merge_options *opt,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst struct rename *ren = ci->ren1;\n-\tconst struct diff_filespec *orig = ren->pair->one;\n-\tconst struct diff_filespec *dest = ren->pair->two;\n-\tconst char *rename_branch = ren->branch;\n-\tconst char *delete_branch = (opt->branch1 == ren->branch ?\n-\t\t\t\t     opt->branch2 : opt->branch1);\n-\n-\tif (handle_change_delete(opt,\n-\t\t\t\t opt->priv->call_depth ? orig->path : dest->path,\n-\t\t\t\t opt->priv->call_depth ? NULL : orig->path,\n-\t\t\t\t orig, dest,\n-\t\t\t\t rename_branch, delete_branch,\n-\t\t\t\t _(\"rename\"), _(\"renamed\")))\n-\t\treturn -1;\n-\n-\tif (opt->priv->call_depth)\n-\t\treturn remove_file_from_index(opt->repo->index, dest->path);\n-\telse\n-\t\treturn update_stages(opt, dest->path, NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? dest : NULL,\n-\t\t\t\t     rename_branch == opt->branch1 ? NULL : dest);\n-}\n-\n-static int handle_file_collision(struct merge_options *opt,\n-\t\t\t\t const char *collide_path,\n-\t\t\t\t const char *prev_path1,\n-\t\t\t\t const char *prev_path2,\n-\t\t\t\t const char *branch1, const char *branch2,\n-\t\t\t\t struct diff_filespec *a,\n-\t\t\t\t struct diff_filespec *b)\n-{\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec null;\n-\tchar *alt_path = NULL;\n-\tconst char *update_path = collide_path;\n-\n-\t/*\n-\t * It's easiest to get the correct things into stage 2 and 3, and\n-\t * to make sure that the content merge puts HEAD before the other\n-\t * branch if we just ensure that branch1 == opt->branch1.  So, simply\n-\t * flip arguments around if we don't have that.\n-\t */\n-\tif (branch1 != opt->branch1) {\n-\t\treturn handle_file_collision(opt, collide_path,\n-\t\t\t\t\t     prev_path2, prev_path1,\n-\t\t\t\t\t     branch2, branch1,\n-\t\t\t\t\t     b, a);\n-\t}\n-\n-\t/* Remove rename sources if rename/add or rename/rename(2to1) */\n-\tif (prev_path1)\n-\t\tremove_file(opt, 1, prev_path1,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path1));\n-\tif (prev_path2)\n-\t\tremove_file(opt, 1, prev_path2,\n-\t\t\t    opt->priv->call_depth || would_lose_untracked(opt, prev_path2));\n-\n-\t/*\n-\t * Remove the collision path, if it wouldn't cause dirty contents\n-\t * or an untracked file to get lost.  We'll either overwrite with\n-\t * merged contents, or just write out to differently named files.\n-\t */\n-\tif (was_dirty(opt, collide_path)) {\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else if (would_lose_untracked(opt, collide_path)) {\n-\t\t/*\n-\t\t * Only way we get here is if both renames were from\n-\t\t * a directory rename AND user had an untracked file\n-\t\t * at the location where both files end up after the\n-\t\t * two directory renames.  See testcase 10d of t6043.\n-\t\t */\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file at \"\n-\t\t\t       \"%s, even though it's in the way.\"),\n-\t\t       collide_path);\n-\t\tupdate_path = alt_path = unique_path(opt, collide_path, \"merged\");\n-\t} else {\n-\t\t/*\n-\t\t * FIXME: It's possible that the two files are identical\n-\t\t * and that the current working copy happens to match, in\n-\t\t * which case we are unnecessarily touching the working\n-\t\t * tree file.  It's not a likely enough scenario that I\n-\t\t * want to code up the checks for it and a better fix is\n-\t\t * available if we restructure how unpack_trees() and\n-\t\t * merge-recursive interoperate anyway, so punting for\n-\t\t * now...\n-\t\t */\n-\t\tremove_file(opt, 0, collide_path, 0);\n-\t}\n-\n-\t/* Store things in diff_filespecs for functions that need it */\n-\tnull.path = (char *)collide_path;\n-\toidcpy(&null.oid, null_oid());\n-\tnull.mode = 0;\n-\n-\tif (merge_mode_and_contents(opt, &null, a, b, collide_path,\n-\t\t\t\t    branch1, branch2, opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tmfi.clean &= !alt_path;\n-\tif (update_file(opt, mfi.clean, &mfi.blob, update_path))\n-\t\treturn -1;\n-\tif (!mfi.clean && !opt->priv->call_depth &&\n-\t    update_stages(opt, collide_path, NULL, a, b))\n-\t\treturn -1;\n-\tfree(alt_path);\n-\t/*\n-\t * FIXME: If both a & b both started with conflicts (only possible\n-\t * if they came from a rename/rename(2to1)), but had IDENTICAL\n-\t * contents including those conflicts, then in the next line we claim\n-\t * it was clean.  If someone cares about this case, we should have the\n-\t * caller notify us if we started with conflicts.\n-\t */\n-\treturn mfi.clean;\n-}\n-\n-static int handle_rename_add(struct merge_options *opt,\n-\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* a was renamed to c, and a separate c was added. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *c = ci->ren1->pair->two;\n-\tchar *path = c->path;\n-\tchar *prev_path_desc;\n-\tstruct merge_file_info mfi;\n-\n-\tconst char *rename_branch = ci->ren1->branch;\n-\tconst char *add_branch = (opt->branch1 == rename_branch ?\n-\t\t\t\t  opt->branch2 : opt->branch1);\n-\tint other_stage = (ci->ren1->branch == opt->branch1 ? 3 : 2);\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/add): \"\n-\t       \"Rename %s->%s in %s.  Added %s in %s\"),\n-\t       a->path, c->path, rename_branch,\n-\t       c->path, add_branch);\n-\n-\tprev_path_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tci->ren1->src_entry->stages[other_stage].path = a->path;\n-\tif (merge_mode_and_contents(opt, a, c,\n-\t\t\t\t    &ci->ren1->src_entry->stages[other_stage],\n-\t\t\t\t    prev_path_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(prev_path_desc);\n-\n-\tci->ren1->dst_entry->stages[other_stage].path = mfi.blob.path = c->path;\n-\treturn handle_file_collision(opt,\n-\t\t\t\t     c->path, a->path, NULL,\n-\t\t\t\t     rename_branch, add_branch,\n-\t\t\t\t     &mfi.blob,\n-\t\t\t\t     &ci->ren1->dst_entry->stages[other_stage]);\n-}\n-\n-static char *find_path_for_conflict(struct merge_options *opt,\n-\t\t\t\t    const char *path,\n-\t\t\t\t    const char *branch1,\n-\t\t\t\t    const char *branch2)\n-{\n-\tchar *new_path = NULL;\n-\tif (dir_in_way(opt->repo->index, path, !opt->priv->call_depth, 0)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"%s is a directory in %s adding \"\n-\t\t\t       \"as %s instead\"),\n-\t\t       path, branch2, new_path);\n-\t} else if (would_lose_untracked(opt, path)) {\n-\t\tnew_path = unique_path(opt, path, branch1);\n-\t\toutput(opt, 1, _(\"Refusing to lose untracked file\"\n-\t\t\t       \" at %s; adding as %s instead\"),\n-\t\t       path, new_path);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * Toggle the stage number between \"ours\" and \"theirs\" (2 and 3).\n- */\n-static inline int flip_stage(int stage)\n-{\n-\treturn (2 + 3) - stage;\n-}\n-\n-static int handle_rename_rename_1to2(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* One file was renamed in both branches, but to different names. */\n-\tstruct merge_file_info mfi;\n-\tstruct diff_filespec *add;\n-\tstruct diff_filespec *o = ci->ren1->pair->one;\n-\tstruct diff_filespec *a = ci->ren1->pair->two;\n-\tstruct diff_filespec *b = ci->ren2->pair->two;\n-\tchar *path_desc;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename \\\"%s\\\"->\\\"%s\\\" in branch \\\"%s\\\" \"\n-\t       \"rename \\\"%s\\\"->\\\"%s\\\" in \\\"%s\\\"%s\"),\n-\t       o->path, a->path, ci->ren1->branch,\n-\t       o->path, b->path, ci->ren2->branch,\n-\t       opt->priv->call_depth ? _(\" (left unresolved)\") : \"\");\n-\n-\tpath_desc = xstrfmt(\"%s and %s, both renamed from %s\",\n-\t\t\t    a->path, b->path, o->path);\n-\tif (merge_mode_and_contents(opt, o, a, b, path_desc,\n-\t\t\t\t    ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t    opt->priv->call_depth * 2, &mfi))\n-\t\treturn -1;\n-\tfree(path_desc);\n-\n-\tif (opt->priv->call_depth)\n-\t\tremove_file_from_index(opt->repo->index, o->path);\n-\n-\t/*\n-\t * For each destination path, we need to see if there is a\n-\t * rename/add collision.  If not, we can write the file out\n-\t * to the specified location.\n-\t */\n-\tadd = &ci->ren1->dst_entry->stages[flip_stage(2)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = a->path;\n-\t\tif (handle_file_collision(opt, a->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  &mfi.blob, add) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, a->path,\n-\t\t\t\t\t\t\tci->ren1->branch,\n-\t\t\t\t\t\t\tci->ren2->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : a->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, a->path, NULL, a, NULL))\n-\t\t\treturn -1;\n-\t}\n-\n-\tif (!mfi.clean && mfi.blob.mode == a->mode &&\n-\t    oideq(&mfi.blob.oid, &a->oid)) {\n-\t\t/*\n-\t\t * Getting here means we were attempting to merge a binary\n-\t\t * blob.  Since we can't merge binaries, the merge algorithm\n-\t\t * just takes one side.  But we don't want to copy the\n-\t\t * contents of one side to both paths; we'd rather use the\n-\t\t * original content at the given path for each path.\n-\t\t */\n-\t\toidcpy(&mfi.blob.oid, &b->oid);\n-\t\tmfi.blob.mode = b->mode;\n-\t}\n-\tadd = &ci->ren2->dst_entry->stages[flip_stage(3)];\n-\tif (is_valid(add)) {\n-\t\tadd->path = mfi.blob.path = b->path;\n-\t\tif (handle_file_collision(opt, b->path,\n-\t\t\t\t\t  NULL, NULL,\n-\t\t\t\t\t  ci->ren1->branch,\n-\t\t\t\t\t  ci->ren2->branch,\n-\t\t\t\t\t  add, &mfi.blob) < 0)\n-\t\t\treturn -1;\n-\t} else {\n-\t\tchar *new_path = find_path_for_conflict(opt, b->path,\n-\t\t\t\t\t\t\tci->ren2->branch,\n-\t\t\t\t\t\t\tci->ren1->branch);\n-\t\tif (update_file(opt, 0, &mfi.blob,\n-\t\t\t\tnew_path ? new_path : b->path))\n-\t\t\treturn -1;\n-\t\tfree(new_path);\n-\t\tif (!opt->priv->call_depth &&\n-\t\t    update_stages(opt, b->path, NULL, NULL, b))\n-\t\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int handle_rename_rename_2to1(struct merge_options *opt,\n-\t\t\t\t     struct rename_conflict_info *ci)\n-{\n-\t/* Two files, a & b, were renamed to the same thing, c. */\n-\tstruct diff_filespec *a = ci->ren1->pair->one;\n-\tstruct diff_filespec *b = ci->ren2->pair->one;\n-\tstruct diff_filespec *c1 = ci->ren1->pair->two;\n-\tstruct diff_filespec *c2 = ci->ren2->pair->two;\n-\tchar *path = c1->path; /* == c2->path */\n-\tchar *path_side_1_desc;\n-\tchar *path_side_2_desc;\n-\tstruct merge_file_info mfi_c1;\n-\tstruct merge_file_info mfi_c2;\n-\tint ostage1, ostage2;\n-\n-\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t       \"Rename %s->%s in %s. \"\n-\t       \"Rename %s->%s in %s\"),\n-\t       a->path, c1->path, ci->ren1->branch,\n-\t       b->path, c2->path, ci->ren2->branch);\n-\n-\tpath_side_1_desc = xstrfmt(\"version of %s from %s\", path, a->path);\n-\tpath_side_2_desc = xstrfmt(\"version of %s from %s\", path, b->path);\n-\tostage1 = ci->ren1->branch == opt->branch1 ? 3 : 2;\n-\tostage2 = flip_stage(ostage1);\n-\tci->ren1->src_entry->stages[ostage1].path = a->path;\n-\tci->ren2->src_entry->stages[ostage2].path = b->path;\n-\tif (merge_mode_and_contents(opt, a, c1,\n-\t\t\t\t    &ci->ren1->src_entry->stages[ostage1],\n-\t\t\t\t    path_side_1_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c1) ||\n-\t    merge_mode_and_contents(opt, b,\n-\t\t\t\t    &ci->ren2->src_entry->stages[ostage2],\n-\t\t\t\t    c2, path_side_2_desc,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    1 + opt->priv->call_depth * 2, &mfi_c2))\n-\t\treturn -1;\n-\tfree(path_side_1_desc);\n-\tfree(path_side_2_desc);\n-\tmfi_c1.blob.path = path;\n-\tmfi_c2.blob.path = path;\n-\n-\treturn handle_file_collision(opt, path, a->path, b->path,\n-\t\t\t\t     ci->ren1->branch, ci->ren2->branch,\n-\t\t\t\t     &mfi_c1.blob, &mfi_c2.blob);\n-}\n-\n-/*\n- * Get the diff_filepairs changed between o_tree and tree.\n- */\n-static struct diff_queue_struct *get_diffpairs(struct merge_options *opt,\n-\t\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t\t       struct tree *tree)\n-{\n-\tstruct diff_queue_struct *ret;\n-\tstruct diff_options opts;\n-\n-\trepo_diff_setup(opt->repo, &opts);\n-\topts.flags.recursive = 1;\n-\topts.flags.rename_empty = 0;\n-\topts.detect_rename = merge_detect_rename(opt);\n-\t/*\n-\t * We do not have logic to handle the detection of copies.  In\n-\t * fact, it may not even make sense to add such logic: would we\n-\t * really want a change to a base file to be propagated through\n-\t * multiple other files by a merge?\n-\t */\n-\tif (opts.detect_rename > DIFF_DETECT_RENAME)\n-\t\topts.detect_rename = DIFF_DETECT_RENAME;\n-\topts.rename_limit = (opt->rename_limit >= 0) ? opt->rename_limit : 7000;\n-\topts.rename_score = opt->rename_score;\n-\topts.show_rename_progress = opt->show_rename_progress;\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_setup_done(&opts);\n-\tdiff_tree_oid(&o_tree->object.oid, &tree->object.oid, \"\", &opts);\n-\tdiffcore_std(&opts);\n-\tif (opts.needed_rename_limit > opt->priv->needed_rename_limit)\n-\t\topt->priv->needed_rename_limit = opts.needed_rename_limit;\n-\n-\tret = xmalloc(sizeof(*ret));\n-\t*ret = diff_queued_diff;\n-\n-\topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_queued_diff.nr = 0;\n-\tdiff_queued_diff.queue = NULL;\n-\tdiff_flush(&opts);\n-\treturn ret;\n-}\n-\n-static int tree_has_path(struct repository *r, struct tree *tree,\n-\t\t\t const char *path)\n-{\n-\tstruct object_id hashy;\n-\tunsigned short mode_o;\n-\n-\treturn !get_tree_entry(r,\n-\t\t\t       &tree->object.oid, path,\n-\t\t\t       &hashy, &mode_o);\n-}\n-\n-/*\n- * Return a new string that replaces the beginning portion (which matches\n- * entry->dir), with entry->new_dir.  In perl-speak:\n- *   new_path_name = (old_path =~ s/entry->dir/entry->new_dir/);\n- * NOTE:\n- *   Caller must ensure that old_path starts with entry->dir + '/'.\n- */\n-static char *apply_dir_rename(struct dir_rename_entry *entry,\n-\t\t\t      const char *old_path)\n-{\n-\tstruct strbuf new_path = STRBUF_INIT;\n-\tint oldlen, newlen;\n-\n-\tif (entry->non_unique_new_dir)\n-\t\treturn NULL;\n-\n-\toldlen = strlen(entry->dir);\n-\tif (entry->new_dir.len == 0)\n-\t\t/*\n-\t\t * If someone renamed/merged a subdirectory into the root\n-\t\t * directory (e.g. 'some/subdir' -> ''), then we want to\n-\t\t * avoid returning\n-\t\t *     '' + '/filename'\n-\t\t * as the rename; we need to make old_path + oldlen advance\n-\t\t * past the '/' character.\n-\t\t */\n-\t\toldlen++;\n-\tnewlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;\n-\tstrbuf_grow(&new_path, newlen);\n-\tstrbuf_addbuf(&new_path, &entry->new_dir);\n-\tstrbuf_addstr(&new_path, &old_path[oldlen]);\n-\n-\treturn strbuf_detach(&new_path, NULL);\n-}\n-\n-static void get_renamed_dir_portion(const char *old_path, const char *new_path,\n-\t\t\t\t    char **old_dir, char **new_dir)\n-{\n-\tchar *end_of_old, *end_of_new;\n-\n-\t/* Default return values: NULL, meaning no rename */\n-\t*old_dir = NULL;\n-\t*new_dir = NULL;\n-\n-\t/*\n-\t * For\n-\t *    \"a/b/c/d/e/foo.c\" -> \"a/b/some/thing/else/e/foo.c\"\n-\t * the \"e/foo.c\" part is the same, we just want to know that\n-\t *    \"a/b/c/d\" was renamed to \"a/b/some/thing/else\"\n-\t * so, for this example, this function returns \"a/b/c/d\" in\n-\t * *old_dir and \"a/b/some/thing/else\" in *new_dir.\n-\t */\n-\n-\t/*\n-\t * If the basename of the file changed, we don't care.  We want\n-\t * to know which portion of the directory, if any, changed.\n-\t */\n-\tend_of_old = strrchr(old_path, '/');\n-\tend_of_new = strrchr(new_path, '/');\n-\n-\t/*\n-\t * If end_of_old is NULL, old_path wasn't in a directory, so there\n-\t * could not be a directory rename (our rule elsewhere that a\n-\t * directory which still exists is not considered to have been\n-\t * renamed means the root directory can never be renamed -- because\n-\t * the root directory always exists).\n-\t */\n-\tif (!end_of_old)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If new_path contains no directory (end_of_new is NULL), then we\n-\t * have a rename of old_path's directory to the root directory.\n-\t */\n-\tif (!end_of_new) {\n-\t\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/* Find the first non-matching character traversing backwards */\n-\twhile (*--end_of_new == *--end_of_old &&\n-\t       end_of_old != old_path &&\n-\t       end_of_new != new_path)\n-\t\t; /* Do nothing; all in the while loop */\n-\n-\t/*\n-\t * If both got back to the beginning of their strings, then the\n-\t * directory didn't change at all, only the basename did.\n-\t */\n-\tif (end_of_old == old_path && end_of_new == new_path &&\n-\t    *end_of_old == *end_of_new)\n-\t\treturn; /* Note: *old_dir and *new_dir are still NULL */\n-\n-\t/*\n-\t * If end_of_new got back to the beginning of its string, and\n-\t * end_of_old got back to the beginning of some subdirectory, then\n-\t * we have a rename/merge of a subdirectory into the root, which\n-\t * needs slightly special handling.\n-\t *\n-\t * Note: There is no need to consider the opposite case, with a\n-\t * rename/merge of the root directory into some subdirectory\n-\t * because as noted above the root directory always exists so it\n-\t * cannot be considered to be renamed.\n-\t */\n-\tif (end_of_new == new_path &&\n-\t    end_of_old != old_path && end_of_old[-1] == '/') {\n-\t\t*old_dir = xstrndup(old_path, --end_of_old - old_path);\n-\t\t*new_dir = xstrdup(\"\");\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * We've found the first non-matching character in the directory\n-\t * paths.  That means the current characters we were looking at\n-\t * were part of the first non-matching subdir name going back from\n-\t * the end of the strings.  Get the whole name by advancing both\n-\t * end_of_old and end_of_new to the NEXT '/' character.  That will\n-\t * represent the entire directory rename.\n-\t *\n-\t * The reason for the increment is cases like\n-\t *    a/b/star/foo/whatever.c -> a/b/tar/foo/random.c\n-\t * After dropping the basename and going back to the first\n-\t * non-matching character, we're now comparing:\n-\t *    a/b/s          and         a/b/\n-\t * and we want to be comparing:\n-\t *    a/b/star/      and         a/b/tar/\n-\t * but without the pre-increment, the one on the right would stay\n-\t * a/b/.\n-\t */\n-\tend_of_old = strchr(++end_of_old, '/');\n-\tend_of_new = strchr(++end_of_new, '/');\n-\n-\t/* Copy the old and new directories into *old_dir and *new_dir. */\n-\t*old_dir = xstrndup(old_path, end_of_old - old_path);\n-\t*new_dir = xstrndup(new_path, end_of_new - new_path);\n-}\n-\n-static void remove_hashmap_entries(struct hashmap *dir_renames,\n-\t\t\t\t   struct string_list *items_to_remove)\n-{\n-\tint i;\n-\tstruct dir_rename_entry *entry;\n-\n-\tfor (i = 0; i < items_to_remove->nr; i++) {\n-\t\tentry = items_to_remove->items[i].util;\n-\t\thashmap_remove(dir_renames, &entry->ent, NULL);\n-\t}\n-\tstring_list_clear(items_to_remove, 0);\n-}\n-\n-/*\n- * See if there is a directory rename for path, and if there are any file\n- * level conflicts for the renamed location.  If there is a rename and\n- * there are no conflicts, return the new name.  Otherwise, return NULL.\n- */\n-static char *handle_path_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t const char *path,\n-\t\t\t\t\t struct dir_rename_entry *entry,\n-\t\t\t\t\t struct hashmap *collisions,\n-\t\t\t\t\t struct tree *tree)\n-{\n-\tchar *new_path = NULL;\n-\tstruct collision_entry *collision_ent;\n-\tint clean = 1;\n-\tstruct strbuf collision_paths = STRBUF_INIT;\n-\n-\t/*\n-\t * entry has the mapping of old directory name to new directory name\n-\t * that we want to apply to path.\n-\t */\n-\tnew_path = apply_dir_rename(entry, path);\n-\n-\tif (!new_path) {\n-\t\t/* This should only happen when entry->non_unique_new_dir set */\n-\t\tif (!entry->non_unique_new_dir)\n-\t\t\tBUG(\"entry->non_unique_new_dir not set and !new_path\");\n-\t\toutput(opt, 1, _(\"CONFLICT (directory rename split): \"\n-\t\t\t       \"Unclear where to place %s because directory \"\n-\t\t\t       \"%s was renamed to multiple other directories, \"\n-\t\t\t       \"with no destination getting a majority of the \"\n-\t\t\t       \"files.\"),\n-\t\t       path, entry->dir);\n-\t\tclean = 0;\n-\t\treturn NULL;\n-\t}\n-\n-\t/*\n-\t * The caller needs to have ensured that it has pre-populated\n-\t * collisions with all paths that map to new_path.  Do a quick check\n-\t * to ensure that's the case.\n-\t */\n-\tcollision_ent = collision_find_entry(collisions, new_path);\n-\tif (!collision_ent)\n-\t\tBUG(\"collision_ent is NULL\");\n-\n-\t/*\n-\t * Check for one-sided add/add/.../add conflicts, i.e.\n-\t * where implicit renames from the other side doing\n-\t * directory rename(s) can affect this side of history\n-\t * to put multiple paths into the same location.  Warn\n-\t * and bail on directory renames for such paths.\n-\t */\n-\tif (collision_ent->reported_already) {\n-\t\tclean = 0;\n-\t} else if (tree_has_path(opt->repo, tree, new_path)) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Existing \"\n-\t\t\t       \"file/dir at %s in the way of implicit \"\n-\t\t\t       \"directory rename(s) putting the following \"\n-\t\t\t       \"path(s) there: %s.\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t} else if (collision_ent->source_files.nr > 1) {\n-\t\tcollision_ent->reported_already = 1;\n-\t\tstrbuf_add_separated_string_list(&collision_paths, \", \",\n-\t\t\t\t\t\t &collision_ent->source_files);\n-\t\toutput(opt, 1, _(\"CONFLICT (implicit dir rename): Cannot map \"\n-\t\t\t       \"more than one path to %s; implicit directory \"\n-\t\t\t       \"renames tried to put these paths there: %s\"),\n-\t\t       new_path, collision_paths.buf);\n-\t\tclean = 0;\n-\t}\n-\n-\t/* Free memory we no longer need */\n-\tstrbuf_release(&collision_paths);\n-\tif (!clean && new_path) {\n-\t\tfree(new_path);\n-\t\treturn NULL;\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-/*\n- * There are a couple things we want to do at the directory level:\n- *   1. Check for both sides renaming to the same thing, in order to avoid\n- *      implicit renaming of files that should be left in place.  (See\n- *      testcase 6b in t6043 for details.)\n- *   2. Prune directory renames if there are still files left in the\n- *      original directory.  These represent a partial directory rename,\n- *      i.e. a rename where only some of the files within the directory\n- *      were renamed elsewhere.  (Technically, this could be done earlier\n- *      in get_directory_renames(), except that would prevent us from\n- *      doing the previous check and thus failing testcase 6b.)\n- *   3. Check for rename/rename(1to2) conflicts (at the directory level).\n- *      In the future, we could potentially record this info as well and\n- *      omit reporting rename/rename(1to2) conflicts for each path within\n- *      the affected directories, thus cleaning up the merge output.\n- *   NOTE: We do NOT check for rename/rename(2to1) conflicts at the\n- *         directory level, because merging directories is fine.  If it\n- *         causes conflicts for files within those merged directories, then\n- *         that should be detected at the individual path level.\n- */\n-static void handle_directory_level_conflicts(struct merge_options *opt,\n-\t\t\t\t\t     struct hashmap *dir_re_head,\n-\t\t\t\t\t     struct tree *head,\n-\t\t\t\t\t     struct hashmap *dir_re_merge,\n-\t\t\t\t\t     struct tree *merge)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *head_ent;\n-\tstruct dir_rename_entry *merge_ent;\n-\n-\tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n-\tstruct string_list remove_from_merge = STRING_LIST_INIT_NODUP;\n-\n-\thashmap_for_each_entry(dir_re_head, &iter, head_ent,\n-\t\t\t\tent /* member name */) {\n-\t\tmerge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);\n-\t\tif (merge_ent &&\n-\t\t    !head_ent->non_unique_new_dir &&\n-\t\t    !merge_ent->non_unique_new_dir &&\n-\t\t    !strbuf_cmp(&head_ent->new_dir, &merge_ent->new_dir)) {\n-\t\t\t/* 1. Renamed identically; remove it from both sides */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t} else if (tree_has_path(opt->repo, head, head_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-\n-\thashmap_for_each_entry(dir_re_merge, &iter, merge_ent,\n-\t\t\t\tent /* member name */) {\n-\t\thead_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);\n-\t\tif (tree_has_path(opt->repo, merge, merge_ent->dir)) {\n-\t\t\t/* 2. This wasn't a directory rename after all */\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t} else if (head_ent &&\n-\t\t\t   !head_ent->non_unique_new_dir &&\n-\t\t\t   !merge_ent->non_unique_new_dir) {\n-\t\t\t/* 3. rename/rename(1to2) */\n-\t\t\t/*\n-\t\t\t * We can assume it's not rename/rename(1to1) because\n-\t\t\t * that was case (1), already checked above.  So we\n-\t\t\t * know that head_ent->new_dir and merge_ent->new_dir\n-\t\t\t * are different strings.\n-\t\t\t */\n-\t\t\toutput(opt, 1, _(\"CONFLICT (rename/rename): \"\n-\t\t\t\t       \"Rename directory %s->%s in %s. \"\n-\t\t\t\t       \"Rename directory %s->%s in %s\"),\n-\t\t\t       head_ent->dir, head_ent->new_dir.buf, opt->branch1,\n-\t\t\t       head_ent->dir, merge_ent->new_dir.buf, opt->branch2);\n-\t\t\tstring_list_append(&remove_from_head,\n-\t\t\t\t\t   head_ent->dir)->util = head_ent;\n-\t\t\tstrbuf_release(&head_ent->new_dir);\n-\t\t\tstring_list_append(&remove_from_merge,\n-\t\t\t\t\t   merge_ent->dir)->util = merge_ent;\n-\t\t\tstrbuf_release(&merge_ent->new_dir);\n-\t\t}\n-\t}\n-\n-\tremove_hashmap_entries(dir_re_head, &remove_from_head);\n-\tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n-}\n-\n-static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n-{\n-\tstruct hashmap *dir_renames;\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *entry;\n-\tint i;\n-\n-\t/*\n-\t * Typically, we think of a directory rename as all files from a\n-\t * certain directory being moved to a target directory.  However,\n-\t * what if someone first moved two files from the original\n-\t * directory in one commit, and then renamed the directory\n-\t * somewhere else in a later commit?  At merge time, we just know\n-\t * that files from the original directory went to two different\n-\t * places, and that the bulk of them ended up in the same place.\n-\t * We want each directory rename to represent where the bulk of the\n-\t * files from that directory end up; this function exists to find\n-\t * where the bulk of the files went.\n-\t *\n-\t * The first loop below simply iterates through the list of file\n-\t * renames, finding out how often each directory rename pair\n-\t * possibility occurs.\n-\t */\n-\tdir_renames = xmalloc(sizeof(*dir_renames));\n-\tdir_rename_init(dir_renames);\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tint *count;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *old_dir, *new_dir;\n-\n-\t\t/* File not part of directory rename if it wasn't renamed */\n-\t\tif (pair->status != 'R')\n-\t\t\tcontinue;\n-\n-\t\tget_renamed_dir_portion(pair->one->path, pair->two->path,\n-\t\t\t\t\t&old_dir,        &new_dir);\n-\t\tif (!old_dir)\n-\t\t\t/* Directory didn't change at all; ignore this one. */\n-\t\t\tcontinue;\n-\n-\t\tentry = dir_rename_find_entry(dir_renames, old_dir);\n-\t\tif (!entry) {\n-\t\t\tentry = xmalloc(sizeof(*entry));\n-\t\t\tdir_rename_entry_init(entry, old_dir);\n-\t\t\thashmap_put(dir_renames, &entry->ent);\n-\t\t} else {\n-\t\t\tfree(old_dir);\n-\t\t}\n-\t\titem = string_list_lookup(&entry->possible_new_dirs, new_dir);\n-\t\tif (!item) {\n-\t\t\titem = string_list_insert(&entry->possible_new_dirs,\n-\t\t\t\t\t\t  new_dir);\n-\t\t\titem->util = xcalloc(1, sizeof(int));\n-\t\t} else {\n-\t\t\tfree(new_dir);\n-\t\t}\n-\t\tcount = item->util;\n-\t\t*count += 1;\n-\t}\n-\n-\t/*\n-\t * For each directory with files moved out of it, we find out which\n-\t * target directory received the most files so we can declare it to\n-\t * be the \"winning\" target location for the directory rename.  This\n-\t * winner gets recorded in new_dir.  If there is no winner\n-\t * (multiple target directories received the same number of files),\n-\t * we set non_unique_new_dir.  Once we've determined the winner (or\n-\t * that there is no winner), we no longer need possible_new_dirs.\n-\t */\n-\thashmap_for_each_entry(dir_renames, &iter, entry,\n-\t\t\t\tent /* member name */) {\n-\t\tint max = 0;\n-\t\tint bad_max = 0;\n-\t\tchar *best = NULL;\n-\n-\t\tfor (i = 0; i < entry->possible_new_dirs.nr; i++) {\n-\t\t\tint *count = entry->possible_new_dirs.items[i].util;\n-\n-\t\t\tif (*count == max)\n-\t\t\t\tbad_max = max;\n-\t\t\telse if (*count > max) {\n-\t\t\t\tmax = *count;\n-\t\t\t\tbest = entry->possible_new_dirs.items[i].string;\n-\t\t\t}\n-\t\t}\n-\t\tif (bad_max == max)\n-\t\t\tentry->non_unique_new_dir = 1;\n-\t\telse {\n-\t\t\tassert(entry->new_dir.len == 0);\n-\t\t\tstrbuf_addstr(&entry->new_dir, best);\n-\t\t}\n-\t\t/*\n-\t\t * The relevant directory sub-portion of the original full\n-\t\t * filepaths were xstrndup'ed before inserting into\n-\t\t * possible_new_dirs, and instead of manually iterating the\n-\t\t * list and free'ing each, just lie and tell\n-\t\t * possible_new_dirs that it did the strdup'ing so that it\n-\t\t * will free them for us.\n-\t\t */\n-\t\tentry->possible_new_dirs.strdup_strings = 1;\n-\t\tstring_list_clear(&entry->possible_new_dirs, 1);\n-\t}\n-\n-\treturn dir_renames;\n-}\n-\n-static struct dir_rename_entry *check_dir_renamed(const char *path,\n-\t\t\t\t\t\t  struct hashmap *dir_renames)\n-{\n-\tchar *temp = xstrdup(path);\n-\tchar *end;\n-\tstruct dir_rename_entry *entry = NULL;\n-\n-\twhile ((end = strrchr(temp, '/'))) {\n-\t\t*end = '\\0';\n-\t\tentry = dir_rename_find_entry(dir_renames, temp);\n-\t\tif (entry)\n-\t\t\tbreak;\n-\t}\n-\tfree(temp);\n-\treturn entry;\n-}\n-\n-static void compute_collisions(struct hashmap *collisions,\n-\t\t\t       struct hashmap *dir_renames,\n-\t\t\t       struct diff_queue_struct *pairs)\n-{\n-\tint i;\n-\n-\t/*\n-\t * Multiple files can be mapped to the same path due to directory\n-\t * renames done by the other side of history.  Since that other\n-\t * side of history could have merged multiple directories into one,\n-\t * if our side of history added the same file basename to each of\n-\t * those directories, then all N of them would get implicitly\n-\t * renamed by the directory rename detection into the same path,\n-\t * and we'd get an add/add/.../add conflict, and all those adds\n-\t * from *this* side of history.  This is not representable in the\n-\t * index, and users aren't going to easily be able to make sense of\n-\t * it.  So we need to provide a good warning about what's\n-\t * happening, and fall back to no-directory-rename detection\n-\t * behavior for those paths.\n-\t *\n-\t * See testcases 9e and all of section 5 from t6043 for examples.\n-\t */\n-\tcollision_init(collisions);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct dir_rename_entry *dir_rename_ent;\n-\t\tstruct collision_entry *collision_ent;\n-\t\tchar *new_path;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R')\n-\t\t\tcontinue;\n-\t\tdir_rename_ent = check_dir_renamed(pair->two->path,\n-\t\t\t\t\t\t   dir_renames);\n-\t\tif (!dir_rename_ent)\n-\t\t\tcontinue;\n-\n-\t\tnew_path = apply_dir_rename(dir_rename_ent, pair->two->path);\n-\t\tif (!new_path)\n-\t\t\t/*\n-\t\t\t * dir_rename_ent->non_unique_new_path is true, which\n-\t\t\t * means there is no directory rename for us to use,\n-\t\t\t * which means it won't cause us any additional\n-\t\t\t * collisions.\n-\t\t\t */\n-\t\t\tcontinue;\n-\t\tcollision_ent = collision_find_entry(collisions, new_path);\n-\t\tif (!collision_ent) {\n-\t\t\tCALLOC_ARRAY(collision_ent, 1);\n-\t\t\thashmap_entry_init(&collision_ent->ent,\n-\t\t\t\t\t\tstrhash(new_path));\n-\t\t\thashmap_put(collisions, &collision_ent->ent);\n-\t\t\tcollision_ent->target_file = new_path;\n-\t\t} else {\n-\t\t\tfree(new_path);\n-\t\t}\n-\t\tstring_list_insert(&collision_ent->source_files,\n-\t\t\t\t   pair->two->path);\n-\t}\n-}\n-\n-static char *check_for_directory_rename(struct merge_options *opt,\n-\t\t\t\t\tconst char *path,\n-\t\t\t\t\tstruct tree *tree,\n-\t\t\t\t\tstruct hashmap *dir_renames,\n-\t\t\t\t\tstruct hashmap *dir_rename_exclusions,\n-\t\t\t\t\tstruct hashmap *collisions,\n-\t\t\t\t\tint *clean_merge)\n-{\n-\tchar *new_path = NULL;\n-\tstruct dir_rename_entry *entry = check_dir_renamed(path, dir_renames);\n-\tstruct dir_rename_entry *oentry = NULL;\n-\n-\tif (!entry)\n-\t\treturn new_path;\n-\n-\t/*\n-\t * This next part is a little weird.  We do not want to do an\n-\t * implicit rename into a directory we renamed on our side, because\n-\t * that will result in a spurious rename/rename(1to2) conflict.  An\n-\t * example:\n-\t *   Base commit: dumbdir/afile, otherdir/bfile\n-\t *   Side 1:      smrtdir/afile, otherdir/bfile\n-\t *   Side 2:      dumbdir/afile, dumbdir/bfile\n-\t * Here, while working on Side 1, we could notice that otherdir was\n-\t * renamed/merged to dumbdir, and change the diff_filepair for\n-\t * otherdir/bfile into a rename into dumbdir/bfile.  However, Side\n-\t * 2 will notice the rename from dumbdir to smrtdir, and do the\n-\t * transitive rename to move it from dumbdir/bfile to\n-\t * smrtdir/bfile.  That gives us bfile in dumbdir vs being in\n-\t * smrtdir, a rename/rename(1to2) conflict.  We really just want\n-\t * the file to end up in smrtdir.  And the way to achieve that is\n-\t * to not let Side1 do the rename to dumbdir, since we know that is\n-\t * the source of one of our directory renames.\n-\t *\n-\t * That's why oentry and dir_rename_exclusions is here.\n-\t *\n-\t * As it turns out, this also prevents N-way transient rename\n-\t * confusion; See testcases 9c and 9d of t6043.\n-\t */\n-\toentry = dir_rename_find_entry(dir_rename_exclusions, entry->new_dir.buf);\n-\tif (oentry) {\n-\t\toutput(opt, 1, _(\"WARNING: Avoiding applying %s -> %s rename \"\n-\t\t\t       \"to %s, because %s itself was renamed.\"),\n-\t\t       entry->dir, entry->new_dir.buf, path, entry->new_dir.buf);\n-\t} else {\n-\t\tnew_path = handle_path_level_conflicts(opt, path, entry,\n-\t\t\t\t\t\t       collisions, tree);\n-\t\t*clean_merge &= (new_path != NULL);\n-\t}\n-\n-\treturn new_path;\n-}\n-\n-static void apply_directory_rename_modifications(struct merge_options *opt,\n-\t\t\t\t\t\t struct diff_filepair *pair,\n-\t\t\t\t\t\t char *new_path,\n-\t\t\t\t\t\t struct rename *re,\n-\t\t\t\t\t\t struct tree *tree,\n-\t\t\t\t\t\t struct tree *o_tree,\n-\t\t\t\t\t\t struct tree *a_tree,\n-\t\t\t\t\t\t struct tree *b_tree,\n-\t\t\t\t\t\t struct string_list *entries)\n-{\n-\tstruct string_list_item *item;\n-\tint stage = (tree == a_tree ? 2 : 3);\n-\tint update_wd;\n-\n-\t/*\n-\t * In all cases where we can do directory rename detection,\n-\t * unpack_trees() will have read pair->two->path into the\n-\t * index and the working copy.  We need to remove it so that\n-\t * we can instead place it at new_path.  It is guaranteed to\n-\t * not be untracked (unpack_trees() would have errored out\n-\t * saying the file would have been overwritten), but it might\n-\t * be dirty, though.\n-\t */\n-\tupdate_wd = !was_dirty(opt, pair->two->path);\n-\tif (!update_wd)\n-\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t       pair->two->path);\n-\tremove_file(opt, 1, pair->two->path, !update_wd);\n-\n-\t/* Find or create a new re->dst_entry */\n-\titem = string_list_lookup(entries, new_path);\n-\tif (item) {\n-\t\t/*\n-\t\t * Since we're renaming on this side of history, and it's\n-\t\t * due to a directory rename on the other side of history\n-\t\t * (which we only allow when the directory in question no\n-\t\t * longer exists on the other side of history), the\n-\t\t * original entry for re->dst_entry is no longer\n-\t\t * necessary...\n-\t\t */\n-\t\tre->dst_entry->processed = 1;\n-\n-\t\t/*\n-\t\t * ...because we'll be using this new one.\n-\t\t */\n-\t\tre->dst_entry = item->util;\n-\t} else {\n-\t\t/*\n-\t\t * re->dst_entry is for the before-dir-rename path, and we\n-\t\t * need it to hold information for the after-dir-rename\n-\t\t * path.  Before creating a new entry, we need to mark the\n-\t\t * old one as unnecessary (...unless it is shared by\n-\t\t * src_entry, i.e. this didn't use to be a rename, in which\n-\t\t * case we can just allow the normal processing to happen\n-\t\t * for it).\n-\t\t */\n-\t\tif (pair->status == 'R')\n-\t\t\tre->dst_entry->processed = 1;\n-\n-\t\tre->dst_entry = insert_stage_data(opt->repo, new_path,\n-\t\t\t\t\t\t  o_tree, a_tree, b_tree,\n-\t\t\t\t\t\t  entries);\n-\t\titem = string_list_insert(entries, new_path);\n-\t\titem->util = re->dst_entry;\n-\t}\n-\n-\t/*\n-\t * Update the stage_data with the information about the path we are\n-\t * moving into place.  That slot will be empty and available for us\n-\t * to write to because of the collision checks in\n-\t * handle_path_level_conflicts().  In other words,\n-\t * re->dst_entry->stages[stage].oid will be the null_oid, so it's\n-\t * open for us to write to.\n-\t *\n-\t * It may be tempting to actually update the index at this point as\n-\t * well, using update_stages_for_stage_data(), but as per the big\n-\t * \"NOTE\" in update_stages(), doing so will modify the current\n-\t * in-memory index which will break calls to would_lose_untracked()\n-\t * that we need to make.  Instead, we need to just make sure that\n-\t * the various handle_rename_*() functions update the index\n-\t * explicitly rather than relying on unpack_trees() to have done it.\n-\t */\n-\tget_tree_entry(opt->repo,\n-\t\t       &tree->object.oid,\n-\t\t       pair->two->path,\n-\t\t       &re->dst_entry->stages[stage].oid,\n-\t\t       &re->dst_entry->stages[stage].mode);\n-\n-\t/*\n-\t * Record the original change status (or 'type' of change).  If it\n-\t * was originally an add ('A'), this lets us differentiate later\n-\t * between a RENAME_DELETE conflict and RENAME_VIA_DIR (they\n-\t * otherwise look the same).  If it was originally a rename ('R'),\n-\t * this lets us remember and report accurately about the transitive\n-\t * renaming that occurred via the directory rename detection.  Also,\n-\t * record the original destination name.\n-\t */\n-\tre->dir_rename_original_type = pair->status;\n-\tre->dir_rename_original_dest = pair->two->path;\n-\n-\t/*\n-\t * We don't actually look at pair->status again, but it seems\n-\t * pedagogically correct to adjust it.\n-\t */\n-\tpair->status = 'R';\n-\n-\t/*\n-\t * Finally, record the new location.\n-\t */\n-\tpair->two->path = new_path;\n-}\n-\n-/*\n- * Get information of all renames which occurred in 'pairs', making use of\n- * any implicit directory renames inferred from the other side of history.\n- * We need the three trees in the merge ('o_tree', 'a_tree' and 'b_tree')\n- * to be able to associate the correct cache entries with the rename\n- * information; tree is always equal to either a_tree or b_tree.\n- */\n-static struct string_list *get_renames(struct merge_options *opt,\n-\t\t\t\t       const char *branch,\n-\t\t\t\t       struct diff_queue_struct *pairs,\n-\t\t\t\t       struct hashmap *dir_renames,\n-\t\t\t\t       struct hashmap *dir_rename_exclusions,\n-\t\t\t\t       struct tree *tree,\n-\t\t\t\t       struct tree *o_tree,\n-\t\t\t\t       struct tree *a_tree,\n-\t\t\t\t       struct tree *b_tree,\n-\t\t\t\t       struct string_list *entries,\n-\t\t\t\t       int *clean_merge)\n-{\n-\tint i;\n-\tstruct hashmap collisions;\n-\tstruct hashmap_iter iter;\n-\tstruct collision_entry *e;\n-\tstruct string_list *renames;\n-\n-\tcompute_collisions(&collisions, dir_renames, pairs);\n-\tCALLOC_ARRAY(renames, 1);\n-\n-\tfor (i = 0; i < pairs->nr; ++i) {\n-\t\tstruct string_list_item *item;\n-\t\tstruct rename *re;\n-\t\tstruct diff_filepair *pair = pairs->queue[i];\n-\t\tchar *new_path; /* non-NULL only with directory renames */\n-\n-\t\tif (pair->status != 'A' && pair->status != 'R') {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tnew_path = check_for_directory_rename(opt, pair->two->path, tree,\n-\t\t\t\t\t\t      dir_renames,\n-\t\t\t\t\t\t      dir_rename_exclusions,\n-\t\t\t\t\t\t      &collisions,\n-\t\t\t\t\t\t      clean_merge);\n-\t\tif (pair->status != 'R' && !new_path) {\n-\t\t\tdiff_free_filepair(pair);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tre = xmalloc(sizeof(*re));\n-\t\tre->processed = 0;\n-\t\tre->pair = pair;\n-\t\tre->branch = branch;\n-\t\tre->dir_rename_original_type = '\\0';\n-\t\tre->dir_rename_original_dest = NULL;\n-\t\titem = string_list_lookup(entries, re->pair->one->path);\n-\t\tif (!item)\n-\t\t\tre->src_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->one->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->src_entry = item->util;\n-\n-\t\titem = string_list_lookup(entries, re->pair->two->path);\n-\t\tif (!item)\n-\t\t\tre->dst_entry = insert_stage_data(opt->repo,\n-\t\t\t\t\tre->pair->two->path,\n-\t\t\t\t\to_tree, a_tree, b_tree, entries);\n-\t\telse\n-\t\t\tre->dst_entry = item->util;\n-\t\titem = string_list_insert(renames, pair->one->path);\n-\t\titem->util = re;\n-\t\tif (new_path)\n-\t\t\tapply_directory_rename_modifications(opt, pair, new_path,\n-\t\t\t\t\t\t\t     re, tree, o_tree,\n-\t\t\t\t\t\t\t     a_tree, b_tree,\n-\t\t\t\t\t\t\t     entries);\n-\t}\n-\n-\thashmap_for_each_entry(&collisions, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->target_file);\n-\t\tstring_list_clear(&e->source_files, 0);\n-\t}\n-\thashmap_clear_and_free(&collisions, struct collision_entry, ent);\n-\treturn renames;\n-}\n-\n-static int process_renames(struct merge_options *opt,\n-\t\t\t   struct string_list *a_renames,\n-\t\t\t   struct string_list *b_renames)\n-{\n-\tint clean_merge = 1, i, j;\n-\tstruct string_list a_by_dst = STRING_LIST_INIT_NODUP;\n-\tstruct string_list b_by_dst = STRING_LIST_INIT_NODUP;\n-\tconst struct rename *sre;\n-\n-\t/*\n-\t * Note that as we build the list, we do not need to check if the\n-\t * existing destination path is already in the list, because the\n-\t * structure of diffcore_rename guarantees we won't have duplicates.\n-\t */\n-\tfor (i = 0; i < a_renames->nr; i++) {\n-\t\tsre = a_renames->items[i].util;\n-\t\tstring_list_append(&a_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tfor (i = 0; i < b_renames->nr; i++) {\n-\t\tsre = b_renames->items[i].util;\n-\t\tstring_list_append(&b_by_dst, sre->pair->two->path)->util\n-\t\t\t= (void *)sre;\n-\t}\n-\tstring_list_sort(&a_by_dst);\n-\tstring_list_sort(&b_by_dst);\n-\n-\tfor (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {\n-\t\tstruct string_list *renames1, *renames2Dst;\n-\t\tstruct rename *ren1 = NULL, *ren2 = NULL;\n-\t\tconst char *ren1_src, *ren1_dst;\n-\t\tstruct string_list_item *lookup;\n-\n-\t\tif (i >= a_renames->nr) {\n-\t\t\tren2 = b_renames->items[j++].util;\n-\t\t} else if (j >= b_renames->nr) {\n-\t\t\tren1 = a_renames->items[i++].util;\n-\t\t} else {\n-\t\t\tint compare = strcmp(a_renames->items[i].string,\n-\t\t\t\t\t     b_renames->items[j].string);\n-\t\t\tif (compare <= 0)\n-\t\t\t\tren1 = a_renames->items[i++].util;\n-\t\t\tif (compare >= 0)\n-\t\t\t\tren2 = b_renames->items[j++].util;\n-\t\t}\n-\n-\t\t/* TODO: refactor, so that 1/2 are not needed */\n-\t\tif (ren1) {\n-\t\t\trenames1 = a_renames;\n-\t\t\trenames2Dst = &b_by_dst;\n-\t\t} else {\n-\t\t\trenames1 = b_renames;\n-\t\t\trenames2Dst = &a_by_dst;\n-\t\t\tSWAP(ren2, ren1);\n-\t\t}\n-\n-\t\tif (ren1->processed)\n-\t\t\tcontinue;\n-\t\tren1->processed = 1;\n-\t\tren1->dst_entry->processed = 1;\n-\t\t/* BUG: We should only mark src_entry as processed if we\n-\t\t * are not dealing with a rename + add-source case.\n-\t\t */\n-\t\tren1->src_entry->processed = 1;\n-\n-\t\tren1_src = ren1->pair->one->path;\n-\t\tren1_dst = ren1->pair->two->path;\n-\n-\t\tif (ren2) {\n-\t\t\t/* One file renamed on both sides */\n-\t\t\tconst char *ren2_src = ren2->pair->one->path;\n-\t\t\tconst char *ren2_dst = ren2->pair->two->path;\n-\t\t\tenum rename_type rename_type;\n-\t\t\tif (strcmp(ren1_src, ren2_src) != 0)\n-\t\t\t\tBUG(\"ren1_src != ren2_src\");\n-\t\t\tren2->dst_entry->processed = 1;\n-\t\t\tren2->processed = 1;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0) {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_TWO;\n-\t\t\t\tclean_merge = 0;\n-\t\t\t} else {\n-\t\t\t\trename_type = RENAME_ONE_FILE_TO_ONE;\n-\t\t\t\t/* BUG: We should only remove ren1_src in\n-\t\t\t\t * the base stage (think of rename +\n-\t\t\t\t * add-source cases).\n-\t\t\t\t */\n-\t\t\t\tremove_file(opt, 1, ren1_src, 1);\n-\t\t\t\tupdate_entry(ren1->dst_entry,\n-\t\t\t\t\t     ren1->pair->one,\n-\t\t\t\t\t     ren1->pair->two,\n-\t\t\t\t\t     ren2->pair->two);\n-\t\t\t}\n-\t\t\tsetup_rename_conflict_info(rename_type, opt, ren1, ren2);\n-\t\t} else if ((lookup = string_list_lookup(renames2Dst, ren1_dst))) {\n-\t\t\t/* Two different files renamed to the same thing */\n-\t\t\tchar *ren2_dst;\n-\t\t\tren2 = lookup->util;\n-\t\t\tren2_dst = ren2->pair->two->path;\n-\t\t\tif (strcmp(ren1_dst, ren2_dst) != 0)\n-\t\t\t\tBUG(\"ren1_dst != ren2_dst\");\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tren2->processed = 1;\n-\t\t\t/*\n-\t\t\t * BUG: We should only mark src_entry as processed\n-\t\t\t * if we are not dealing with a rename + add-source\n-\t\t\t * case.\n-\t\t\t */\n-\t\t\tren2->src_entry->processed = 1;\n-\n-\t\t\tsetup_rename_conflict_info(RENAME_TWO_FILES_TO_ONE,\n-\t\t\t\t\t\t   opt, ren1, ren2);\n-\t\t} else {\n-\t\t\t/* Renamed in 1, maybe changed in 2 */\n-\t\t\t/* we only use sha1 and mode of these */\n-\t\t\tstruct diff_filespec src_other, dst_other;\n-\t\t\tint try_merge;\n-\n-\t\t\t/*\n-\t\t\t * unpack_trees loads entries from common-commit\n-\t\t\t * into stage 1, from head-commit into stage 2, and\n-\t\t\t * from merge-commit into stage 3.  We keep track\n-\t\t\t * of which side corresponds to the rename.\n-\t\t\t */\n-\t\t\tint renamed_stage = a_renames == renames1 ? 2 : 3;\n-\t\t\tint other_stage =   a_renames == renames1 ? 3 : 2;\n-\n-\t\t\t/*\n-\t\t\t * Directory renames have a funny corner case...\n-\t\t\t */\n-\t\t\tint renamed_to_self = !strcmp(ren1_src, ren1_dst);\n-\n-\t\t\t/* BUG: We should only remove ren1_src in the base\n-\t\t\t * stage and in other_stage (think of rename +\n-\t\t\t * add-source case).\n-\t\t\t */\n-\t\t\tif (!renamed_to_self)\n-\t\t\t\tremove_file(opt, 1, ren1_src,\n-\t\t\t\t\t    renamed_stage == 2 ||\n-\t\t\t\t\t    !was_tracked(opt, ren1_src));\n-\n-\t\t\toidcpy(&src_other.oid,\n-\t\t\t       &ren1->src_entry->stages[other_stage].oid);\n-\t\t\tsrc_other.mode = ren1->src_entry->stages[other_stage].mode;\n-\t\t\toidcpy(&dst_other.oid,\n-\t\t\t       &ren1->dst_entry->stages[other_stage].oid);\n-\t\t\tdst_other.mode = ren1->dst_entry->stages[other_stage].mode;\n-\t\t\ttry_merge = 0;\n-\n-\t\t\tif (oideq(&src_other.oid, null_oid()) &&\n-\t\t\t    ren1->dir_rename_original_type == 'A') {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_VIA_DIR,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (renamed_to_self) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (oideq(&src_other.oid, null_oid())) {\n-\t\t\t\tsetup_rename_conflict_info(RENAME_DELETE,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if ((dst_other.mode == ren1->pair->two->mode) &&\n-\t\t\t\t   oideq(&dst_other.oid, &ren1->pair->two->oid)) {\n-\t\t\t\t/*\n-\t\t\t\t * Added file on the other side identical to\n-\t\t\t\t * the file being renamed: clean merge.\n-\t\t\t\t * Also, there is no need to overwrite the\n-\t\t\t\t * file already in the working copy, so call\n-\t\t\t\t * update_file_flags() instead of\n-\t\t\t\t * update_file().\n-\t\t\t\t */\n-\t\t\t\tif (update_file_flags(opt,\n-\t\t\t\t\t\t      ren1->pair->two,\n-\t\t\t\t\t\t      ren1_dst,\n-\t\t\t\t\t\t      1, /* update_cache */\n-\t\t\t\t\t\t      0  /* update_wd    */))\n-\t\t\t\t\tclean_merge = -1;\n-\t\t\t} else if (!oideq(&dst_other.oid, null_oid())) {\n-\t\t\t\t/*\n-\t\t\t\t * Probably not a clean merge, but it's\n-\t\t\t\t * premature to set clean_merge to 0 here,\n-\t\t\t\t * because if the rename merges cleanly and\n-\t\t\t\t * the merge exactly matches the newly added\n-\t\t\t\t * file, then the merge will be clean.\n-\t\t\t\t */\n-\t\t\t\tsetup_rename_conflict_info(RENAME_ADD,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else\n-\t\t\t\ttry_merge = 1;\n-\n-\t\t\tif (clean_merge < 0)\n-\t\t\t\tgoto cleanup_and_return;\n-\t\t\tif (try_merge) {\n-\t\t\t\tstruct diff_filespec *o, *a, *b;\n-\t\t\t\tsrc_other.path = (char *)ren1_src;\n-\n-\t\t\t\to = ren1->pair->one;\n-\t\t\t\tif (a_renames == renames1) {\n-\t\t\t\t\ta = ren1->pair->two;\n-\t\t\t\t\tb = &src_other;\n-\t\t\t\t} else {\n-\t\t\t\t\tb = ren1->pair->two;\n-\t\t\t\t\ta = &src_other;\n-\t\t\t\t}\n-\t\t\t\tupdate_entry(ren1->dst_entry, o, a, b);\n-\t\t\t\tsetup_rename_conflict_info(RENAME_NORMAL,\n-\t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t}\n-\t\t}\n-\t}\n-cleanup_and_return:\n-\tstring_list_clear(&a_by_dst, 0);\n-\tstring_list_clear(&b_by_dst, 0);\n-\n-\treturn clean_merge;\n-}\n-\n-struct rename_info {\n-\tstruct string_list *head_renames;\n-\tstruct string_list *merge_renames;\n-};\n-\n-static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n-\t\t\t\t   struct hashmap *dir_renames)\n-{\n-\tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *e;\n-\n-\thashmap_for_each_entry(dir_renames, &iter, e,\n-\t\t\t\tent /* member name */) {\n-\t\tfree(e->dir);\n-\t\tstrbuf_release(&e->new_dir);\n-\t\t/* possible_new_dirs already cleared in get_directory_renames */\n-\t}\n-\thashmap_clear_and_free(dir_renames, struct dir_rename_entry, ent);\n-\tfree(dir_renames);\n-\n-\tfree(pairs->queue);\n-\tfree(pairs);\n-}\n-\n-static int detect_and_process_renames(struct merge_options *opt,\n-\t\t\t\t      struct tree *common,\n-\t\t\t\t      struct tree *head,\n-\t\t\t\t      struct tree *merge,\n-\t\t\t\t      struct string_list *entries,\n-\t\t\t\t      struct rename_info *ri)\n-{\n-\tstruct diff_queue_struct *head_pairs, *merge_pairs;\n-\tstruct hashmap *dir_re_head, *dir_re_merge;\n-\tint clean = 1;\n-\n-\tri->head_renames = NULL;\n-\tri->merge_renames = NULL;\n-\n-\tif (!merge_detect_rename(opt))\n-\t\treturn 1;\n-\n-\thead_pairs = get_diffpairs(opt, common, head);\n-\tmerge_pairs = get_diffpairs(opt, common, merge);\n-\n-\tif ((opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) ||\n-\t    (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t     !opt->priv->call_depth)) {\n-\t\tdir_re_head = get_directory_renames(head_pairs);\n-\t\tdir_re_merge = get_directory_renames(merge_pairs);\n-\n-\t\thandle_directory_level_conflicts(opt,\n-\t\t\t\t\t\t dir_re_head, head,\n-\t\t\t\t\t\t dir_re_merge, merge);\n-\t} else {\n-\t\tdir_re_head  = xmalloc(sizeof(*dir_re_head));\n-\t\tdir_re_merge = xmalloc(sizeof(*dir_re_merge));\n-\t\tdir_rename_init(dir_re_head);\n-\t\tdir_rename_init(dir_re_merge);\n-\t}\n-\n-\tri->head_renames  = get_renames(opt, opt->branch1, head_pairs,\n-\t\t\t\t\tdir_re_merge, dir_re_head, head,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tri->merge_renames = get_renames(opt, opt->branch2, merge_pairs,\n-\t\t\t\t\tdir_re_head, dir_re_merge, merge,\n-\t\t\t\t\tcommon, head, merge, entries,\n-\t\t\t\t\t&clean);\n-\tif (clean < 0)\n-\t\tgoto cleanup;\n-\tclean &= process_renames(opt, ri->head_renames, ri->merge_renames);\n-\n-cleanup:\n-\t/*\n-\t * Some cleanup is deferred until cleanup_renames() because the\n-\t * data structures are still needed and referenced in\n-\t * process_entry().  But there are a few things we can free now.\n-\t */\n-\tinitial_cleanup_rename(head_pairs, dir_re_head);\n-\tinitial_cleanup_rename(merge_pairs, dir_re_merge);\n-\n-\treturn clean;\n-}\n-\n-static void final_cleanup_rename(struct string_list *rename)\n-{\n-\tconst struct rename *re;\n-\tint i;\n-\n-\tif (!rename)\n-\t\treturn;\n-\n-\tfor (i = 0; i < rename->nr; i++) {\n-\t\tre = rename->items[i].util;\n-\t\tdiff_free_filepair(re->pair);\n-\t\tif (re->src_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->src_entry->rename_conflict_info);\n-\t\tif (re->dst_entry->rename_conflict_info_owned)\n-\t\t\tFREE_AND_NULL(re->dst_entry->rename_conflict_info);\n-\t}\n-\tstring_list_clear(rename, 1);\n-\tfree(rename);\n-}\n-\n-static void final_cleanup_renames(struct rename_info *re_info)\n-{\n-\tfinal_cleanup_rename(re_info->head_renames);\n-\tfinal_cleanup_rename(re_info->merge_renames);\n-}\n-\n-static int read_oid_strbuf(struct merge_options *opt,\n-\t\t\t   const struct object_id *oid,\n-\t\t\t   struct strbuf *dst)\n-{\n-\tvoid *buf;\n-\tenum object_type type;\n-\tunsigned long size;\n-\tbuf = repo_read_object_file(the_repository, oid, &type, &size);\n-\tif (!buf)\n-\t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n-\tif (type != OBJ_BLOB) {\n-\t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n-\t}\n-\tstrbuf_attach(dst, buf, size, size + 1);\n-\treturn 0;\n-}\n-\n-static int blob_unchanged(struct merge_options *opt,\n-\t\t\t  const struct diff_filespec *o,\n-\t\t\t  const struct diff_filespec *a,\n-\t\t\t  int renormalize, const char *path)\n-{\n-\tstruct strbuf obuf = STRBUF_INIT;\n-\tstruct strbuf abuf = STRBUF_INIT;\n-\tint ret = 0; /* assume changed for safety */\n-\tstruct index_state *idx = opt->repo->index;\n-\n-\tif (a->mode != o->mode)\n-\t\treturn 0;\n-\tif (oideq(&o->oid, &a->oid))\n-\t\treturn 1;\n-\tif (!renormalize)\n-\t\treturn 0;\n-\n-\tif (read_oid_strbuf(opt, &o->oid, &obuf) ||\n-\t    read_oid_strbuf(opt, &a->oid, &abuf))\n-\t\tgoto error_return;\n-\t/*\n-\t * Note: binary | is used so that both renormalizations are\n-\t * performed.  Comparison can be skipped if both files are\n-\t * unchanged since their sha1s have already been compared.\n-\t */\n-\tif (renormalize_buffer(idx, path, obuf.buf, obuf.len, &obuf) |\n-\t    renormalize_buffer(idx, path, abuf.buf, abuf.len, &abuf))\n-\t\tret = (obuf.len == abuf.len && !memcmp(obuf.buf, abuf.buf, obuf.len));\n-\n-error_return:\n-\tstrbuf_release(&obuf);\n-\tstrbuf_release(&abuf);\n-\treturn ret;\n-}\n-\n-static int handle_modify_delete(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b)\n-{\n-\tconst char *modify_branch, *delete_branch;\n-\tconst struct diff_filespec *changed;\n-\n-\tif (is_valid(a)) {\n-\t\tmodify_branch = opt->branch1;\n-\t\tdelete_branch = opt->branch2;\n-\t\tchanged = a;\n-\t} else {\n-\t\tmodify_branch = opt->branch2;\n-\t\tdelete_branch = opt->branch1;\n-\t\tchanged = b;\n-\t}\n-\n-\treturn handle_change_delete(opt,\n-\t\t\t\t    path, NULL,\n-\t\t\t\t    o, changed,\n-\t\t\t\t    modify_branch, delete_branch,\n-\t\t\t\t    _(\"modify\"), _(\"modified\"));\n-}\n-\n-static int handle_content_merge(struct merge_file_info *mfi,\n-\t\t\t\tstruct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tint is_dirty,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tconst char *reason = _(\"content\");\n-\tunsigned df_conflict_remains = 0;\n-\n-\tif (!is_valid(o))\n-\t\treason = _(\"add/add\");\n-\n-\tassert(o->path && a->path && b->path);\n-\tif (ci && dir_in_way(opt->repo->index, path, !opt->priv->call_depth,\n-\t\t\t     S_ISGITLINK(ci->ren1->pair->two->mode)))\n-\t\tdf_conflict_remains = 1;\n-\n-\tif (merge_mode_and_contents(opt, o, a, b, path,\n-\t\t\t\t    opt->branch1, opt->branch2,\n-\t\t\t\t    opt->priv->call_depth * 2, mfi))\n-\t\treturn -1;\n-\n-\t/*\n-\t * We can skip updating the working tree file iff:\n-\t *   a) The merge is clean\n-\t *   b) The merge matches what was in HEAD (content, mode, pathname)\n-\t *   c) The target path is usable (i.e. not involved in D/F conflict)\n-\t */\n-\tif (mfi->clean && was_tracked_and_matches(opt, path, &mfi->blob) &&\n-\t    !df_conflict_remains) {\n-\t\tint pos;\n-\t\tstruct cache_entry *ce;\n-\n-\t\toutput(opt, 3, _(\"Skipped %s (merged same as existing)\"), path);\n-\t\tif (add_cacheinfo(opt, &mfi->blob, path,\n-\t\t\t\t  0, (!opt->priv->call_depth && !is_dirty), 0))\n-\t\t\treturn -1;\n-\t\t/*\n-\t\t * However, add_cacheinfo() will delete the old cache entry\n-\t\t * and add a new one.  We need to copy over any skip_worktree\n-\t\t * flag to avoid making the file appear as if it were\n-\t\t * deleted by the user.\n-\t\t */\n-\t\tpos = index_name_pos(&opt->priv->orig_index, path, strlen(path));\n-\t\tce = opt->priv->orig_index.cache[pos];\n-\t\tif (ce_skip_worktree(ce)) {\n-\t\t\tpos = index_name_pos(opt->repo->index, path, strlen(path));\n-\t\t\tce = opt->repo->index->cache[pos];\n-\t\t\tce->ce_flags |= CE_SKIP_WORKTREE;\n-\t\t}\n-\t\treturn mfi->clean;\n-\t}\n-\n-\tif (!mfi->clean) {\n-\t\tif (S_ISGITLINK(mfi->blob.mode))\n-\t\t\treason = _(\"submodule\");\n-\t\toutput(opt, 1, _(\"CONFLICT (%s): Merge conflict in %s\"),\n-\t\t\t\treason, path);\n-\t\tif (ci && !df_conflict_remains)\n-\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\treturn -1;\n-\t}\n-\n-\tif (df_conflict_remains || is_dirty) {\n-\t\tchar *new_path;\n-\t\tif (opt->priv->call_depth) {\n-\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t} else {\n-\t\t\tif (!mfi->clean) {\n-\t\t\t\tif (update_stages(opt, path, o, a, b))\n-\t\t\t\t\treturn -1;\n-\t\t\t} else {\n-\t\t\t\tint file_from_stage2 = was_tracked(opt, path);\n-\n-\t\t\t\tif (update_stages(opt, path, NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? &mfi->blob : NULL,\n-\t\t\t\t\t\t  file_from_stage2 ? NULL : &mfi->blob))\n-\t\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t}\n-\t\tnew_path = unique_path(opt, path, ci->ren1->branch);\n-\t\tif (is_dirty) {\n-\t\t\toutput(opt, 1, _(\"Refusing to lose dirty file at %s\"),\n-\t\t\t       path);\n-\t\t}\n-\t\toutput(opt, 1, _(\"Adding as %s instead\"), new_path);\n-\t\tif (update_file(opt, 0, &mfi->blob, new_path)) {\n-\t\t\tfree(new_path);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tfree(new_path);\n-\t\tmfi->clean = 0;\n-\t} else if (update_file(opt, mfi->clean, &mfi->blob, path))\n-\t\treturn -1;\n-\treturn !is_dirty && mfi->clean;\n-}\n-\n-static int handle_rename_normal(struct merge_options *opt,\n-\t\t\t\tconst char *path,\n-\t\t\t\tconst struct diff_filespec *o,\n-\t\t\t\tconst struct diff_filespec *a,\n-\t\t\t\tconst struct diff_filespec *b,\n-\t\t\t\tstruct rename_conflict_info *ci)\n-{\n-\tstruct rename *ren = ci->ren1;\n-\tstruct merge_file_info mfi;\n-\tint clean;\n-\n-\t/* Merge the content and write it out */\n-\tclean = handle_content_merge(&mfi, opt, path, was_dirty(opt, path),\n-\t\t\t\t     o, a, b, ci);\n-\n-\tif (clean &&\n-\t    opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&\n-\t    ren->dir_rename_original_dest) {\n-\t\tif (update_stages(opt, path,\n-\t\t\t\t  &mfi.blob, &mfi.blob, &mfi.blob))\n-\t\t\treturn -1;\n-\t\tclean = 0; /* not clean, but conflicted */\n-\t}\n-\treturn clean;\n-}\n-\n-static void dir_rename_warning(const char *msg,\n-\t\t\t       int is_add,\n-\t\t\t       int clean,\n-\t\t\t       struct merge_options *opt,\n-\t\t\t       struct rename *ren)\n-{\n-\tconst char *other_branch;\n-\tother_branch = (ren->branch == opt->branch1 ?\n-\t\t\topt->branch2 : opt->branch1);\n-\tif (is_add) {\n-\t\toutput(opt, clean ? 2 : 1, msg,\n-\t\t       ren->pair->one->path, ren->branch,\n-\t\t       other_branch, ren->pair->two->path);\n-\t\treturn;\n-\t}\n-\toutput(opt, clean ? 2 : 1, msg,\n-\t       ren->pair->one->path, ren->dir_rename_original_dest, ren->branch,\n-\t       other_branch, ren->pair->two->path);\n-}\n-static int warn_about_dir_renamed_entries(struct merge_options *opt,\n-\t\t\t\t\t  struct rename *ren)\n-{\n-\tconst char *msg;\n-\tint clean = 1, is_add;\n-\n-\tif (!ren)\n-\t\treturn clean;\n-\n-\t/* Return early if ren was not affected/created by a directory rename */\n-\tif (!ren->dir_rename_original_dest)\n-\t\treturn clean;\n-\n-\t/* Sanity checks */\n-\tassert(opt->detect_directory_renames > MERGE_DIRECTORY_RENAMES_NONE);\n-\tassert(ren->dir_rename_original_type == 'A' ||\n-\t       ren->dir_rename_original_type == 'R');\n-\n-\t/* Check whether to treat directory renames as a conflict */\n-\tclean = (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE);\n-\n-\tis_add = (ren->dir_rename_original_type == 'A');\n-\tif (ren->dir_rename_original_type == 'A' && clean) {\n-\t\tmsg = _(\"Path updated: %s added in %s inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'A' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s added in %s \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && clean) {\n-\t\tmsg = _(\"Path updated: %s renamed to %s in %s, inside a \"\n-\t\t\t\"directory that was renamed in %s; moving it to %s.\");\n-\t} else if (ren->dir_rename_original_type == 'R' && !clean) {\n-\t\tmsg = _(\"CONFLICT (file location): %s renamed to %s in %s, \"\n-\t\t\t\"inside a directory that was renamed in %s, \"\n-\t\t\t\"suggesting it should perhaps be moved to %s.\");\n-\t} else {\n-\t\tBUG(\"Impossible dir_rename_original_type/clean combination\");\n-\t}\n-\tdir_rename_warning(msg, is_add, clean, opt, ren);\n-\n-\treturn clean;\n-}\n-\n-/* Per entry merge function */\n-static int process_entry(struct merge_options *opt,\n-\t\t\t const char *path, struct stage_data *entry)\n-{\n-\tint clean_merge = 1;\n-\tint normalize = opt->renormalize;\n-\n-\tstruct diff_filespec *o = &entry->stages[1];\n-\tstruct diff_filespec *a = &entry->stages[2];\n-\tstruct diff_filespec *b = &entry->stages[3];\n-\tint o_valid = is_valid(o);\n-\tint a_valid = is_valid(a);\n-\tint b_valid = is_valid(b);\n-\to->path = a->path = b->path = (char*)path;\n-\n-\tentry->processed = 1;\n-\tif (entry->rename_conflict_info) {\n-\t\tstruct rename_conflict_info *ci = entry->rename_conflict_info;\n-\t\tstruct diff_filespec *temp;\n-\t\tint path_clean;\n-\n-\t\tpath_clean = warn_about_dir_renamed_entries(opt, ci->ren1);\n-\t\tpath_clean &= warn_about_dir_renamed_entries(opt, ci->ren2);\n-\n-\t\t/*\n-\t\t * For cases with a single rename, {o,a,b}->path have all been\n-\t\t * set to the rename target path; we need to set two of these\n-\t\t * back to the rename source.\n-\t\t * For rename/rename conflicts, we'll manually fix paths below.\n-\t\t */\n-\t\ttemp = (opt->branch1 == ci->ren1->branch) ? b : a;\n-\t\to->path = temp->path = ci->ren1->pair->one->path;\n-\t\tif (ci->ren2) {\n-\t\t\tassert(opt->branch1 == ci->ren1->branch);\n-\t\t}\n-\n-\t\tswitch (ci->rename_type) {\n-\t\tcase RENAME_NORMAL:\n-\t\tcase RENAME_ONE_FILE_TO_ONE:\n-\t\t\tclean_merge = handle_rename_normal(opt, path, o, a, b,\n-\t\t\t\t\t\t\t   ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_VIA_DIR:\n-\t\t\tclean_merge = handle_rename_via_dir(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_ADD:\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the renamed file\n-\t\t\t * merges cleanly and the result can then be\n-\t\t\t * two-way merged cleanly with the added file, I\n-\t\t\t * guess it's a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_add(opt, ci);\n-\t\t\tbreak;\n-\t\tcase RENAME_DELETE:\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_delete(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_ONE_FILE_TO_TWO:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note:\n-\t\t\t * ren[12]->pair->one->path are equal.\n-\t\t\t */\n-\t\t\to->path = ci->ren1->pair->one->path;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_rename_rename_1to2(opt, ci))\n-\t\t\t\tclean_merge = -1;\n-\t\t\tbreak;\n-\t\tcase RENAME_TWO_FILES_TO_ONE:\n-\t\t\t/*\n-\t\t\t * Manually fix up paths; note,\n-\t\t\t * ren[12]->pair->two->path are actually equal.\n-\t\t\t */\n-\t\t\to->path = NULL;\n-\t\t\ta->path = ci->ren1->pair->two->path;\n-\t\t\tb->path = ci->ren2->pair->two->path;\n-\n-\t\t\t/*\n-\t\t\t * Probably unclean merge, but if the two renamed\n-\t\t\t * files merge cleanly and the two resulting files\n-\t\t\t * can then be two-way merged cleanly, I guess it's\n-\t\t\t * a clean merge?\n-\t\t\t */\n-\t\t\tclean_merge = handle_rename_rename_2to1(opt, ci);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tentry->processed = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (path_clean < clean_merge)\n-\t\t\tclean_merge = path_clean;\n-\t} else if (o_valid && (!a_valid || !b_valid)) {\n-\t\t/* Case A: Deleted in one */\n-\t\tif ((!a_valid && !b_valid) ||\n-\t\t    (!b_valid && blob_unchanged(opt, o, a, normalize, path)) ||\n-\t\t    (!a_valid && blob_unchanged(opt, o, b, normalize, path))) {\n-\t\t\t/* Deleted in both or deleted in one and\n-\t\t\t * unchanged in the other */\n-\t\t\tif (a_valid)\n-\t\t\t\toutput(opt, 2, _(\"Removing %s\"), path);\n-\t\t\t/* do not touch working file if it did not exist */\n-\t\t\tremove_file(opt, 1, path, !a_valid);\n-\t\t} else {\n-\t\t\t/* Modify/delete; deleted side may have put a directory in the way */\n-\t\t\tclean_merge = 0;\n-\t\t\tif (handle_modify_delete(opt, path, o, a, b))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if ((!o_valid && a_valid && !b_valid) ||\n-\t\t   (!o_valid && !a_valid && b_valid)) {\n-\t\t/* Case B: Added in one. */\n-\t\t/* [nothing|directory] -> ([nothing|directory], file) */\n-\n-\t\tconst char *add_branch;\n-\t\tconst char *other_branch;\n-\t\tconst char *conf;\n-\t\tconst struct diff_filespec *contents;\n-\n-\t\tif (a_valid) {\n-\t\t\tadd_branch = opt->branch1;\n-\t\t\tother_branch = opt->branch2;\n-\t\t\tcontents = a;\n-\t\t\tconf = _(\"file/directory\");\n-\t\t} else {\n-\t\t\tadd_branch = opt->branch2;\n-\t\t\tother_branch = opt->branch1;\n-\t\t\tcontents = b;\n-\t\t\tconf = _(\"directory/file\");\n-\t\t}\n-\t\tif (dir_in_way(opt->repo->index, path,\n-\t\t\t       !opt->priv->call_depth && !S_ISGITLINK(a->mode),\n-\t\t\t       0)) {\n-\t\t\tchar *new_path = unique_path(opt, path, add_branch);\n-\t\t\tclean_merge = 0;\n-\t\t\toutput(opt, 1, _(\"CONFLICT (%s): There is a directory with name %s in %s. \"\n-\t\t\t       \"Adding %s as %s\"),\n-\t\t\t       conf, path, other_branch, path, new_path);\n-\t\t\tif (update_file(opt, 0, contents, new_path))\n-\t\t\t\tclean_merge = -1;\n-\t\t\telse if (opt->priv->call_depth)\n-\t\t\t\tremove_file_from_index(opt->repo->index, path);\n-\t\t\tfree(new_path);\n-\t\t} else {\n-\t\t\toutput(opt, 2, _(\"Adding %s\"), path);\n-\t\t\t/* do not overwrite file if already present */\n-\t\t\tif (update_file_flags(opt, contents, path, 1, !a_valid))\n-\t\t\t\tclean_merge = -1;\n-\t\t}\n-\t} else if (a_valid && b_valid) {\n-\t\tif (!o_valid) {\n-\t\t\t/* Case C: Added in both (check for same permissions) */\n-\t\t\toutput(opt, 1,\n-\t\t\t       _(\"CONFLICT (add/add): Merge conflict in %s\"),\n-\t\t\t       path);\n-\t\t\tclean_merge = handle_file_collision(opt,\n-\t\t\t\t\t\t\t    path, NULL, NULL,\n-\t\t\t\t\t\t\t    opt->branch1,\n-\t\t\t\t\t\t\t    opt->branch2,\n-\t\t\t\t\t\t\t    a, b);\n-\t\t} else {\n-\t\t\t/* case D: Modified in both, but differently. */\n-\t\t\tstruct merge_file_info mfi;\n-\t\t\tint is_dirty = 0; /* unpack_trees would have bailed if dirty */\n-\t\t\tclean_merge = handle_content_merge(&mfi, opt, path,\n-\t\t\t\t\t\t\t   is_dirty,\n-\t\t\t\t\t\t\t   o, a, b, NULL);\n-\t\t}\n-\t} else if (!o_valid && !a_valid && !b_valid) {\n-\t\t/*\n-\t\t * this entry was deleted altogether. a_mode == 0 means\n-\t\t * we had that path and want to actively remove it.\n-\t\t */\n-\t\tremove_file(opt, 1, path, !a->mode);\n-\t} else\n-\t\tBUG(\"fatal merge failure, shouldn't happen.\");\n-\n-\treturn clean_merge;\n-}\n-\n-static int merge_trees_internal(struct merge_options *opt,\n-\t\t\t\tstruct tree *head,\n-\t\t\t\tstruct tree *merge,\n-\t\t\t\tstruct tree *merge_base,\n-\t\t\t\tstruct tree **result)\n-{\n-\tstruct index_state *istate = opt->repo->index;\n-\tint code, clean;\n-\n-\tif (opt->subtree_shift) {\n-\t\tmerge = shift_tree_object(opt->repo, head, merge,\n-\t\t\t\t\t  opt->subtree_shift);\n-\t\tmerge_base = shift_tree_object(opt->repo, head, merge_base,\n-\t\t\t\t\t       opt->subtree_shift);\n-\t}\n-\n-\tif (oideq(&merge_base->object.oid, &merge->object.oid)) {\n-\t\toutput(opt, 0, _(\"Already up to date.\"));\n-\t\t*result = head;\n-\t\treturn 1;\n-\t}\n-\n-\tcode = unpack_trees_start(opt, merge_base, head, merge);\n-\n-\tif (code != 0) {\n-\t\tif (show(opt, 4) || opt->priv->call_depth)\n-\t\t\terr(opt, _(\"merging of trees %s and %s failed\"),\n-\t\t\t    oid_to_hex(&head->object.oid),\n-\t\t\t    oid_to_hex(&merge->object.oid));\n-\t\tunpack_trees_finish(opt);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unmerged_index(istate)) {\n-\t\tstruct string_list *entries;\n-\t\tstruct rename_info re_info;\n-\t\tint i;\n-\t\t/*\n-\t\t * Only need the hashmap while processing entries, so\n-\t\t * initialize it here and free it when we are done running\n-\t\t * through the entries. Keeping it in the merge_options as\n-\t\t * opposed to decaring a local hashmap is for convenience\n-\t\t * so that we don't have to pass it to around.\n-\t\t */\n-\t\thashmap_init(&opt->priv->current_file_dir_set, path_hashmap_cmp,\n-\t\t\t     NULL, 512);\n-\t\tget_files_dirs(opt, head);\n-\t\tget_files_dirs(opt, merge);\n-\n-\t\tentries = get_unmerged(opt->repo->index);\n-\t\tclean = detect_and_process_renames(opt, merge_base, head, merge,\n-\t\t\t\t\t\t   entries, &re_info);\n-\t\trecord_df_conflict_files(opt, entries);\n-\t\tif (clean < 0)\n-\t\t\tgoto cleanup;\n-\t\tfor (i = entries->nr-1; 0 <= i; i--) {\n-\t\t\tconst char *path = entries->items[i].string;\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed) {\n-\t\t\t\tint ret = process_entry(opt, path, e);\n-\t\t\t\tif (!ret)\n-\t\t\t\t\tclean = 0;\n-\t\t\t\telse if (ret < 0) {\n-\t\t\t\t\tclean = ret;\n-\t\t\t\t\tgoto cleanup;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t\tfor (i = 0; i < entries->nr; i++) {\n-\t\t\tstruct stage_data *e = entries->items[i].util;\n-\t\t\tif (!e->processed)\n-\t\t\t\tBUG(\"unprocessed path??? %s\",\n-\t\t\t\t    entries->items[i].string);\n-\t\t}\n-\n-\tcleanup:\n-\t\tfinal_cleanup_renames(&re_info);\n-\n-\t\tstring_list_clear(entries, 1);\n-\t\tfree(entries);\n-\n-\t\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t\t\tstruct path_hashmap_entry, e);\n-\n-\t\tif (clean < 0) {\n-\t\t\tunpack_trees_finish(opt);\n-\t\t\treturn clean;\n-\t\t}\n-\t}\n-\telse\n-\t\tclean = 1;\n-\n-\tunpack_trees_finish(opt);\n-\n-\tif (opt->priv->call_depth &&\n-\t    !(*result = write_in_core_index_as_tree(opt->repo)))\n-\t\treturn -1;\n-\n-\treturn clean;\n-}\n-\n-/*\n- * Merge the commits h1 and h2, returning a flag (int) indicating the\n- * cleanness of the merge.  Also, if opt->priv->call_depth, create a\n- * virtual commit and write its location to *result.\n- */\n-static int merge_recursive_internal(struct merge_options *opt,\n-\t\t\t\t    struct commit *h1,\n-\t\t\t\t    struct commit *h2,\n-\t\t\t\t    const struct commit_list *_merge_bases,\n-\t\t\t\t    struct commit **result)\n-{\n-\tstruct commit_list *merge_bases = copy_commit_list(_merge_bases);\n-\tstruct commit_list *iter;\n-\tstruct commit *merged_merge_bases;\n-\tstruct tree *result_tree;\n-\tconst char *ancestor_name;\n-\tstruct strbuf merge_base_abbrev = STRBUF_INIT;\n-\tint ret;\n-\n-\tif (show(opt, 4)) {\n-\t\toutput(opt, 4, _(\"Merging:\"));\n-\t\toutput_commit_title(opt, h1);\n-\t\toutput_commit_title(opt, h2);\n-\t}\n-\n-\tif (!merge_bases) {\n-\t\tif (repo_get_merge_bases(the_repository, h1, h2,\n-\t\t\t\t\t &merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\tmerge_bases = reverse_commit_list(merge_bases);\n-\t}\n-\n-\tif (show(opt, 5)) {\n-\t\tunsigned cnt = commit_list_count(merge_bases);\n-\n-\t\toutput(opt, 5, Q_(\"found %u common ancestor:\",\n-\t\t\t\t\"found %u common ancestors:\", cnt), cnt);\n-\t\tfor (iter = merge_bases; iter; iter = iter->next)\n-\t\t\toutput_commit_title(opt, iter->item);\n-\t}\n-\n-\tmerged_merge_bases = pop_commit(&merge_bases);\n-\tif (!merged_merge_bases) {\n-\t\t/* if there is no common ancestor, use an empty tree */\n-\t\tstruct tree *tree;\n-\n-\t\ttree = lookup_tree(opt->repo, opt->repo->hash_algo->empty_tree);\n-\t\tmerged_merge_bases = make_virtual_commit(opt->repo, tree,\n-\t\t\t\t\t\t\t \"ancestor\");\n-\t\tancestor_name = \"empty tree\";\n-\t} else if (opt->ancestor && !opt->priv->call_depth) {\n-\t\tancestor_name = opt->ancestor;\n-\t} else if (merge_bases) {\n-\t\tancestor_name = \"merged common ancestors\";\n-\t} else {\n-\t\tstrbuf_add_unique_abbrev(&merge_base_abbrev,\n-\t\t\t\t\t &merged_merge_bases->object.oid,\n-\t\t\t\t\t DEFAULT_ABBREV);\n-\t\tancestor_name = merge_base_abbrev.buf;\n-\t}\n-\n-\tfor (iter = merge_bases; iter; iter = iter->next) {\n-\t\tconst char *saved_b1, *saved_b2;\n-\t\topt->priv->call_depth++;\n-\t\t/*\n-\t\t * When the merge fails, the result contains files\n-\t\t * with conflict markers. The cleanness flag is\n-\t\t * ignored (unless indicating an error), it was never\n-\t\t * actually used, as result of merge_trees has always\n-\t\t * overwritten it: the committed \"conflicts\" were\n-\t\t * already resolved.\n-\t\t */\n-\t\tdiscard_index(opt->repo->index);\n-\t\tsaved_b1 = opt->branch1;\n-\t\tsaved_b2 = opt->branch2;\n-\t\topt->branch1 = \"Temporary merge branch 1\";\n-\t\topt->branch2 = \"Temporary merge branch 2\";\n-\t\tif (merge_recursive_internal(opt, merged_merge_bases, iter->item,\n-\t\t\t\t\t     NULL, &merged_merge_bases) < 0) {\n-\t\t\tret = -1;\n-\t\t\tgoto out;\n-\t\t}\n-\t\topt->branch1 = saved_b1;\n-\t\topt->branch2 = saved_b2;\n-\t\topt->priv->call_depth--;\n-\n-\t\tif (!merged_merge_bases) {\n-\t\t\tret = err(opt, _(\"merge returned no commit\"));\n-\t\t\tgoto out;\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * FIXME: Since merge_recursive_internal() is only ever called by\n-\t * places that ensure the index is loaded first\n-\t * (e.g. builtin/merge.c, rebase/sequencer, etc.), in the common\n-\t * case where the merge base was unique that means when we get here\n-\t * we immediately discard the index and re-read it, which is a\n-\t * complete waste of time.  We should only be discarding and\n-\t * re-reading if we were forced to recurse.\n-\t */\n-\tdiscard_index(opt->repo->index);\n-\tif (!opt->priv->call_depth)\n-\t\trepo_read_index(opt->repo);\n-\n-\topt->ancestor = ancestor_name;\n-\tret = merge_trees_internal(opt,\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h1),\n-\t\t\t\t   repo_get_commit_tree(opt->repo, h2),\n-\t\t\t\t   repo_get_commit_tree(opt->repo,\n-\t\t\t\t\t\t\tmerged_merge_bases),\n-\t\t\t\t   &result_tree);\n-\topt->ancestor = NULL;  /* avoid accidental re-use of opt->ancestor */\n-\tif (ret < 0) {\n-\t\tflush_output(opt);\n-\t\tgoto out;\n-\t}\n-\n-\tif (opt->priv->call_depth) {\n-\t\t*result = make_virtual_commit(opt->repo, result_tree,\n-\t\t\t\t\t      \"merged tree\");\n-\t\tcommit_list_insert(h1, &(*result)->parents);\n-\t\tcommit_list_insert(h2, &(*result)->parents->next);\n-\t}\n-\n-out:\n-\tstrbuf_release(&merge_base_abbrev);\n-\tfree_commit_list(merge_bases);\n-\treturn ret;\n-}\n-\n-static int merge_start(struct merge_options *opt, struct tree *head)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t/* Sanity checks on opt */\n-\tassert(opt->repo);\n-\n-\tassert(opt->branch1 && opt->branch2);\n-\n-\tassert(opt->detect_renames >= -1 &&\n-\t       opt->detect_renames <= DIFF_DETECT_COPY);\n-\tassert(opt->detect_directory_renames >= MERGE_DIRECTORY_RENAMES_NONE &&\n-\t       opt->detect_directory_renames <= MERGE_DIRECTORY_RENAMES_TRUE);\n-\tassert(opt->rename_limit >= -1);\n-\tassert(opt->rename_score >= 0 && opt->rename_score <= MAX_SCORE);\n-\tassert(opt->show_rename_progress >= 0 && opt->show_rename_progress <= 1);\n-\n-\tassert(opt->xdl_opts >= 0);\n-\tassert(opt->recursive_variant >= MERGE_VARIANT_NORMAL &&\n-\t       opt->recursive_variant <= MERGE_VARIANT_THEIRS);\n-\n-\tassert(opt->verbosity >= 0 && opt->verbosity <= 5);\n-\tassert(opt->buffer_output <= 2);\n-\tassert(opt->obuf.len == 0);\n-\n-\tassert(opt->priv == NULL);\n-\n-\t/* Not supported; option specific to merge-ort */\n-\tassert(!opt->record_conflict_msgs_as_headers);\n-\tassert(!opt->msg_header_prefix);\n-\n-\t/* Sanity check on repo state; index must match head */\n-\tif (repo_index_has_changes(opt->repo, head, &sb)) {\n-\t\terr(opt, _(\"Your local changes to the following files would be overwritten by merge:\\n  %s\"),\n-\t\t    sb.buf);\n-\t\tstrbuf_release(&sb);\n-\t\treturn -1;\n-\t}\n-\n-\tCALLOC_ARRAY(opt->priv, 1);\n-\tstring_list_init_dup(&opt->priv->df_conflict_file_set);\n-\treturn 0;\n-}\n-\n-static void merge_finalize(struct merge_options *opt)\n-{\n-\tflush_output(opt);\n-\tif (!opt->priv->call_depth && opt->buffer_output < 2)\n-\t\tstrbuf_release(&opt->obuf);\n-\tif (show(opt, 2))\n-\t\tdiff_warn_rename_limit(\"merge.renamelimit\",\n-\t\t\t\t       opt->priv->needed_rename_limit, 0);\n-\thashmap_clear_and_free(&opt->priv->current_file_dir_set,\n-\t\t\t       struct path_hashmap_entry, e);\n-\tstring_list_clear(&opt->priv->df_conflict_file_set, 0);\n-\tFREE_AND_NULL(opt->priv);\n-}\n-\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base)\n-{\n-\tint clean;\n-\tstruct tree *ignored;\n-\n-\tassert(opt->ancestor != NULL);\n-\n-\tif (merge_start(opt, head))\n-\t\treturn -1;\n-\tclean = merge_trees_internal(opt, head, merge, merge_base, &ignored);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result)\n-{\n-\tint clean;\n-\n-\tassert(opt->ancestor == NULL ||\n-\t       !strcmp(opt->ancestor, \"constructed merge base\"));\n-\n-\tprepare_repo_settings(opt->repo);\n-\topt->repo->settings.command_requires_full_index = 1;\n-\n-\tif (merge_start(opt, repo_get_commit_tree(opt->repo, h1)))\n-\t\treturn -1;\n-\tclean = merge_recursive_internal(opt, h1, h2, merge_bases, result);\n-\tmerge_finalize(opt);\n-\n-\treturn clean;\n-}\n-\n-static struct commit *get_ref(struct repository *repo,\n-\t\t\t      const struct object_id *oid,\n-\t\t\t      const char *name)\n-{\n-\tstruct object *object;\n-\n-\tobject = deref_tag(repo, parse_object(repo, oid),\n-\t\t\t   name, strlen(name));\n-\tif (!object)\n-\t\treturn NULL;\n-\tif (object->type == OBJ_TREE)\n-\t\treturn make_virtual_commit(repo, (struct tree*)object, name);\n-\tif (object->type != OBJ_COMMIT)\n-\t\treturn NULL;\n-\tif (repo_parse_commit(repo, (struct commit *)object))\n-\t\treturn NULL;\n-\treturn (struct commit *)object;\n-}\n-\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result)\n-{\n-\tint clean;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct commit *head_commit = get_ref(opt->repo, head, opt->branch1);\n-\tstruct commit *next_commit = get_ref(opt->repo, merge, opt->branch2);\n-\tstruct commit_list *ca = NULL;\n-\n-\tif (merge_bases) {\n-\t\tint i;\n-\t\tfor (i = 0; i < num_merge_bases; ++i) {\n-\t\t\tstruct commit *base;\n-\t\t\tif (!(base = get_ref(opt->repo, &merge_bases[i],\n-\t\t\t\t\t     oid_to_hex(&merge_bases[i]))))\n-\t\t\t\treturn err(opt, _(\"Could not parse object '%s'\"),\n-\t\t\t\t\t   oid_to_hex(&merge_bases[i]));\n-\t\t\tcommit_list_insert(base, &ca);\n-\t\t}\n-\t\tif (num_merge_bases == 1)\n-\t\t\topt->ancestor = \"constructed merge base\";\n-\t}\n-\n-\trepo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);\n-\tclean = merge_recursive(opt, head_commit, next_commit, ca,\n-\t\t\t\tresult);\n-\tfree_commit_list(ca);\n-\tif (clean < 0) {\n-\t\trollback_lock_file(&lock);\n-\t\treturn clean;\n-\t}\n-\n-\tif (write_locked_index(opt->repo->index, &lock,\n-\t\t\t       COMMIT_LOCK | SKIP_IF_UNCHANGED))\n-\t\treturn err(opt, _(\"Unable to write index.\"));\n-\n-\treturn clean ? 0 : 1;\n-}\n-\n-static void merge_recursive_config(struct merge_options *opt, int ui)\n-{\n-\tchar *value = NULL;\n-\tint renormalize = 0;\n-\tgit_config_get_int(\"merge.verbosity\", &opt->verbosity);\n-\tgit_config_get_int(\"diff.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_int(\"merge.renamelimit\", &opt->rename_limit);\n-\tgit_config_get_bool(\"merge.renormalize\", &renormalize);\n-\topt->renormalize = renormalize;\n-\tif (!git_config_get_string(\"diff.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"diff.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.renames\", &value)) {\n-\t\topt->detect_renames = git_config_rename(\"merge.renames\", value);\n-\t\tfree(value);\n-\t}\n-\tif (!git_config_get_string(\"merge.directoryrenames\", &value)) {\n-\t\tint boolval = git_parse_maybe_bool(value);\n-\t\tif (0 <= boolval) {\n-\t\t\topt->detect_directory_renames = boolval ?\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_TRUE :\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_NONE;\n-\t\t} else if (!strcasecmp(value, \"conflict\")) {\n-\t\t\topt->detect_directory_renames =\n-\t\t\t\tMERGE_DIRECTORY_RENAMES_CONFLICT;\n-\t\t} /* avoid erroring on values from future versions of git */\n-\t\tfree(value);\n-\t}\n-\tif (ui) {\n-\t\tif (!git_config_get_string(\"diff.algorithm\", &value)) {\n-\t\t\tlong diff_algorithm = parse_algorithm_value(value);\n-\t\t\tif (diff_algorithm < 0)\n-\t\t\t\tdie(_(\"unknown value for config '%s': %s\"), \"diff.algorithm\", value);\n-\t\t\topt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;\n-\t\t\tfree(value);\n-\t\t}\n-\t}\n-\tgit_config(git_xmerge_config, NULL);\n-}\n-\n-static void init_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo, int ui)\n-{\n-\tconst char *merge_verbosity;\n-\tmemset(opt, 0, sizeof(struct merge_options));\n-\n-\topt->repo = repo;\n-\n-\topt->detect_renames = -1;\n-\topt->detect_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;\n-\topt->rename_limit = -1;\n-\n-\topt->verbosity = 2;\n-\topt->buffer_output = 1;\n-\tstrbuf_init(&opt->obuf, 0);\n-\n-\topt->renormalize = 0;\n-\n-\topt->conflict_style = -1;\n-\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\n-\tmerge_recursive_config(opt, ui);\n-\tmerge_verbosity = getenv(\"GIT_MERGE_VERBOSITY\");\n-\tif (merge_verbosity)\n-\t\topt->verbosity = strtol(merge_verbosity, NULL, 10);\n-\tif (opt->verbosity >= 5)\n-\t\topt->buffer_output = 0;\n-}\n-\n-void init_ui_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 1);\n-}\n-\n-void init_basic_merge_options(struct merge_options *opt,\n-\t\t\tstruct repository *repo)\n-{\n-\tinit_merge_options(opt, repo, 0);\n-}\n-\n-/*\n- * For now, members of merge_options do not need deep copying, but\n- * it may change in the future, in which case we would need to update\n- * this, and also make a matching change to clear_merge_options() to\n- * release the resources held by a copied instance.\n- */\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src)\n-{\n-\t*dst = *src;\n-}\n-\n-void clear_merge_options(struct merge_options *opt UNUSED)\n-{\n-\t; /* no-op as our copy is shallow right now */\n-}\n-\n-int parse_merge_opt(struct merge_options *opt, const char *s)\n-{\n-\tconst char *arg;\n-\n-\tif (!s || !*s)\n-\t\treturn -1;\n-\tif (!strcmp(s, \"ours\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_OURS;\n-\telse if (!strcmp(s, \"theirs\"))\n-\t\topt->recursive_variant = MERGE_VARIANT_THEIRS;\n-\telse if (!strcmp(s, \"subtree\"))\n-\t\topt->subtree_shift = \"\";\n-\telse if (skip_prefix(s, \"subtree=\", &arg))\n-\t\topt->subtree_shift = arg;\n-\telse if (!strcmp(s, \"patience\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, PATIENCE_DIFF);\n-\telse if (!strcmp(s, \"histogram\"))\n-\t\topt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);\n-\telse if (skip_prefix(s, \"diff-algorithm=\", &arg)) {\n-\t\tlong value = parse_algorithm_value(arg);\n-\t\tif (value < 0)\n-\t\t\treturn -1;\n-\t\t/* clear out previous settings */\n-\t\tDIFF_XDL_CLR(opt, NEED_MINIMAL);\n-\t\topt->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;\n-\t\topt->xdl_opts |= value;\n-\t}\n-\telse if (!strcmp(s, \"ignore-space-change\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_CHANGE);\n-\telse if (!strcmp(s, \"ignore-all-space\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE);\n-\telse if (!strcmp(s, \"ignore-space-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_WHITESPACE_AT_EOL);\n-\telse if (!strcmp(s, \"ignore-cr-at-eol\"))\n-\t\tDIFF_XDL_SET(opt, IGNORE_CR_AT_EOL);\n-\telse if (!strcmp(s, \"renormalize\"))\n-\t\topt->renormalize = 1;\n-\telse if (!strcmp(s, \"no-renormalize\"))\n-\t\topt->renormalize = 0;\n-\telse if (!strcmp(s, \"no-renames\"))\n-\t\topt->detect_renames = 0;\n-\telse if (!strcmp(s, \"find-renames\")) {\n-\t\topt->detect_renames = 1;\n-\t\topt->rename_score = 0;\n-\t}\n-\telse if (skip_prefix(s, \"find-renames=\", &arg) ||\n-\t\t skip_prefix(s, \"rename-threshold=\", &arg)) {\n-\t\tif ((opt->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)\n-\t\t\treturn -1;\n-\t\topt->detect_renames = 1;\n-\t}\n-\t/*\n-\t * Please update $__git_merge_strategy_options in\n-\t * git-completion.bash when you add new options\n-\t */\n-\telse\n-\t\treturn -1;\n-\treturn 0;\n-}\ndiff --git a/merge-recursive.h b/merge-recursive.h\ndeleted file mode 100644\nindex 0b91f28f902..00000000000\n--- a/merge-recursive.h\n+++ /dev/null\n@@ -1,132 +0,0 @@\n-#ifndef MERGE_RECURSIVE_H\n-#define MERGE_RECURSIVE_H\n-\n-#include \"strbuf.h\"\n-\n-struct commit;\n-struct commit_list;\n-struct object_id;\n-struct repository;\n-struct tree;\n-\n-struct merge_options_internal;\n-struct merge_options {\n-\tstruct repository *repo;\n-\n-\t/* ref names used in console messages and conflict markers */\n-\tconst char *ancestor;\n-\tconst char *branch1;\n-\tconst char *branch2;\n-\n-\t/* rename related options */\n-\tint detect_renames;\n-\tenum {\n-\t\tMERGE_DIRECTORY_RENAMES_NONE = 0,\n-\t\tMERGE_DIRECTORY_RENAMES_CONFLICT = 1,\n-\t\tMERGE_DIRECTORY_RENAMES_TRUE = 2\n-\t} detect_directory_renames;\n-\tint rename_limit;\n-\tint rename_score;\n-\tint show_rename_progress;\n-\n-\t/* xdiff-related options (patience, ignore whitespace, ours/theirs) */\n-\tlong xdl_opts;\n-\tint conflict_style;\n-\tenum {\n-\t\tMERGE_VARIANT_NORMAL = 0,\n-\t\tMERGE_VARIANT_OURS,\n-\t\tMERGE_VARIANT_THEIRS\n-\t} recursive_variant;\n-\n-\t/* console output related options */\n-\tint verbosity;\n-\tunsigned buffer_output; /* 1: output at end, 2: keep buffered */\n-\tstruct strbuf obuf;     /* output buffer; if buffer_output == 2, caller\n-\t\t\t\t * must handle and call strbuf_release */\n-\n-\t/* miscellaneous control options */\n-\tconst char *subtree_shift;\n-\tunsigned renormalize : 1;\n-\tunsigned record_conflict_msgs_as_headers : 1;\n-\tconst char *msg_header_prefix;\n-\n-\t/* internal fields used by the implementation */\n-\tstruct merge_options_internal *priv;\n-};\n-\n-/* for use by porcelain commands */\n-void init_ui_merge_options(struct merge_options *opt, struct repository *repo);\n-/* for use by plumbing commands */\n-void init_basic_merge_options(struct merge_options *opt, struct repository *repo);\n-\n-void copy_merge_options(struct merge_options *dst, struct merge_options *src);\n-void clear_merge_options(struct merge_options *opt);\n-\n-/* parse the option in s and update the relevant field of opt */\n-int parse_merge_opt(struct merge_options *opt, const char *s);\n-\n-/*\n- * RETURN VALUES: All the merge_* functions below return a value as follows:\n- *   > 0     Merge was clean\n- *   = 0     Merge had conflicts\n- *   < 0     Merge hit an unexpected and unrecoverable problem (e.g. disk\n- *             full) and aborted merge part-way through.\n- */\n-\n-/*\n- * rename-detecting three-way merge, no recursion.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_trees(struct merge_options *opt,\n-\t\tstruct tree *head,\n-\t\tstruct tree *merge,\n-\t\tstruct tree *merge_base);\n-\n-/*\n- * merge_recursive is like merge_trees() but with recursive ancestor\n- * consolidation.\n- *\n- * NOTE: empirically, about a decade ago it was determined that with more\n- *       than two merge bases, optimal behavior was found when the\n- *       merge_bases were passed in the order of oldest commit to newest\n- *       commit.  Also, merge_bases will be consumed (emptied) so make a\n- *       copy if you need it.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index NOT written to disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive(struct merge_options *opt,\n-\t\t    struct commit *h1,\n-\t\t    struct commit *h2,\n-\t\t    const struct commit_list *merge_bases,\n-\t\t    struct commit **result);\n-\n-/*\n- * merge_recursive_generic can operate on trees instead of commits, by\n- * wrapping the trees into virtual commits, and calling merge_recursive().\n- * It also writes out the in-memory index to disk if the merge is successful.\n- *\n- * Outputs:\n- *   - See RETURN VALUES above\n- *   - *result is treated as scratch space for temporary recursive merges\n- *   - opt->repo->index has the new index\n- *   - new index also written to $GIT_INDEX_FILE on disk\n- *   - The working tree is updated with results of the merge\n- */\n-int merge_recursive_generic(struct merge_options *opt,\n-\t\t\t    const struct object_id *head,\n-\t\t\t    const struct object_id *merge,\n-\t\t\t    int num_merge_bases,\n-\t\t\t    const struct object_id *merge_bases,\n-\t\t\t    struct commit **result);\n-\n-#endif\ndiff --git a/meson.build b/meson.build\nindex e98cfa4909f..8448df9d15e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -338,7 +338,6 @@ libgit_sources = [\n   'merge-ll.c',\n   'merge-ort.c',\n   'merge-ort-wrappers.c',\n-  'merge-recursive.c',\n   'merge.c',\n   'midx.c',\n   'midx-write.c',\n-- \ngitgitgadget\n\n"}]}