@@ -588,6 +588,156 @@ test_expect_success 'reset with wildcard pathspec' '
588
588
test_all_match git status --porcelain=v2
589
589
'
590
590
591
+ # NEEDSWORK: although update-index executes without error on files outside
592
+ # the sparse checkout definition, it does not actually add the file to the
593
+ # index. This is also true when "--no-ignore-skip-worktree-entries" is
594
+ # specified.
595
+ test_expect_success ' update-index add outside sparse definition' '
596
+ init_repos &&
597
+
598
+ write_script edit-contents <<-\EOF &&
599
+ echo text >>$1
600
+ EOF
601
+
602
+ run_on_sparse mkdir -p folder1 &&
603
+ run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
604
+
605
+ # Edit the file only in sparse checkouts so that, when checking the status
606
+ # of the index, the unmodified full-checkout is compared to the "modified"
607
+ # sparse checkouts.
608
+ run_on_sparse ../edit-contents folder1/a &&
609
+
610
+ test_sparse_match git update-index --add folder1/a &&
611
+ test_all_match git status --porcelain=v2 &&
612
+ test_sparse_match git update-index --add --no-ignore-skip-worktree-entries folder1/a &&
613
+ test_all_match git status --porcelain=v2
614
+ '
615
+
616
+ test_expect_success ' update-index remove outside sparse definition' '
617
+ init_repos &&
618
+
619
+ # When --remove is specified, files outside the sparse checkout definition
620
+ # are considered "removed".
621
+ rm -f full-checkout/folder1/a &&
622
+ test_all_match git update-index --remove folder1/a &&
623
+ test_all_match git status --porcelain=v2 &&
624
+
625
+ git reset --hard &&
626
+
627
+ # When --ignore-skip-worktree-entries is explicitly specified, a file
628
+ # outside the sparse definition is not added to the index as "removed"
629
+ # (thus matching the unmodified full-checkout).
630
+ test_sparse_match git update-index --remove --ignore-skip-worktree-entries folder1/a &&
631
+ test_all_match git status --porcelain=v2 &&
632
+
633
+ git reset --hard &&
634
+
635
+ # --force-remove supercedes --ignore-skip-worktree-entries and always
636
+ # removes the file from the index.
637
+ test_all_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a &&
638
+ test_all_match git status --porcelain=v2
639
+ '
640
+
641
+ test_expect_success ' update-index folder add/remove' '
642
+ init_repos &&
643
+
644
+ test_all_match test_must_fail git update-index --add --remove deep &&
645
+ test_all_match test_must_fail git update-index --add --remove deep/ &&
646
+
647
+ # NEEDSWORK: attempting to update-index on an existing folder outside the
648
+ # sparse checkout definition does not throw an error (as it does for folders
649
+ # inside the definition, or in the full checkout). However, it is a no-op.
650
+ test_sparse_match git update-index --add --remove folder1 &&
651
+ test_sparse_match git update-index --add --remove folder1/ &&
652
+ test_sparse_match git update-index --force-remove folder1/ &&
653
+ test_all_match git status --porcelain=v2 &&
654
+
655
+ # New folders, even in sparse checkouts, throw an error on update-index
656
+ run_on_all mkdir folder3 &&
657
+ run_on_all cp a folder3/a &&
658
+ run_on_all test_must_fail git update-index --add --remove folder3
659
+ '
660
+
661
+ test_expect_success ' update-index with updated flags' '
662
+ init_repos &&
663
+
664
+ # NEEDSWORK: updating flags runs inconsistently on directories, performing no
665
+ # operation with warning text specifying the path being ignored if a trailing
666
+ # slash is in the path, but throwing an error if there is no trailing slash.
667
+ test_all_match test_must_fail git update-index --no-skip-worktree folder1 &&
668
+ test_all_match git update-index --no-skip-worktree folder1/ &&
669
+ test_all_match git status --porcelain=v2 &&
670
+
671
+ # Removing the skip-worktree bit from a file outside the sparse checkout
672
+ # will cause the file to appear as unstaged and deleted.
673
+ test_sparse_match git update-index --no-skip-worktree folder1/a &&
674
+ rm -f full-checkout/folder1/a &&
675
+ test_all_match git status --porcelain=v2
676
+ '
677
+
678
+ test_expect_success ' update-index --again file outside sparse definition' '
679
+ init_repos &&
680
+
681
+ write_script edit-contents <<-\EOF &&
682
+ echo text >>$1
683
+ EOF
684
+
685
+ # When a file is manually added and modified outside the checkout
686
+ # definition, it will not be changed with `--again` because its changes are
687
+ # not tracked in the index.
688
+ run_on_sparse mkdir -p folder1 &&
689
+ run_on_sparse ../edit-contents folder1/a &&
690
+ test_sparse_match git update-index --again &&
691
+ test_sparse_match git status --porcelain=v2 &&
692
+
693
+ # Update the sparse checkouts so that folder1/a is no longer skipped and
694
+ # exists on-disk
695
+ run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
696
+ test_sparse_match git update-index --no-skip-worktree folder1/a &&
697
+ test_all_match git status --porcelain=v2 &&
698
+
699
+ # Stage change for commit
700
+ run_on_all ../edit-contents folder1/a &&
701
+ test_all_match git update-index folder1/a &&
702
+ test_all_match git status --porcelain=v2 &&
703
+
704
+ # Modify the file
705
+ run_on_all ../edit-contents folder1/a &&
706
+ test_all_match git status --porcelain=v2 &&
707
+
708
+ # Run update-index --again, which re-stages the local changes
709
+ test_all_match git update-index --again &&
710
+ test_all_match git ls-files -s folder1/a &&
711
+ test_all_match git status --porcelain=v2 &&
712
+
713
+ # Running update-index --again with staged changes after manually deleting
714
+ # the file on disk will cause it to fail if --remove is not also specified
715
+ run_on_all rm -f folder1/a &&
716
+ test_all_match test_must_fail git update-index --again folder1 &&
717
+ test_all_match git update-index --remove --again &&
718
+ test_all_match git status --porcelain=v2
719
+ '
720
+
721
+ test_expect_success ' update-index --cacheinfo' '
722
+ init_repos &&
723
+
724
+ deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) &&
725
+ folder2_oid=$(git -C full-checkout rev-parse update-folder2:folder2) &&
726
+ folder1_a_oid=$(git -C full-checkout rev-parse update-folder1:folder1/a) &&
727
+
728
+ test_all_match git update-index --cacheinfo 100644 $deep_a_oid deep/a &&
729
+ test_all_match git status --porcelain=v2 &&
730
+
731
+ # Cannot add sparse directory, even in sparse index case
732
+ test_all_match test_must_fail git update-index --add --cacheinfo 040000 $folder2_oid folder2/ &&
733
+
734
+ # Sparse match only - because folder1/a is outside the sparse checkout
735
+ # definition (and thus not on-disk), it will appear as "deleted" in
736
+ # unstaged changes.
737
+ test_all_match git update-index --add --cacheinfo 100644 $folder1_a_oid folder1/a &&
738
+ test_sparse_match git status --porcelain=v2
739
+ '
740
+
591
741
test_expect_success ' merge, cherry-pick, and rebase' '
592
742
init_repos &&
593
743
0 commit comments