@@ -805,6 +805,117 @@ test_expect_success 'update-index --cacheinfo' '
805805 test_sparse_match git status --porcelain=v2
806806'
807807
808+ test_expect_success ' read-tree --merge with files outside sparse definition' '
809+ init_repos &&
810+
811+ test_all_match git checkout -b test-branch update-folder1 &&
812+ for MERGE_TREES in "base HEAD update-folder2" \
813+ "update-folder1 update-folder2" \
814+ "update-folder2"
815+ do
816+ # Clean up and remove on-disk files
817+ test_all_match git reset --hard HEAD &&
818+ test_sparse_match git sparse-checkout reapply &&
819+
820+ # Although the index matches, without --no-sparse-checkout, outside-of-
821+ # definition files will not exist on disk for sparse checkouts
822+ test_all_match git read-tree -mu $MERGE_TREES &&
823+ test_all_match git status --porcelain=v2 &&
824+ test_path_is_missing sparse-checkout/folder2 &&
825+ test_path_is_missing sparse-index/folder2 &&
826+
827+ test_all_match git read-tree --reset -u HEAD &&
828+ test_all_match git status --porcelain=v2 &&
829+
830+ test_all_match git read-tree -mu --no-sparse-checkout $MERGE_TREES &&
831+ test_all_match git status --porcelain=v2 &&
832+ test_cmp sparse-checkout/folder2/a sparse-index/folder2/a &&
833+ test_cmp sparse-checkout/folder2/a full-checkout/folder2/a || return 1
834+ done
835+ '
836+
837+ test_expect_success ' read-tree --merge with edit/edit conflicts in sparse directories' '
838+ init_repos &&
839+
840+ # Merge of multiple changes to same directory (but not same files) should
841+ # succeed
842+ test_all_match git read-tree -mu base rename-base update-folder1 &&
843+ test_all_match git status --porcelain=v2 &&
844+
845+ test_all_match git reset --hard &&
846+
847+ test_all_match git read-tree -mu rename-base update-folder2 &&
848+ test_all_match git status --porcelain=v2 &&
849+
850+ test_all_match git reset --hard &&
851+
852+ test_all_match test_must_fail git read-tree -mu base update-folder1 rename-out-to-in &&
853+ test_all_match test_must_fail git read-tree -mu rename-out-to-in update-folder1
854+ '
855+
856+ test_expect_success ' read-tree --merge with modified file outside definition' '
857+ init_repos &&
858+
859+ write_script edit-contents <<-\EOF &&
860+ echo text >>$1
861+ EOF
862+
863+ test_all_match git checkout -b test-branch update-folder1 &&
864+ run_on_sparse mkdir -p folder2 &&
865+ run_on_all ../edit-contents folder2/a &&
866+
867+ # With manually-modified file, full-checkout cannot merge, but it is ignored
868+ # in sparse checkouts
869+ test_must_fail git -C full-checkout read-tree -mu update-folder2 &&
870+ test_sparse_match git read-tree -mu update-folder2 &&
871+ test_sparse_match git status --porcelain=v2 &&
872+
873+ # Reset only the sparse checkouts to "undo" the merge. All three checkouts
874+ # now have matching indexes and matching folder2/a on disk.
875+ test_sparse_match git read-tree --reset -u HEAD &&
876+
877+ # When --no-sparse-checkout is specified, sparse checkouts identify the file
878+ # on disk and prevent the merge
879+ test_all_match test_must_fail git read-tree -mu --no-sparse-checkout update-folder2
880+ '
881+
882+ test_expect_success ' read-tree --prefix outside sparse definition' '
883+ init_repos &&
884+
885+ # Cannot read-tree --prefix with a single argument when files exist within
886+ # prefix
887+ test_all_match test_must_fail git read-tree --prefix=folder1/ -u update-folder1 &&
888+
889+ test_all_match git read-tree --prefix=folder2/0 -u rename-base &&
890+ test_path_is_missing sparse-checkout/folder2 &&
891+ test_path_is_missing sparse-index/folder2 &&
892+
893+ test_all_match git read-tree --reset -u HEAD &&
894+ test_all_match git read-tree --prefix=folder2/0 -u --no-sparse-checkout rename-base &&
895+ test_cmp sparse-checkout/folder2/0/a sparse-index/folder2/0/a &&
896+ test_cmp sparse-checkout/folder2/0/a full-checkout/folder2/0/a
897+ '
898+
899+ test_expect_success ' read-tree --merge with directory-file conflicts' '
900+ init_repos &&
901+
902+ test_all_match git checkout -b test-branch rename-base &&
903+
904+ # Although the index matches, without --no-sparse-checkout, outside-of-
905+ # definition files will not exist on disk for sparse checkouts
906+ test_sparse_match git read-tree -mu rename-out-to-out &&
907+ test_sparse_match git status --porcelain=v2 &&
908+ test_path_is_missing sparse-checkout/folder2 &&
909+ test_path_is_missing sparse-index/folder2 &&
910+
911+ test_sparse_match git read-tree --reset -u HEAD &&
912+ test_sparse_match git status --porcelain=v2 &&
913+
914+ test_sparse_match git read-tree -mu --no-sparse-checkout rename-out-to-out &&
915+ test_sparse_match git status --porcelain=v2 &&
916+ test_cmp sparse-checkout/folder2/0/1 sparse-index/folder2/0/1
917+ '
918+
808919test_expect_success ' merge, cherry-pick, and rebase' '
809920 init_repos &&
810921
@@ -1221,6 +1332,23 @@ test_expect_success 'sparse index is not expanded: update-index' '
12211332 ensure_not_expanded update-index --add --remove --again
12221333'
12231334
1335+ test_expect_success ' sparse index is not expanded: read-tree' '
1336+ init_repos &&
1337+
1338+ ensure_not_expanded checkout -b test-branch update-folder1 &&
1339+ for MERGE_TREES in "update-folder2"
1340+ do
1341+ ensure_not_expanded read-tree -mu $MERGE_TREES &&
1342+ ensure_not_expanded reset --hard HEAD || return 1
1343+ done &&
1344+
1345+ rm -rf sparse-index/deep/deeper2 &&
1346+ ensure_not_expanded add . &&
1347+ ensure_not_expanded commit -m "test" &&
1348+
1349+ ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest
1350+ '
1351+
12241352# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
12251353# in this scenario, but it shouldn't.
12261354test_expect_success ' reset mixed and checkout orphan' '
0 commit comments