@@ -244,6 +244,24 @@ test_expect_success 'expanded in-memory index matches full index' '
244244 test_sparse_match git ls-files --stage
245245'
246246
247+ test_expect_success ' root directory cannot be sparse' '
248+ init_repos &&
249+
250+ # Remove all in-cone files and directories from the index, collapse index
251+ # with `git sparse-checkout reapply`
252+ git -C sparse-index rm -r . &&
253+ git -C sparse-index sparse-checkout reapply &&
254+
255+ # Verify sparse directories still present, root directory is not sparse
256+ cat >expect <<-EOF &&
257+ folder1/
258+ folder2/
259+ x/
260+ EOF
261+ git -C sparse-index ls-files --sparse >actual &&
262+ test_cmp expect actual
263+ '
264+
247265test_expect_success ' status with options' '
248266 init_repos &&
249267 test_sparse_match ls &&
@@ -260,6 +278,13 @@ test_expect_success 'status with options' '
260278 test_all_match git status --porcelain=v2 -uno
261279'
262280
281+ test_expect_success ' status with diff in unexpanded sparse directory' '
282+ init_repos &&
283+ test_all_match git checkout rename-base &&
284+ test_all_match git reset --soft rename-out-to-out &&
285+ test_all_match git status --porcelain=v2
286+ '
287+
263288test_expect_success ' status reports sparse-checkout' '
264289 init_repos &&
265290 git -C sparse-checkout status >full &&
@@ -794,6 +819,93 @@ test_expect_success 'update-index --cacheinfo' '
794819 test_cmp expect sparse-checkout-out
795820'
796821
822+ for MERGE_TREES in " base HEAD update-folder2" \
823+ " update-folder1 update-folder2" \
824+ " update-folder2"
825+ do
826+ test_expect_success " 'read-tree -mu $MERGE_TREES ' with files outside sparse definition" '
827+ init_repos &&
828+
829+ # Although the index matches, without --no-sparse-checkout, outside-of-
830+ # definition files will not exist on disk for sparse checkouts
831+ test_all_match git read-tree -mu $MERGE_TREES &&
832+ test_all_match git status --porcelain=v2 &&
833+ test_path_is_missing sparse-checkout/folder2 &&
834+ test_path_is_missing sparse-index/folder2 &&
835+
836+ test_all_match git read-tree --reset -u HEAD &&
837+ test_all_match git status --porcelain=v2 &&
838+
839+ test_all_match git read-tree -mu --no-sparse-checkout $MERGE_TREES &&
840+ test_all_match git status --porcelain=v2 &&
841+ test_cmp sparse-checkout/folder2/a sparse-index/folder2/a &&
842+ test_cmp sparse-checkout/folder2/a full-checkout/folder2/a
843+
844+ '
845+ done
846+
847+ test_expect_success ' read-tree --merge with edit/edit conflicts in sparse directories' '
848+ init_repos &&
849+
850+ # Merge of multiple changes to same directory (but not same files) should
851+ # succeed
852+ test_all_match git read-tree -mu base rename-base update-folder1 &&
853+ test_all_match git status --porcelain=v2 &&
854+
855+ test_all_match git reset --hard &&
856+
857+ test_all_match git read-tree -mu rename-base update-folder2 &&
858+ test_all_match git status --porcelain=v2 &&
859+
860+ test_all_match git reset --hard &&
861+
862+ test_all_match test_must_fail git read-tree -mu base update-folder1 rename-out-to-in &&
863+ test_all_match test_must_fail git read-tree -mu rename-out-to-in update-folder1
864+ '
865+
866+ test_expect_success ' read-tree --prefix' '
867+ init_repos &&
868+
869+ # If files differing between the index and target <commit-ish> exist
870+ # inside the prefix, `read-tree --prefix` should fail
871+ test_all_match test_must_fail git read-tree --prefix=deep/ deepest &&
872+ test_all_match test_must_fail git read-tree --prefix=folder1/ update-folder1 &&
873+
874+ # If no differing index entries exist matching the prefix,
875+ # `read-tree --prefix` updates the index successfully
876+ test_all_match git rm -rf deep/deeper1/deepest/ &&
877+ test_all_match git read-tree --prefix=deep/deeper1/deepest -u deepest &&
878+ test_all_match git status --porcelain=v2 &&
879+
880+ test_all_match git rm -rf --sparse folder1/ &&
881+ test_all_match git read-tree --prefix=folder1/ -u update-folder1 &&
882+ test_all_match git status --porcelain=v2 &&
883+
884+ test_all_match git rm -rf --sparse folder2/0 &&
885+ test_all_match git read-tree --prefix=folder2/0/ -u rename-out-to-out &&
886+ test_all_match git status --porcelain=v2
887+ '
888+
889+ test_expect_success ' read-tree --merge with directory-file conflicts' '
890+ init_repos &&
891+
892+ test_all_match git checkout -b test-branch rename-base &&
893+
894+ # Although the index matches, without --no-sparse-checkout, outside-of-
895+ # definition files will not exist on disk for sparse checkouts
896+ test_sparse_match git read-tree -mu rename-out-to-out &&
897+ test_sparse_match git status --porcelain=v2 &&
898+ test_path_is_missing sparse-checkout/folder2 &&
899+ test_path_is_missing sparse-index/folder2 &&
900+
901+ test_sparse_match git read-tree --reset -u HEAD &&
902+ test_sparse_match git status --porcelain=v2 &&
903+
904+ test_sparse_match git read-tree -mu --no-sparse-checkout rename-out-to-out &&
905+ test_sparse_match git status --porcelain=v2 &&
906+ test_cmp sparse-checkout/folder2/0/1 sparse-index/folder2/0/1
907+ '
908+
797909test_expect_success ' merge, cherry-pick, and rebase' '
798910 init_repos &&
799911
@@ -1297,6 +1409,27 @@ test_expect_success 'sparse index is not expanded: fetch/pull' '
12971409 ensure_not_expanded pull full base
12981410'
12991411
1412+ test_expect_success ' sparse index is not expanded: read-tree' '
1413+ init_repos &&
1414+
1415+ ensure_not_expanded checkout -b test-branch update-folder1 &&
1416+ for MERGE_TREES in "base HEAD update-folder2" \
1417+ "base HEAD rename-base" \
1418+ "base update-folder2" \
1419+ "base rename-base" \
1420+ "update-folder2"
1421+ do
1422+ ensure_not_expanded read-tree -mu $MERGE_TREES &&
1423+ ensure_not_expanded reset --hard || return 1
1424+ done &&
1425+
1426+ rm -rf sparse-index/deep/deeper2 &&
1427+ ensure_not_expanded add . &&
1428+ ensure_not_expanded commit -m "test" &&
1429+
1430+ ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest
1431+ '
1432+
13001433test_expect_success ' ls-files' '
13011434 init_repos &&
13021435
0 commit comments