diff options
Diffstat (limited to 'contrib/subtree/t/t7900-subtree.sh')
| -rwxr-xr-x | contrib/subtree/t/t7900-subtree.sh | 227 |
1 files changed, 214 insertions, 13 deletions
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 316dc5269e..18d2b56448 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -368,6 +368,28 @@ test_expect_success 'split requires path given by option --prefix must exist' ' ) ' +test_expect_success 'split works when prefix exists in commit but not in working tree' ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + + # create subtree + mkdir pkg && + echo ok >pkg/file && + git add pkg && + git commit -m "add pkg" && + good=$(git rev-parse HEAD) && + + # remove it from working tree in later commit + git rm -r pkg && + git commit -m "remove pkg" && + + # must still be able to split using the old commit + git subtree split --prefix=pkg "$good" >out && + test -s out + ) +' + test_expect_success 'split rejects flags for add' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/sub proj" && @@ -411,8 +433,9 @@ test_expect_success 'split sub dir/ with --rejoin' ' git fetch ./"sub proj" HEAD && git subtree merge --prefix="sub dir" FETCH_HEAD && split_hash=$(git subtree split --prefix="sub dir" --annotate="*") && - git subtree split --prefix="sub dir" --annotate="*" --rejoin && - test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" + git subtree split --prefix="sub dir" --annotate="*" -b spl --rejoin && + test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" && + test "$(git rev-list --count spl)" -eq 5 ) ' @@ -427,8 +450,7 @@ test_expect_success 'split sub dir/ with --rejoin' ' # - Perform 'split' on subtree B # - Create new commits with changes to subtree A and B # - Perform split on subtree A -# - Check that the commits in subtree B are not processed -# as part of the subtree A split +# - Check for expected history test_expect_success 'split with multiple subtrees' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/subA" && @@ -442,18 +464,25 @@ test_expect_success 'split with multiple subtrees' ' git -C "$test_count" subtree add --prefix=subADir FETCH_HEAD && git -C "$test_count" fetch ./subB HEAD && git -C "$test_count" subtree add --prefix=subBDir FETCH_HEAD && + test "$(git -C "$test_count" rev-list --count main)" -eq 7 && test_create_commit "$test_count" subADir/main-subA1 && test_create_commit "$test_count" subBDir/main-subB1 && git -C "$test_count" subtree split --prefix=subADir \ - --squash --rejoin -m "Sub A Split 1" && + --squash --rejoin -m "Sub A Split 1" -b a1 && + test "$(git -C "$test_count" rev-list --count main..a1)" -eq 1 && git -C "$test_count" subtree split --prefix=subBDir \ - --squash --rejoin -m "Sub B Split 1" && + --squash --rejoin -m "Sub B Split 1" -b b1 && + test "$(git -C "$test_count" rev-list --count main..b1)" -eq 1 && test_create_commit "$test_count" subADir/main-subA2 && test_create_commit "$test_count" subBDir/main-subB2 && git -C "$test_count" subtree split --prefix=subADir \ - --squash --rejoin -m "Sub A Split 2" && - test "$(git -C "$test_count" subtree split --prefix=subBDir \ - --squash --rejoin -d -m "Sub B Split 1" 2>&1 | grep -w "\[1\]")" = "" + --squash --rejoin -m "Sub A Split 2" -b a2 && + test "$(git -C "$test_count" rev-list --count main..a2)" -eq 2 && + test "$(git -C "$test_count" rev-list --count a1..a2)" -eq 1 && + git -C "$test_count" subtree split --prefix=subBDir \ + --squash --rejoin -d -m "Sub B Split 1" -b b2 && + test "$(git -C "$test_count" rev-list --count main..b2)" -eq 2 && + test "$(git -C "$test_count" rev-list --count b1..b2)" -eq 1 ' # When subtree split-ing a directory that has other subtree @@ -477,6 +506,7 @@ do test_path_is_file subA/file1.t && test_path_is_file subA/subB/file2.t && git subtree split --prefix=subA --branch=bsplit && + test "$(git rev-list --count bsplit)" -eq 2 && git checkout bsplit && test_path_is_file file1.t && test_path_is_file subB/file2.t && @@ -489,6 +519,7 @@ do --prefix=subA/subB mksubtree && test_path_is_file subA/subB/file3.t && git subtree split --prefix=subA --branch=bsplit && + test "$(git rev-list --count bsplit)" -eq 3 && git checkout bsplit && test_path_is_file file1.t && test_path_is_file subB/file2.t && @@ -497,6 +528,67 @@ do ' done +# Usually, +# +# git subtree merge -P subA --squash f00... +# +# makes two commits, in this order: +# +# 1. Squashed 'subA/' content from commit f00... +# 2. Merge commit (1) as 'subA' +# +# Commit 1 updates the subtree but does *not* rewrite paths. +# Commit 2 rewrites all trees to start with `subA/` +# +# Commit 1 either has no parents or depends only on other +# "Squashed 'subA/' content" commits. +# +# For merge without --squash, subtree produces just one commit: +# a merge commit with git-subtree trailers. +# +# In either case, if the user rebases these commits, they will +# still have the git-subtree-* trailers… but will NOT have +# the layout described above. +# +# Test that subsequent `git subtree split` are not confused by this. +test_expect_success 'split with rebased subtree commit' ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + test_commit file0 && + test_create_subtree_add \ + . mksubtree subA file1 --squash && + test_path_is_file subA/file1.t && + mkdir subB && + test_commit subB/bfile && + git commit --amend -F - <<'EOF' && +Squashed '\''subB/'\'' content from commit '\''badf00da911bbe895347b4b236f5461d55dc9877'\'' + +Simulate a cherry-picked or rebased subtree commit. + +git-subtree-dir: subB +git-subtree-split: badf00da911bbe895347b4b236f5461d55dc9877 +EOF + test_commit subA/file2 && + test_commit subB/bfile2 && + git commit --amend -F - <<'EOF' && +Split '\''subB/'\'' into commit '\''badf00da911bbe895347b4b236f5461d55dc9877'\'' + +Simulate a cherry-picked or rebased subtree commit. + +git-subtree-dir: subB +git-subtree-mainline: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +git-subtree-split: badf00da911bbe895347b4b236f5461d55dc9877 +EOF + git subtree split --prefix=subA --branch=bsplit && + git checkout bsplit && + test_path_is_file file1.t && + test_path_is_file file2.t && + test "$(last_commit_subject)" = "subA/file2" && + test "$(git rev-list --count bsplit)" -eq 2 + ) +' + test_expect_success 'split sub dir/ with --rejoin from scratch' ' subtree_test_create_repo "$test_count" && test_create_commit "$test_count" main1 && @@ -1575,6 +1667,116 @@ test_expect_success 'push split to subproj' ' ) ' +# --ignore-joins must ignore mainline content outside of the +# subtree. This test verifies that the logic in +# `find_existing_splits()` correctly handles a `git subtree add` +# In this test, the split history must not contain a commit titled +# +# Add 'sub/' from commit ... +# +# see: dd21d43b58 (subtree: make --ignore-joins pay +# attention to adds, 2018-09-28) +test_expect_success 'split --ignore-joins respects subtree add' ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + test_commit main_must_not_be_in_subtree && + test_create_subtree_add . mksubtree sub sub1 && + test_commit sub/sub2 && + test_commit main_must_not_be_in_subtree2 && + git subtree split --prefix sub -b first_split --rejoin && + test_commit sub/sub3 && + no_ignore_joins="$(git subtree split --prefix sub -b no_ignore_joins)" && + ignore_joins="$(git subtree split --prefix sub --ignore-joins -b ignore_joins)" && + git checkout ignore_joins && + test_path_is_file sub1.t && + test_path_is_file sub2.t && + test_path_is_file sub3.t && + ! test_path_is_file main_must_not_be_in_subtree.t && + ! test_path_is_file main_must_not_be_in_subtree2.t && + test -z "$(git log -1 --grep "Add '''sub/''' from commit" ignore_joins)" && + test "$no_ignore_joins" = "$ignore_joins" && + test "$(git rev-list --count ignore_joins)" -eq 3; + ) +' + +# split excludes commits reachable from any previous --rejoin. +# These ignored commits can still be the basis for new work +# after the --rejoin. These commits must be processed, even +# if they are excluded. Otherwise, the split history will be +# incorrect. +# +# here, the merge +# +# git merge --no-ff new_work_based_on_prejoin +# +# doesn't contain any subtree changes and so should not end +# up in the split history. this subtree should be flat, +# with no merges. +# +# see: 315a84f9aa (subtree: use commits before rejoins for +# splits, 2018-09-28) +test_expect_success 'split links out-of-tree pre --rejoin commits with post --rejoin commits' ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + test_commit main_must_not_be_in_subtree && + mkdir sub && + test_commit sub/sub1 && + test_commit sub/sub2 && + git subtree split --prefix sub --rejoin && + test "$(git rev-list --count HEAD)" -eq 6 && + git checkout sub/sub1 && + git checkout -b new_work_based_on_prejoin && + test_commit main_must_not_be_in_subtree2 && + git checkout main && + git merge --no-ff new_work_based_on_prejoin && + test_commit sub/sub3 && + git subtree split -d --prefix sub -b second_split && + git checkout second_split && + test_path_is_file sub1.t && + test_path_is_file sub2.t && + test_path_is_file sub3.t && + ! test_path_is_file main_must_not_be_in_subtree.t && + ! test_path_is_file main_must_not_be_in_subtree2.t && + test "$(git rev-list --count --merges second_split)" -eq 0 && + test "$(git rev-list --count second_split)" -eq 3; + ) +' + +# split must keep merge commits with unrelated histories, even +# if both parents are treesame. When deciding whether or not +# to eliminate a parent, copy_or_skip compares the merge-base +# of each parent. +# +# in the split_of_merges branch: +# +# * expect 4 commits +# * HEAD~ must be a merge +# +# see: 68f8ff8151 (subtree: improve decision on merges kept +# in split, 2018-09-28) +test_expect_success 'split preserves merges with unrelated history' ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + test_commit main_must_not_be_in_subtree && + mkdir sub && + test_commit sub/sub1 && + git checkout --orphan new_history && + git checkout sub/sub1 -- . && + git add . && + git commit -m "treesame history but not a merge-base" && + git checkout main && + git merge --allow-unrelated-histories --no-ff new_history && + test "$(git rev-parse "HEAD^1^{tree}")" = "$(git rev-parse "HEAD^2^{tree}")" && + test_commit sub/sub2 && + git subtree split -d --prefix sub -b split_of_merges && + test "$(git rev-list --count split_of_merges)" -eq 4 && + test -n "$(git rev-list --merges HEAD~)"; + ) +' + # # This test covers 2 cases in subtree split copy_or_skip code # 1) Merges where one parent is a superset of the changes of the other @@ -1597,7 +1799,6 @@ test_expect_success 'push split to subproj' ' test_expect_success 'subtree descendant check' ' subtree_test_create_repo "$test_count" && - defaultBranch=$(sed "s,ref: refs/heads/,," "$test_count/.git/HEAD") && test_create_commit "$test_count" folder_subtree/a && ( cd "$test_count" && @@ -1614,7 +1815,7 @@ test_expect_success 'subtree descendant check' ' ( cd "$test_count" && git cherry-pick $cherry && - git checkout $defaultBranch && + git checkout main && git merge -m "merge should be kept on subtree" branch && git branch no_subtree_work_branch ) && @@ -1626,10 +1827,10 @@ test_expect_success 'subtree descendant check' ' test_create_commit "$test_count" not_a_subtree_change && ( cd "$test_count" && - git checkout $defaultBranch && + git checkout main && git merge -m "merge should be skipped on subtree" no_subtree_work_branch && - git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch && + git subtree split --prefix folder_subtree/ --branch subtree_tip main && git subtree split --prefix folder_subtree/ --branch subtree_branch branch && test $(git rev-list --count subtree_tip..subtree_branch) = 0 ) |
