{"thread":{"id":"65010","subject":"[PATCH v2 3/3] contrib/subtree: process out-of-prefix subtrees","startedAt":"2026-02-18T02:32:03Z","lastAt":"2026-02-18T02:32:07Z","messageCount":4,"participants":["Colin Stagner"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"536239","messageId":"20260217-cs-subtree-remove-optimization-v2-3-4299e71a30c6@howdoi.land","threadId":"65010","inReplyTo":"20260217-cs-subtree-remove-optimization-v2-0-4299e71a30c6@howdoi.land","subject":"[PATCH v2 3/3] contrib/subtree: process out-of-prefix subtrees","fromName":"Colin Stagner","fromEmail":"ask+git@howdoi.land","sentAt":"2026-02-18T02:31:32Z","receivedAt":"2026-02-18T02:32:03Z","isPatch":true,"sender":{"key":"ask+git@howdoi.land","avatar":null},"body":"`should_ignore_subtree_split_commit` detects subtrees which are\noutside of the current path --prefix and ignores them. This can\nspeed up splits of repositories that have many subtrees.\n\nSince its inception [1], every iteration of this logic [2], [3]\nincorrectly excludes commits. This alters the split history. The\nsplit history and its commit hashes are API contract, so this is\nnot permissible.\n\nWhile a commit from a different subtree may look like it doesn't\ncontribute anything to a split, sometimes it does. Merge commits\nare a particular hot spot. For these, the pruning logic in\n`copy_or_skip` performs:\n\n1. a check for \"treesame\" parents\n2. two different common ancestry checks\n\nThese checks operate on the **split history**, not the input\nhistory. The split history omits commits that do not affect the\n--prefix. This can significantly alter the ancestry of a merge.\nIn order to determine if `copy_or_skip` will skip a merge, it\nis likely necessary to compute all the split history... which\nis what `should_ignore_subtree_split_commit` tries to avoid.\n\nTo make this logic API-preserving, we could gate it behind a\nnew CLI argument. The present implementation is actually a\nspeed penalty in many cases, however, so this is not done here.\n\nRemove the `should_ignore_subtree_split_commit` logic. This\nfixes the regression reported in [4].\n\n[1]: 98ba49ccc2 (subtree: fix split processing with multiple subtrees present, 2023-12-01)\n\n[2]: 83f9dad7d6 (contrib/subtree: fix split with squashed subtrees, 2025-09-09)\n\n[3]: 28a7e27cff (contrib/subtree: detect rewritten subtree commits, 2026-01-09)\n\n[4]: <20251230170719.845029-1-george@mail.dietrich.pub>\n\nReported-by: George <george@mail.dietrich.pub>\nReported-by: Christian Heusel <christian@heusel.eu>\nSigned-off-by: Colin Stagner <ask+git@howdoi.land>\n---\n contrib/subtree/git-subtree.sh     | 50 +---------------------------\n contrib/subtree/t/t7900-subtree.sh | 68 +++++++++++++++++++++++++++++++++++---\n 2 files changed, 65 insertions(+), 53 deletions(-)\n\ndiff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh\nindex 17106d1a72..ba9fb2ee5d 100755\n--- a/contrib/subtree/git-subtree.sh\n+++ b/contrib/subtree/git-subtree.sh\n@@ -785,42 +785,6 @@ ensure_valid_ref_format () {\n \t\tdie \"fatal: '$1' does not look like a ref\"\n }\n \n-# Usage: should_ignore_subtree_split_commit REV\n-#\n-# Check if REV is a commit from another subtree and should be\n-# ignored from processing for splits\n-should_ignore_subtree_split_commit () {\n-\tassert test $# = 1\n-\n-\tgit show \\\n-\t\t--no-patch \\\n-\t\t--no-show-signature \\\n-\t\t--format='%(trailers:key=git-subtree-dir,key=git-subtree-mainline)' \\\n-\t\t\"$1\" |\n-\t(\n-\thave_mainline=\n-\tsubtree_dir=\n-\n-\twhile read -r trailer val\n-\tdo\n-\t\tcase \"$trailer\" in\n-\t\tgit-subtree-dir:)\n-\t\t\tsubtree_dir=\"${val%/}\" ;;\n-\t\tgit-subtree-mainline:)\n-\t\t\thave_mainline=y ;;\n-\t\tesac\n-\tdone\n-\n-\tif test -n \"${subtree_dir}\" &&\n-\t\ttest -z \"${have_mainline}\" &&\n-\t\ttest \"${subtree_dir}\" != \"$arg_prefix\"\n-\tthen\n-\t\treturn 0\n-\tfi\n-\treturn 1\n-\t)\n-}\n-\n # Usage: process_split_commit REV PARENTS\n process_split_commit () {\n \tassert test $# = 2\n@@ -1006,19 +970,7 @@ cmd_split () {\n \teval \"$grl\" |\n \twhile read rev parents\n \tdo\n-\t\tif should_ignore_subtree_split_commit \"$rev\"\n-\t\tthen\n-\t\t\tcontinue\n-\t\tfi\n-\t\tparsedparents=''\n-\t\tfor parent in $parents\n-\t\tdo\n-\t\t\tif ! should_ignore_subtree_split_commit \"$parent\"\n-\t\t\tthen\n-\t\t\t\tparsedparents=\"$parsedparents$parent \"\n-\t\t\tfi\n-\t\tdone\n-\t\tprocess_split_commit \"$rev\" \"$parsedparents\"\n+\t\tprocess_split_commit \"$rev\" \"$parents\"\n \tdone || exit $?\n \n \tlatest_new=$(cache_get latest_new) || exit $?\ndiff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh\nindex dad8dea63a..05a774ad47 100755\n--- a/contrib/subtree/t/t7900-subtree.sh\n+++ b/contrib/subtree/t/t7900-subtree.sh\n@@ -428,8 +428,7 @@ test_expect_success 'split sub dir/ with --rejoin' '\n # \t- Perform 'split' on subtree B\n # \t- Create new commits with changes to subtree A and B\n # \t- Perform split on subtree A\n-# \t- Check that the commits in subtree B are not processed\n-#\t\t\tas part of the subtree A split\n+# \t- Check for expected history\n test_expect_success 'split with multiple subtrees' '\n \tsubtree_test_create_repo \"$test_count\" &&\n \tsubtree_test_create_repo \"$test_count/subA\" &&\n@@ -458,8 +457,8 @@ test_expect_success 'split with multiple subtrees' '\n \t\t--squash --rejoin -m \"Sub A Split 2\" -b a2 &&\n \ttest \"$(git -C \"$test_count\" rev-list --count main..a2)\" -eq 2 &&\n \ttest \"$(git -C \"$test_count\" rev-list --count a1..a2)\" -eq 1 &&\n-\ttest \"$(git -C \"$test_count\" subtree split --prefix=subBDir \\\n-\t\t--squash --rejoin -d -m \"Sub B Split 1\" -b b2 2>&1 | grep -w \"\\[1\\]\")\" = \"\" &&\n+\tgit -C \"$test_count\" subtree split --prefix=subBDir \\\n+\t\t--squash --rejoin -d -m \"Sub B Split 1\" -b b2 &&\n \ttest \"$(git -C \"$test_count\" rev-list --count main..b2)\" -eq 2 &&\n \ttest \"$(git -C \"$test_count\" rev-list --count b1..b2)\" -eq 1\n '\n@@ -507,6 +506,67 @@ do\n \t'\n done\n \n+# Usually,\n+#\n+#    git subtree merge -P subA --squash f00...\n+#\n+# makes two commits, in this order:\n+#\n+# 1. Squashed 'subA/' content from commit f00...\n+# 2. Merge commit (1) as 'subA'\n+#\n+# Commit 1 updates the subtree but does *not* rewrite paths.\n+# Commit 2 rewrites all trees to start with `subA/`\n+#\n+# Commit 1 either has no parents or depends only on other\n+# \"Squashed 'subA/' content\" commits.\n+#\n+# For merge without --squash, subtree produces just one commit:\n+# a merge commit with git-subtree trailers.\n+#\n+# In either case, if the user rebases these commits, they will\n+# still have the git-subtree-* trailers… but will NOT have\n+# the layout described above.\n+#\n+# Test that subsequent `git subtree split` are not confused by this.\n+test_expect_success 'split with rebased subtree commit' '\n+\tsubtree_test_create_repo \"$test_count\" &&\n+\t(\n+\t\tcd \"$test_count\" &&\n+\t\ttest_commit file0 &&\n+\t\ttest_create_subtree_add \\\n+\t\t\t. mksubtree subA file1 --squash &&\n+\t\ttest_path_is_file subA/file1.t &&\n+\t\tmkdir subB &&\n+\t\ttest_commit subB/bfile &&\n+\t\tgit commit --amend -F - <<'EOF' &&\n+Squashed '\\''subB/'\\'' content from commit '\\''badf00da911bbe895347b4b236f5461d55dc9877'\\''\n+\n+Simulate a cherry-picked or rebased subtree commit.\n+\n+git-subtree-dir: subB\n+git-subtree-split: badf00da911bbe895347b4b236f5461d55dc9877\n+EOF\n+\t\ttest_commit subA/file2 &&\n+\t\ttest_commit subB/bfile2 &&\n+\t\tgit commit --amend -F - <<'EOF' &&\n+Split '\\''subB/'\\'' into commit '\\''badf00da911bbe895347b4b236f5461d55dc9877'\\''\n+\n+Simulate a cherry-picked or rebased subtree commit.\n+\n+git-subtree-dir: subB\n+git-subtree-mainline: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n+git-subtree-split: badf00da911bbe895347b4b236f5461d55dc9877\n+EOF\n+\t\tgit subtree split --prefix=subA --branch=bsplit &&\n+\t\tgit checkout bsplit &&\n+\t\ttest_path_is_file file1.t &&\n+\t\ttest_path_is_file file2.t &&\n+\t\ttest \"$(last_commit_subject)\" = \"subA/file2\" &&\n+\t\ttest \"$(git rev-list --count bsplit)\" -eq 2\n+\t)\n+'\n+\n test_expect_success 'split sub dir/ with --rejoin from scratch' '\n \tsubtree_test_create_repo \"$test_count\" &&\n \ttest_create_commit \"$test_count\" main1 &&\n\n-- \n2.43.0\n\n"},{"id":"536240","messageId":"20260217-cs-subtree-remove-optimization-v2-2-4299e71a30c6@howdoi.land","threadId":"65010","inReplyTo":"20260217-cs-subtree-remove-optimization-v2-0-4299e71a30c6@howdoi.land","subject":"[PATCH v2 2/3] contrib/subtree: test history depth","fromName":"Colin Stagner","fromEmail":"ask+git@howdoi.land","sentAt":"2026-02-18T02:31:31Z","receivedAt":"2026-02-18T02:32:04Z","isPatch":true,"sender":{"key":"ask+git@howdoi.land","avatar":null},"body":"Add history depth checks to some of the subtree unit tests.\n\nThese checks were previously introduced as part of 28a7e27cff\n(contrib/subtree: detect rewritten subtree commits, 2026-01-09),\nwhich has since been reverted.\n\nSigned-off-by: Colin Stagner <ask+git@howdoi.land>\n---\n contrib/subtree/t/t7900-subtree.sh | 22 ++++++++++++++++------\n 1 file changed, 16 insertions(+), 6 deletions(-)\n\ndiff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh\nindex 3ee2f95d86..dad8dea63a 100755\n--- a/contrib/subtree/t/t7900-subtree.sh\n+++ b/contrib/subtree/t/t7900-subtree.sh\n@@ -411,8 +411,9 @@ test_expect_success 'split sub dir/ with --rejoin' '\n \t\tgit fetch ./\"sub proj\" HEAD &&\n \t\tgit subtree merge --prefix=\"sub dir\" FETCH_HEAD &&\n \t\tsplit_hash=$(git subtree split --prefix=\"sub dir\" --annotate=\"*\") &&\n-\t\tgit subtree split --prefix=\"sub dir\" --annotate=\"*\" --rejoin &&\n-\t\ttest \"$(last_commit_subject)\" = \"Split '\\''sub dir/'\\'' into commit '\\''$split_hash'\\''\"\n+\t\tgit subtree split --prefix=\"sub dir\" --annotate=\"*\" -b spl --rejoin &&\n+\t\ttest \"$(last_commit_subject)\" = \"Split '\\''sub dir/'\\'' into commit '\\''$split_hash'\\''\" &&\n+\t\ttest \"$(git rev-list --count spl)\" -eq 5\n \t)\n '\n \n@@ -442,18 +443,25 @@ test_expect_success 'split with multiple subtrees' '\n \tgit -C \"$test_count\" subtree add --prefix=subADir FETCH_HEAD &&\n \tgit -C \"$test_count\" fetch ./subB HEAD &&\n \tgit -C \"$test_count\" subtree add --prefix=subBDir FETCH_HEAD &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count main)\" -eq 7 &&\n \ttest_create_commit \"$test_count\" subADir/main-subA1 &&\n \ttest_create_commit \"$test_count\" subBDir/main-subB1 &&\n \tgit -C \"$test_count\" subtree split --prefix=subADir \\\n-\t\t--squash --rejoin -m \"Sub A Split 1\" &&\n+\t\t--squash --rejoin -m \"Sub A Split 1\" -b a1 &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count main..a1)\" -eq 1 &&\n \tgit -C \"$test_count\" subtree split --prefix=subBDir \\\n-\t\t--squash --rejoin -m \"Sub B Split 1\" &&\n+\t\t--squash --rejoin -m \"Sub B Split 1\" -b b1 &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count main..b1)\" -eq 1 &&\n \ttest_create_commit \"$test_count\" subADir/main-subA2 &&\n \ttest_create_commit \"$test_count\" subBDir/main-subB2 &&\n \tgit -C \"$test_count\" subtree split --prefix=subADir \\\n-\t\t--squash --rejoin -m \"Sub A Split 2\" &&\n+\t\t--squash --rejoin -m \"Sub A Split 2\" -b a2 &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count main..a2)\" -eq 2 &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count a1..a2)\" -eq 1 &&\n \ttest \"$(git -C \"$test_count\" subtree split --prefix=subBDir \\\n-\t\t--squash --rejoin -d -m \"Sub B Split 1\" 2>&1 | grep -w \"\\[1\\]\")\" = \"\"\n+\t\t--squash --rejoin -d -m \"Sub B Split 1\" -b b2 2>&1 | grep -w \"\\[1\\]\")\" = \"\" &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count main..b2)\" -eq 2 &&\n+\ttest \"$(git -C \"$test_count\" rev-list --count b1..b2)\" -eq 1\n '\n \n # When subtree split-ing a directory that has other subtree\n@@ -477,6 +485,7 @@ do\n \t\t\ttest_path_is_file subA/file1.t &&\n \t\t\ttest_path_is_file subA/subB/file2.t &&\n \t\t\tgit subtree split --prefix=subA --branch=bsplit &&\n+\t\t\ttest \"$(git rev-list --count bsplit)\" -eq 2 &&\n \t\t\tgit checkout bsplit &&\n \t\t\ttest_path_is_file file1.t &&\n \t\t\ttest_path_is_file subB/file2.t &&\n@@ -489,6 +498,7 @@ do\n \t\t\t\t--prefix=subA/subB mksubtree &&\n \t\t\ttest_path_is_file subA/subB/file3.t &&\n \t\t\tgit subtree split --prefix=subA --branch=bsplit &&\n+\t\t\ttest \"$(git rev-list --count bsplit)\" -eq 3 &&\n \t\t\tgit checkout bsplit &&\n \t\t\ttest_path_is_file file1.t &&\n \t\t\ttest_path_is_file subB/file2.t &&\n\n-- \n2.43.0\n\n"},{"id":"536241","messageId":"20260217-cs-subtree-remove-optimization-v2-0-4299e71a30c6@howdoi.land","threadId":"65010","inReplyTo":"20260215201906.889951-1-ask+git@howdoi.land","subject":"[PATCH v2 0/3] contrib/subtree: process out-of-prefix subtrees","fromName":"Colin Stagner","fromEmail":"ask+git@howdoi.land","sentAt":"2026-02-18T02:31:29Z","receivedAt":"2026-02-18T02:32:06Z","isPatch":true,"sender":{"key":"ask+git@howdoi.land","avatar":null},"body":"* cs/subtree-remove-optimization:\n  Remove an optimization that can exclude too much\n  history during a \"subtree split.\"\n\nRemove an optimization introduced in 98ba49ccc2 (subtree: fix split\nprocessing with multiple subtrees present, 2023-12-01). The\noptimization incorrectly excludes commits from the split history\nthat must be included.\n\nThe above commit, and my later attempt to fix it in 83f9dad7d6\n(contrib/subtree: fix split with squashed subtrees, 2025-09-09),\nboth introduce known regressions.\n\nImprove test coverage for `copy_or_skip`, which will help detect\nfuture regressions.\n\nSigned-off-by: Colin Stagner <ask+git@howdoi.land>\n---\nChanges in v2:\n- remove incorrect newlines from commit message trailers\n- patch diffs are unchanged\n\n---\nColin Stagner (3):\n      contrib/subtree: capture additional test-cases\n      contrib/subtree: test history depth\n      contrib/subtree: process out-of-prefix subtrees\n\n contrib/subtree/git-subtree.sh     |  50 +---------\n contrib/subtree/t/t7900-subtree.sh | 198 +++++++++++++++++++++++++++++++++++--\n 2 files changed, 190 insertions(+), 58 deletions(-)\n---\nbase-commit: 852829b3dd2fe4e7c7fc4d8badde644cf1b66c74\nchange-id: 20260217-cs-subtree-remove-optimization-aca442f748eb\n\nBest regards,\n--  \nColin Stagner <ask+git@howdoi.land>\n\n"},{"id":"536242","messageId":"20260217-cs-subtree-remove-optimization-v2-1-4299e71a30c6@howdoi.land","threadId":"65010","inReplyTo":"20260217-cs-subtree-remove-optimization-v2-0-4299e71a30c6@howdoi.land","subject":"[PATCH v2 1/3] contrib/subtree: capture additional test-cases","fromName":"Colin Stagner","fromEmail":"ask+git@howdoi.land","sentAt":"2026-02-18T02:31:30Z","receivedAt":"2026-02-18T02:32:07Z","isPatch":true,"sender":{"key":"ask+git@howdoi.land","avatar":null},"body":"Patch series e7b07376e5 (Merge branch 'rs/subtree-fixes',\n2018-10-26) corrects several defects in `git subtree split`.\nThe defects affect `split --rejoin` and merge commit processing.\n\nThere is no test coverage for this, and e7b07376e5 did not\nintroduce any.\n\nConvert the minimum working example [1] from the original patch\nsubmission [2] into test cases.\n\n[1]: https://gist.github.com/FoxFireX/1b794384612b7fd5e7cd157cff96269e\n\n[2]: <20180928183540.48968-1-roger.strain@swri.org>\n\nSigned-off-by: Colin Stagner <ask+git@howdoi.land>\n---\n contrib/subtree/t/t7900-subtree.sh | 110 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 110 insertions(+)\n\ndiff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh\nindex e7040718f2..3ee2f95d86 100755\n--- a/contrib/subtree/t/t7900-subtree.sh\n+++ b/contrib/subtree/t/t7900-subtree.sh\n@@ -1575,6 +1575,116 @@ test_expect_success 'push split to subproj' '\n \t)\n '\n \n+# --ignore-joins must ignore mainline content outside of the\n+# subtree. This test verifies that the logic in\n+# `find_existing_splits()` correctly handles a `git subtree add`\n+# In this test, the split history must not contain a commit titled\n+#\n+#     Add 'sub/' from commit ...\n+#\n+# see: dd21d43b58 (subtree: make --ignore-joins pay\n+#      attention to adds, 2018-09-28)\n+test_expect_success 'split --ignore-joins respects subtree add' '\n+\tsubtree_test_create_repo \"$test_count\" &&\n+\t(\n+\t\tcd \"$test_count\" &&\n+\t\ttest_commit main_must_not_be_in_subtree &&\n+\t\ttest_create_subtree_add . mksubtree sub sub1 &&\n+\t\ttest_commit sub/sub2 &&\n+\t\ttest_commit main_must_not_be_in_subtree2 &&\n+\t\tgit subtree split --prefix sub -b first_split --rejoin &&\n+\t\ttest_commit sub/sub3 &&\n+\t\tno_ignore_joins=\"$(git subtree split --prefix sub -b no_ignore_joins)\" &&\n+\t\tignore_joins=\"$(git subtree split --prefix sub --ignore-joins -b ignore_joins)\" &&\n+\t\tgit checkout ignore_joins &&\n+\t\ttest_path_is_file sub1.t &&\n+\t\ttest_path_is_file sub2.t &&\n+\t\ttest_path_is_file sub3.t &&\n+\t\t! test_path_is_file main_must_not_be_in_subtree.t &&\n+\t\t! test_path_is_file main_must_not_be_in_subtree2.t &&\n+\t\ttest -z \"$(git log -1 --grep \"Add '''sub/''' from commit\" ignore_joins)\" &&\n+\t\ttest \"$no_ignore_joins\" = \"$ignore_joins\" &&\n+\t\ttest \"$(git rev-list --count ignore_joins)\" -eq 3;\n+\t)\n+'\n+\n+# split excludes commits reachable from any previous --rejoin.\n+# These ignored commits can still be the basis for new work\n+# after the --rejoin. These commits must be processed, even\n+# if they are excluded. Otherwise, the split history will be\n+# incorrect.\n+#\n+# here, the merge\n+#\n+#     git merge --no-ff new_work_based_on_prejoin\n+#\n+# doesn't contain any subtree changes and so should not end\n+# up in the split history. this subtree should be flat,\n+# with no merges.\n+#\n+# see: 315a84f9aa (subtree: use commits before rejoins for\n+#      splits, 2018-09-28)\n+test_expect_success 'split links out-of-tree pre --rejoin commits with post --rejoin commits' '\n+\tsubtree_test_create_repo \"$test_count\" &&\n+\t(\n+\t\tcd \"$test_count\" &&\n+\t\ttest_commit main_must_not_be_in_subtree &&\n+\t\tmkdir sub &&\n+\t\ttest_commit sub/sub1 &&\n+\t\ttest_commit sub/sub2 &&\n+\t\tgit subtree split --prefix sub --rejoin &&\n+\t\ttest \"$(git rev-list --count HEAD)\" -eq 6 &&\n+\t\tgit checkout sub/sub1 &&\n+\t\tgit checkout -b new_work_based_on_prejoin &&\n+\t\ttest_commit main_must_not_be_in_subtree2 &&\n+\t\tgit checkout main &&\n+\t\tgit merge --no-ff new_work_based_on_prejoin &&\n+\t\ttest_commit sub/sub3 &&\n+\t\tgit subtree split -d --prefix sub -b second_split &&\n+\t\tgit checkout second_split &&\n+\t\ttest_path_is_file sub1.t &&\n+\t\ttest_path_is_file sub2.t &&\n+\t\ttest_path_is_file sub3.t &&\n+\t\t! test_path_is_file main_must_not_be_in_subtree.t &&\n+\t\t! test_path_is_file main_must_not_be_in_subtree2.t &&\n+\t\ttest \"$(git rev-list --count --merges second_split)\" -eq 0 &&\n+\t\ttest \"$(git rev-list --count second_split)\" -eq 3;\n+\t)\n+'\n+\n+# split must keep merge commits with unrelated histories, even\n+# if both parents are treesame. When deciding whether or not\n+# to eliminate a parent, copy_or_skip compares the merge-base\n+# of each parent.\n+#\n+# in the split_of_merges branch:\n+#\n+#   * expect 4 commits\n+#   * HEAD~ must be a merge\n+#\n+# see: 68f8ff8151 (subtree: improve decision on merges kept\n+#      in split, 2018-09-28)\n+test_expect_success 'split preserves merges with unrelated history' '\n+\tsubtree_test_create_repo \"$test_count\" &&\n+\t(\n+\t\tcd \"$test_count\" &&\n+\t\ttest_commit main_must_not_be_in_subtree &&\n+\t\tmkdir sub &&\n+\t\ttest_commit sub/sub1 &&\n+\t\tgit checkout --orphan new_history &&\n+\t\tgit checkout sub/sub1 -- . &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"treesame history but not a merge-base\" &&\n+\t\tgit checkout main &&\n+\t\tgit merge --allow-unrelated-histories --no-ff new_history &&\n+\t\ttest \"$(git rev-parse \"HEAD^1^{tree}\")\" = \"$(git rev-parse \"HEAD^2^{tree}\")\" &&\n+\t\ttest_commit sub/sub2 &&\n+\t\tgit subtree split -d --prefix sub -b split_of_merges &&\n+\t\ttest \"$(git rev-list --count split_of_merges)\" -eq 4 &&\n+\t\ttest -n \"$(git rev-list --merges HEAD~)\";\n+\t)\n+'\n+\n #\n # This test covers 2 cases in subtree split copy_or_skip code\n # 1) Merges where one parent is a superset of the changes of the other\n\n-- \n2.43.0\n\n"}]}