aboutsummaryrefslogtreecommitdiff
path: root/contrib/subtree/t/t7900-subtree.sh
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/subtree/t/t7900-subtree.sh')
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh227
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
)