@@ -625,6 +625,156 @@ test_expect_success 'reset with wildcard pathspec' '
625
625
test_all_match git status --porcelain=v2
626
626
'
627
627
628
+ # NEEDSWORK: although update-index executes without error on files outside
629
+ # the sparse checkout definition, it does not actually add the file to the
630
+ # index. This is also true when "--no-ignore-skip-worktree-entries" is
631
+ # specified.
632
+ test_expect_success ' update-index add outside sparse definition' '
633
+ init_repos &&
634
+
635
+ write_script edit-contents <<-\EOF &&
636
+ echo text >>$1
637
+ EOF
638
+
639
+ run_on_sparse mkdir -p folder1 &&
640
+ run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
641
+
642
+ # Edit the file only in sparse checkouts so that, when checking the status
643
+ # of the index, the unmodified full-checkout is compared to the "modified"
644
+ # sparse checkouts.
645
+ run_on_sparse ../edit-contents folder1/a &&
646
+
647
+ test_sparse_match git update-index --add folder1/a &&
648
+ test_all_match git status --porcelain=v2 &&
649
+ test_sparse_match git update-index --add --no-ignore-skip-worktree-entries folder1/a &&
650
+ test_all_match git status --porcelain=v2
651
+ '
652
+
653
+ test_expect_success ' update-index remove outside sparse definition' '
654
+ init_repos &&
655
+
656
+ # When --remove is specified, files outside the sparse checkout definition
657
+ # are considered "removed".
658
+ rm -f full-checkout/folder1/a &&
659
+ test_all_match git update-index --remove folder1/a &&
660
+ test_all_match git status --porcelain=v2 &&
661
+
662
+ git reset --hard &&
663
+
664
+ # When --ignore-skip-worktree-entries is explicitly specified, a file
665
+ # outside the sparse definition is not added to the index as "removed"
666
+ # (thus matching the unmodified full-checkout).
667
+ test_sparse_match git update-index --remove --ignore-skip-worktree-entries folder1/a &&
668
+ test_all_match git status --porcelain=v2 &&
669
+
670
+ git reset --hard &&
671
+
672
+ # --force-remove supercedes --ignore-skip-worktree-entries and always
673
+ # removes the file from the index.
674
+ test_all_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a &&
675
+ test_all_match git status --porcelain=v2
676
+ '
677
+
678
+ test_expect_success ' update-index folder add/remove' '
679
+ init_repos &&
680
+
681
+ test_all_match test_must_fail git update-index --add --remove deep &&
682
+ test_all_match test_must_fail git update-index --add --remove deep/ &&
683
+
684
+ # NEEDSWORK: attempting to update-index on an existing folder outside the
685
+ # sparse checkout definition does not throw an error (as it does for folders
686
+ # inside the definition, or in the full checkout). However, it is a no-op.
687
+ test_sparse_match git update-index --add --remove folder1 &&
688
+ test_sparse_match git update-index --add --remove folder1/ &&
689
+ test_sparse_match git update-index --force-remove folder1/ &&
690
+ test_all_match git status --porcelain=v2 &&
691
+
692
+ # New folders, even in sparse checkouts, throw an error on update-index
693
+ run_on_all mkdir folder3 &&
694
+ run_on_all cp a folder3/a &&
695
+ run_on_all test_must_fail git update-index --add --remove folder3
696
+ '
697
+
698
+ test_expect_success ' update-index with updated flags' '
699
+ init_repos &&
700
+
701
+ # NEEDSWORK: updating flags runs inconsistently on directories, performing no
702
+ # operation with warning text specifying the path being ignored if a trailing
703
+ # slash is in the path, but throwing an error if there is no trailing slash.
704
+ test_all_match test_must_fail git update-index --no-skip-worktree folder1 &&
705
+ test_all_match git update-index --no-skip-worktree folder1/ &&
706
+ test_all_match git status --porcelain=v2 &&
707
+
708
+ # Removing the skip-worktree bit from a file outside the sparse checkout
709
+ # will cause the file to appear as unstaged and deleted.
710
+ test_sparse_match git update-index --no-skip-worktree folder1/a &&
711
+ rm -f full-checkout/folder1/a &&
712
+ test_all_match git status --porcelain=v2
713
+ '
714
+
715
+ test_expect_success ' update-index --again file outside sparse definition' '
716
+ init_repos &&
717
+
718
+ write_script edit-contents <<-\EOF &&
719
+ echo text >>$1
720
+ EOF
721
+
722
+ # When a file is manually added and modified outside the checkout
723
+ # definition, it will not be changed with `--again` because its changes are
724
+ # not tracked in the index.
725
+ run_on_sparse mkdir -p folder1 &&
726
+ run_on_sparse ../edit-contents folder1/a &&
727
+ test_sparse_match git update-index --again &&
728
+ test_sparse_match git status --porcelain=v2 &&
729
+
730
+ # Update the sparse checkouts so that folder1/a is no longer skipped and
731
+ # exists on-disk
732
+ run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
733
+ test_sparse_match git update-index --no-skip-worktree folder1/a &&
734
+ test_all_match git status --porcelain=v2 &&
735
+
736
+ # Stage change for commit
737
+ run_on_all ../edit-contents folder1/a &&
738
+ test_all_match git update-index folder1/a &&
739
+ test_all_match git status --porcelain=v2 &&
740
+
741
+ # Modify the file
742
+ run_on_all ../edit-contents folder1/a &&
743
+ test_all_match git status --porcelain=v2 &&
744
+
745
+ # Run update-index --again, which re-stages the local changes
746
+ test_all_match git update-index --again &&
747
+ test_all_match git ls-files -s folder1/a &&
748
+ test_all_match git status --porcelain=v2 &&
749
+
750
+ # Running update-index --again with staged changes after manually deleting
751
+ # the file on disk will cause it to fail if --remove is not also specified
752
+ run_on_all rm -f folder1/a &&
753
+ test_all_match test_must_fail git update-index --again folder1 &&
754
+ test_all_match git update-index --remove --again &&
755
+ test_all_match git status --porcelain=v2
756
+ '
757
+
758
+ test_expect_success ' update-index --cacheinfo' '
759
+ init_repos &&
760
+
761
+ deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) &&
762
+ folder2_oid=$(git -C full-checkout rev-parse update-folder2:folder2) &&
763
+ folder1_a_oid=$(git -C full-checkout rev-parse update-folder1:folder1/a) &&
764
+
765
+ test_all_match git update-index --cacheinfo 100644 $deep_a_oid deep/a &&
766
+ test_all_match git status --porcelain=v2 &&
767
+
768
+ # Cannot add sparse directory, even in sparse index case
769
+ test_all_match test_must_fail git update-index --add --cacheinfo 040000 $folder2_oid folder2/ &&
770
+
771
+ # Sparse match only - because folder1/a is outside the sparse checkout
772
+ # definition (and thus not on-disk), it will appear as "deleted" in
773
+ # unstaged changes.
774
+ test_all_match git update-index --add --cacheinfo 100644 $folder1_a_oid folder1/a &&
775
+ test_sparse_match git status --porcelain=v2
776
+ '
777
+
628
778
test_expect_success ' merge, cherry-pick, and rebase' '
629
779
init_repos &&
630
780
@@ -931,6 +1081,21 @@ test_expect_success 'sparse index is not expanded: sparse-checkout' '
931
1081
ensure_not_expanded sparse-checkout set
932
1082
'
933
1083
1084
+ test_expect_success ' sparse index is not expanded: update-index' '
1085
+ init_repos &&
1086
+
1087
+ echo "test" >sparse-index/README.md &&
1088
+ echo "test2" >sparse-index/a &&
1089
+ rm -f sparse-index/deep/a &&
1090
+
1091
+ ensure_not_expanded update-index --add README.md &&
1092
+ ensure_not_expanded update-index a &&
1093
+ ensure_not_expanded update-index --remove deep/a &&
1094
+
1095
+ rm -f sparse-index/README.md sparse-index/a &&
1096
+ ensure_not_expanded update-index --add --remove --again
1097
+ '
1098
+
934
1099
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
935
1100
# in this scenario, but it shouldn't.
936
1101
test_expect_success ' reset mixed and checkout orphan' '
0 commit comments