3 test_description
='compare full workdir to sparse workdir'
10 test_expect_success
'setup' '
11 git init initial-repo &&
13 GIT_TEST_SPARSE_INDEX=0 &&
16 echo "after deep" >e &&
17 echo "after folder1" >g &&
19 mkdir folder1 folder2 deep x &&
20 mkdir deep/deeper1 deep/deeper2 deep/before deep/later &&
21 mkdir deep/deeper1/deepest &&
22 echo "after deeper1" >deep/e &&
23 echo "after deepest" >deep/deeper1/e &&
32 cp a deep/deeper1/deepest &&
33 cp -r deep/deeper1/deepest deep/deeper2 &&
34 mkdir deep/deeper1/0 &&
35 mkdir deep/deeper1/0/0 &&
36 touch deep/deeper1/0/1 &&
37 touch deep/deeper1/0/0/0 &&
41 cp -r deep/deeper1/0 folder1 &&
42 cp -r deep/deeper1/0 folder2 &&
43 echo >>folder1/0/0/0 &&
46 git commit -m "initial commit" &&
47 git checkout -b base &&
48 for dir in folder1 folder2 deep
50 git checkout -b update-$dir base &&
51 echo "updated $dir" >$dir/a &&
52 git commit -a -m "update $dir" || return 1
55 git checkout -b rename-base base &&
56 cat >folder1/larger-content <<-\EOF &&
63 cp folder1/larger-content folder2/ &&
64 cp folder1/larger-content deep/deeper1/ &&
66 git commit -m "add interesting rename content" &&
68 git checkout -b rename-out-to-out rename-base &&
69 mv folder1/a folder2/b &&
70 mv folder1/larger-content folder2/edited-content &&
71 echo >>folder2/edited-content &&
73 echo stuff >>deep/deeper1/a &&
75 git commit -m "rename folder1/... to folder2/..." &&
77 git checkout -b rename-out-to-in rename-base &&
78 mv folder1/a deep/deeper1/b &&
79 echo more stuff >>deep/deeper1/a &&
82 echo >>folder2/0/1/1 &&
83 mv folder1/larger-content deep/deeper1/edited-content &&
84 echo >>deep/deeper1/edited-content &&
86 git commit -m "rename folder1/... to deep/deeper1/..." &&
88 git checkout -b rename-in-to-out rename-base &&
89 mv deep/deeper1/a folder1/b &&
93 mv deep/deeper1/larger-content folder1/edited-content &&
94 echo >>folder1/edited-content &&
96 git commit -m "rename deep/deeper1/... to folder1/..." &&
98 git checkout -b df-conflict-1 base &&
100 echo content >folder1 &&
102 git commit -m "dir to file" &&
104 git checkout -b df-conflict-2 base &&
106 echo content >folder2 &&
108 git commit -m "dir to file" &&
110 git checkout -b fd-conflict base &&
115 git commit -m "file to dir" &&
117 for side in left right
119 git checkout -b merge-$side base &&
120 echo $side >>deep/deeper2/a &&
121 echo $side >>folder1/a &&
122 echo $side >>folder2/a &&
124 git commit -m "$side" || return 1
127 git checkout -b deepest base &&
128 echo "updated deepest" >deep/deeper1/deepest/a &&
129 git commit -a -m "update deepest" &&
131 git checkout -f base &&
137 rm -rf full-checkout sparse-checkout sparse-index
&&
139 # create repos in initial state
140 cp -r initial-repo full-checkout
&&
141 git
-C full-checkout
reset --hard &&
143 cp -r initial-repo sparse-checkout
&&
144 git
-C sparse-checkout
reset --hard &&
146 cp -r initial-repo sparse-index
&&
147 git
-C sparse-index
reset --hard &&
149 # initialize sparse-checkout definitions
150 git
-C sparse-checkout sparse-checkout init
--cone &&
151 git
-C sparse-checkout sparse-checkout
set deep
&&
152 git
-C sparse-index sparse-checkout init
--cone --sparse-index &&
153 test_cmp_config
-C sparse-index true index.sparse
&&
154 git
-C sparse-index sparse-checkout
set deep
159 cd sparse-checkout
&&
160 GIT_PROGRESS_DELAY
=100000 "$@" >..
/sparse-checkout-out
2>..
/sparse-checkout-err
164 GIT_PROGRESS_DELAY
=100000 "$@" >..
/sparse-index-out
2>..
/sparse-index-err
171 GIT_PROGRESS_DELAY
=100000 "$@" >..
/full-checkout-out
2>..
/full-checkout-err
178 test_cmp full-checkout-out sparse-checkout-out
&&
179 test_cmp full-checkout-out sparse-index-out
&&
180 test_cmp full-checkout-err sparse-checkout-err
&&
181 test_cmp full-checkout-err sparse-index-err
184 test_sparse_match
() {
185 run_on_sparse
"$@" &&
186 test_cmp sparse-checkout-out sparse-index-out
&&
187 test_cmp sparse-checkout-err sparse-index-err
190 test_sparse_unstaged
() {
192 for repo
in sparse-checkout sparse-index
194 # Skip "unmerged" paths
195 git
-C $repo diff --staged --diff-filter=u
-- "$file" >diff &&
196 test_must_be_empty
diff ||
return 1
200 test_expect_success
'sparse-index contents' '
203 test-tool -C sparse-index read-cache --table >cache &&
204 for dir in folder1 folder2 x
206 TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
207 grep "040000 tree $TREE $dir/" cache \
211 git -C sparse-index sparse-checkout set folder1 &&
213 test-tool -C sparse-index read-cache --table >cache &&
214 for dir in deep folder2 x
216 TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
217 grep "040000 tree $TREE $dir/" cache \
221 git -C sparse-index sparse-checkout set deep/deeper1 &&
223 test-tool -C sparse-index read-cache --table >cache &&
224 for dir in deep/deeper2 folder1 folder2 x
226 TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
227 grep "040000 tree $TREE $dir/" cache \
231 # Disabling the sparse-index removes tree entries with full ones
232 git -C sparse-index sparse-checkout init --no-sparse-index &&
234 test-tool -C sparse-index read-cache --table >cache &&
235 ! grep "040000 tree" cache &&
236 test_sparse_match test-tool read-cache --table
239 test_expect_success
'expanded in-memory index matches full index' '
241 test_sparse_match test-tool read-cache --expand --table
244 test_expect_success
'status with options' '
246 test_sparse_match ls &&
247 test_all_match git status --porcelain=v2 &&
248 test_all_match git status --porcelain=v2 -z -u &&
249 test_all_match git status --porcelain=v2 -uno &&
250 run_on_all touch README.md &&
251 test_all_match git status --porcelain=v2 &&
252 test_all_match git status --porcelain=v2 -z -u &&
253 test_all_match git status --porcelain=v2 -uno &&
254 test_all_match git add README.md &&
255 test_all_match git status --porcelain=v2 &&
256 test_all_match git status --porcelain=v2 -z -u &&
257 test_all_match git status --porcelain=v2 -uno
260 test_expect_success
'status reports sparse-checkout' '
262 git -C sparse-checkout status >full &&
263 git -C sparse-index status >sparse &&
264 test_i18ngrep "You are in a sparse checkout with " full &&
265 test_i18ngrep "You are in a sparse checkout." sparse
268 test_expect_success
'add, commit, checkout' '
271 write_script edit-contents <<-\EOF &&
274 run_on_all ../edit-contents README.md &&
276 test_all_match git add README.md &&
277 test_all_match git status --porcelain=v2 &&
278 test_all_match git commit -m "Add README.md" &&
280 test_all_match git checkout HEAD~1 &&
281 test_all_match git checkout - &&
283 run_on_all ../edit-contents README.md &&
285 test_all_match git add -A &&
286 test_all_match git status --porcelain=v2 &&
287 test_all_match git commit -m "Extend README.md" &&
289 test_all_match git checkout HEAD~1 &&
290 test_all_match git checkout - &&
292 run_on_all ../edit-contents deep/newfile &&
294 test_all_match git status --porcelain=v2 -uno &&
295 test_all_match git status --porcelain=v2 &&
296 test_all_match git add . &&
297 test_all_match git status --porcelain=v2 &&
298 test_all_match git commit -m "add deep/newfile" &&
300 test_all_match git checkout HEAD~1 &&
301 test_all_match git checkout -
304 test_expect_success
'add outside sparse cone' '
307 run_on_sparse mkdir folder1 &&
308 run_on_sparse ../edit-contents folder1/a &&
309 run_on_sparse ../edit-contents folder1/newfile &&
310 test_sparse_match test_must_fail git add folder1/a &&
311 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
312 test_sparse_unstaged folder1/a &&
313 test_sparse_match test_must_fail git add folder1/newfile &&
314 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
315 test_sparse_unstaged folder1/newfile
318 test_expect_success
'commit including unstaged changes' '
321 write_script edit-file <<-\EOF &&
325 run_on_all ../edit-file 1 a &&
326 run_on_all ../edit-file 1 deep/a &&
328 test_all_match git commit -m "-a" -a &&
329 test_all_match git status --porcelain=v2 &&
331 run_on_all ../edit-file 2 a &&
332 run_on_all ../edit-file 2 deep/a &&
334 test_all_match git commit -m "--include" --include deep/a &&
335 test_all_match git status --porcelain=v2 &&
336 test_all_match git commit -m "--include" --include a &&
337 test_all_match git status --porcelain=v2 &&
339 run_on_all ../edit-file 3 a &&
340 run_on_all ../edit-file 3 deep/a &&
342 test_all_match git commit -m "--amend" -a --amend &&
343 test_all_match git status --porcelain=v2
346 test_expect_success
'status/add: outside sparse cone' '
349 # folder1 is at HEAD, but outside the sparse cone
350 run_on_sparse mkdir folder1 &&
351 cp initial-repo/folder1/a sparse-checkout/folder1/a &&
352 cp initial-repo/folder1/a sparse-index/folder1/a &&
354 test_sparse_match git status &&
356 write_script edit-contents <<-\EOF &&
359 run_on_sparse ../edit-contents folder1/a &&
360 run_on_all ../edit-contents folder1/new &&
362 test_sparse_match git status --porcelain=v2 &&
364 # Adding the path outside of the sparse-checkout cone should fail.
365 test_sparse_match test_must_fail git add folder1/a &&
366 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
367 test_sparse_unstaged folder1/a &&
368 test_sparse_match test_must_fail git add --refresh folder1/a &&
369 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
370 test_sparse_unstaged folder1/a &&
371 test_sparse_match test_must_fail git add folder1/new &&
372 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
373 test_sparse_unstaged folder1/new &&
374 test_sparse_match git add --sparse folder1/a &&
375 test_sparse_match git add --sparse folder1/new &&
377 test_all_match git add --sparse . &&
378 test_all_match git status --porcelain=v2 &&
379 test_all_match git commit -m folder1/new &&
380 test_all_match git rev-parse HEAD^{tree} &&
382 run_on_all ../edit-contents folder1/newer &&
383 test_all_match git add --sparse folder1/ &&
384 test_all_match git status --porcelain=v2 &&
385 test_all_match git commit -m folder1/newer &&
386 test_all_match git rev-parse HEAD^{tree}
389 test_expect_success
'checkout and reset --hard' '
392 test_all_match git checkout update-folder1 &&
393 test_all_match git status --porcelain=v2 &&
395 test_all_match git checkout update-deep &&
396 test_all_match git status --porcelain=v2 &&
398 test_all_match git checkout -b reset-test &&
399 test_all_match git reset --hard deepest &&
400 test_all_match git reset --hard update-folder1 &&
401 test_all_match git reset --hard update-folder2
404 test_expect_success
'diff --staged' '
407 write_script edit-contents <<-\EOF &&
408 echo text >>README.md
410 run_on_all ../edit-contents &&
412 test_all_match git diff &&
413 test_all_match git diff --staged &&
414 test_all_match git add README.md &&
415 test_all_match git diff &&
416 test_all_match git diff --staged
419 # NEEDSWORK: sparse-checkout behaves differently from full-checkout when
420 # running this test with 'df-conflict-2' after 'df-conflict-1'.
421 test_expect_success
'diff with renames and conflicts' '
424 for branch in rename-out-to-out \
430 test_all_match git checkout rename-base &&
431 test_all_match git checkout $branch -- . &&
432 test_all_match git status --porcelain=v2 &&
433 test_all_match git diff --staged --no-renames &&
434 test_all_match git diff --staged --find-renames || return 1
438 test_expect_success
'diff with directory/file conflicts' '
441 for branch in rename-out-to-out \
448 git -C full-checkout reset --hard &&
449 test_sparse_match git reset --hard &&
450 test_all_match git checkout $branch &&
451 test_all_match git checkout rename-base -- . &&
452 test_all_match git status --porcelain=v2 &&
453 test_all_match git diff --staged --no-renames &&
454 test_all_match git diff --staged --find-renames || return 1
458 test_expect_success
'log with pathspec outside sparse definition' '
461 test_all_match git log -- a &&
462 test_all_match git log -- folder1/a &&
463 test_all_match git log -- folder2/a &&
464 test_all_match git log -- deep/a &&
465 test_all_match git log -- deep/deeper1/a &&
466 test_all_match git log -- deep/deeper1/deepest/a &&
468 test_all_match git checkout update-folder1 &&
469 test_all_match git log -- folder1/a
472 test_expect_success
'blame with pathspec inside sparse definition' '
475 test_all_match git blame a &&
476 test_all_match git blame deep/a &&
477 test_all_match git blame deep/deeper1/a &&
478 test_all_match git blame deep/deeper1/deepest/a
481 # TODO: blame currently does not support blaming files outside of the
482 # sparse definition. It complains that the file doesn't exist locally.
483 test_expect_failure
'blame with pathspec outside sparse definition' '
486 test_all_match git blame folder1/a &&
487 test_all_match git blame folder2/a &&
488 test_all_match git blame deep/deeper2/a &&
489 test_all_match git blame deep/deeper2/deepest/a
492 # NEEDSWORK: a sparse-checkout behaves differently from a full checkout
493 # in this scenario, but it shouldn't.
494 test_expect_failure
'checkout and reset (mixed)' '
497 test_all_match git checkout -b reset-test update-deep &&
498 test_all_match git reset deepest &&
499 test_all_match git reset update-folder1 &&
500 test_all_match git reset update-folder2
503 # NEEDSWORK: a sparse-checkout behaves differently from a full checkout
504 # in this scenario, but it shouldn't.
505 test_expect_success
'checkout and reset (mixed) [sparse]' '
508 test_sparse_match git checkout -b reset-test update-deep &&
509 test_sparse_match git reset deepest &&
510 test_sparse_match git reset update-folder1 &&
511 test_sparse_match git reset update-folder2
514 test_expect_success
'merge, cherry-pick, and rebase' '
517 for OPERATION in "merge -m merge" cherry-pick "rebase --apply" "rebase --merge"
519 test_all_match git checkout -B temp update-deep &&
520 test_all_match git $OPERATION update-folder1 &&
521 test_all_match git rev-parse HEAD^{tree} &&
522 test_all_match git $OPERATION update-folder2 &&
523 test_all_match git rev-parse HEAD^{tree} || return 1
527 test_expect_success
'merge with conflict outside cone' '
530 test_all_match git checkout -b merge-tip merge-left &&
531 test_all_match git status --porcelain=v2 &&
532 test_all_match test_must_fail git merge -m merge merge-right &&
533 test_all_match git status --porcelain=v2 &&
535 # Resolve the conflict in different ways:
536 # 1. Revert to the base
537 test_all_match git checkout base -- deep/deeper2/a &&
538 test_all_match git status --porcelain=v2 &&
540 # 2. Add the file with conflict markers
541 test_sparse_match test_must_fail git add folder1/a &&
542 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
543 test_sparse_unstaged folder1/a &&
544 test_all_match git add --sparse folder1/a &&
545 test_all_match git status --porcelain=v2 &&
547 # 3. Rename the file to another sparse filename and
548 # accept conflict markers as resolved content.
549 run_on_all mv folder2/a folder2/z &&
550 test_sparse_match test_must_fail git add folder2 &&
551 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
552 test_sparse_unstaged folder2/z &&
553 test_all_match git add --sparse folder2 &&
554 test_all_match git status --porcelain=v2 &&
556 test_all_match git merge --continue &&
557 test_all_match git status --porcelain=v2 &&
558 test_all_match git rev-parse HEAD^{tree}
561 test_expect_success
'cherry-pick/rebase with conflict outside cone' '
564 for OPERATION in cherry-pick rebase
566 test_all_match git checkout -B tip &&
567 test_all_match git reset --hard merge-left &&
568 test_all_match git status --porcelain=v2 &&
569 test_all_match test_must_fail git $OPERATION merge-right &&
570 test_all_match git status --porcelain=v2 &&
572 # Resolve the conflict in different ways:
573 # 1. Revert to the base
574 test_all_match git checkout base -- deep/deeper2/a &&
575 test_all_match git status --porcelain=v2 &&
577 # 2. Add the file with conflict markers
578 # NEEDSWORK: Even though the merge conflict removed the
579 # SKIP_WORKTREE bit from the index entry for folder1/a, we should
580 # warn that this is a problematic add.
581 test_sparse_match test_must_fail git add folder1/a &&
582 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
583 test_sparse_unstaged folder1/a &&
584 test_all_match git add --sparse folder1/a &&
585 test_all_match git status --porcelain=v2 &&
587 # 3. Rename the file to another sparse filename and
588 # accept conflict markers as resolved content.
589 # NEEDSWORK: This mode now fails, because folder2/z is
590 # outside of the sparse-checkout cone and does not match an
591 # existing index entry with the SKIP_WORKTREE bit cleared.
592 run_on_all mv folder2/a folder2/z &&
593 test_sparse_match test_must_fail git add folder2 &&
594 grep "Disable or modify the sparsity rules" sparse-checkout-err &&
595 test_sparse_unstaged folder2/z &&
596 test_all_match git add --sparse folder2 &&
597 test_all_match git status --porcelain=v2 &&
599 test_all_match git $OPERATION --continue &&
600 test_all_match git status --porcelain=v2 &&
601 test_all_match git rev-parse HEAD^{tree} || return 1
605 test_expect_success
'merge with outside renames' '
608 for type in out-to-out out-to-in in-to-out
610 test_all_match git reset --hard &&
611 test_all_match git checkout -f -b merge-$type update-deep &&
612 test_all_match git merge -m "$type" rename-$type &&
613 test_all_match git rev-parse HEAD^{tree} || return 1
617 # Sparse-index fails to convert the index in the
618 # final 'git cherry-pick' command.
619 test_expect_success
'cherry-pick with conflicts' '
622 write_script edit-conflict <<-\EOF &&
626 test_all_match git checkout -b to-cherry-pick &&
627 run_on_all ../edit-conflict ABC &&
628 test_all_match git add conflict &&
629 test_all_match git commit -m "conflict to pick" &&
631 test_all_match git checkout -B base HEAD~1 &&
632 run_on_all ../edit-conflict DEF &&
633 test_all_match git add conflict &&
634 test_all_match git commit -m "conflict in base" &&
636 test_all_match test_must_fail git cherry-pick to-cherry-pick
639 test_expect_success
'clean' '
642 echo bogus >>.gitignore &&
643 run_on_all cp ../.gitignore . &&
644 test_all_match git add .gitignore &&
645 test_all_match git commit -m "ignore bogus files" &&
647 run_on_sparse mkdir folder1 &&
648 run_on_all touch folder1/bogus &&
650 test_all_match git status --porcelain=v2 &&
651 test_all_match git clean -f &&
652 test_all_match git status --porcelain=v2 &&
653 test_sparse_match ls &&
654 test_sparse_match ls folder1 &&
656 test_all_match git clean -xf &&
657 test_all_match git status --porcelain=v2 &&
658 test_sparse_match ls &&
659 test_sparse_match ls folder1 &&
661 test_all_match git clean -xdf &&
662 test_all_match git status --porcelain=v2 &&
663 test_sparse_match ls &&
664 test_sparse_match ls folder1 &&
666 test_sparse_match test_path_is_dir folder1
669 test_expect_success
'submodule handling' '
672 test_sparse_match git sparse-checkout add modules &&
673 test_all_match mkdir modules &&
674 test_all_match touch modules/a &&
675 test_all_match git add modules &&
676 test_all_match git commit -m "add modules directory" &&
678 run_on_all git submodule add "$(pwd)/initial-repo" modules/sub &&
679 test_all_match git commit -m "add submodule" &&
681 # having a submodule prevents "modules" from collapse
682 test_sparse_match git sparse-checkout set deep/deeper1 &&
683 test-tool -C sparse-index read-cache --table >cache &&
684 grep "100644 blob .* modules/a" cache &&
685 grep "160000 commit $(git -C initial-repo rev-parse HEAD) modules/sub" cache
688 test_expect_success
'sparse-index is expanded and converted back' '
691 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
692 git -C sparse-index -c core.fsmonitor="" reset --hard &&
693 test_region index convert_to_sparse trace2.txt &&
694 test_region index ensure_full_index trace2.txt
697 test_expect_success
'index.sparse disabled inline uses full index' '
700 # When index.sparse is disabled inline with `git status`, the
701 # index is expanded at the beginning of the execution then never
702 # converted back to sparse. It is then written to disk as a full index.
704 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
705 git -C sparse-index -c index.sparse=false status &&
706 ! test_region index convert_to_sparse trace2.txt &&
707 test_region index ensure_full_index trace2.txt &&
709 # Since index.sparse is set to true at a repo level, the index
710 # is converted from full to sparse when read, then never expanded
711 # over the course of `git status`. It is written to disk as a sparse
714 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
715 git -C sparse-index status &&
716 test_region index convert_to_sparse trace2.txt &&
717 ! test_region index ensure_full_index trace2.txt &&
719 # Now that the index has been written to disk as sparse, it is not
720 # converted to sparse (or expanded to full) when read by `git status`.
722 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
723 git -C sparse-index status &&
724 ! test_region index convert_to_sparse trace2.txt &&
725 ! test_region index ensure_full_index trace2.txt
728 ensure_not_expanded
() {
730 echo >>sparse-index
/untracked.txt
&&
736 GIT_TRACE2_EVENT
="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING
=10 \
737 git
-C sparse-index
"$@" ||
return 1
739 GIT_TRACE2_EVENT
="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING
=10 \
740 git
-C sparse-index
"$@" ||
return 1
742 test_region
! index ensure_full_index trace2.txt
745 test_expect_success
'sparse-index is not expanded' '
748 ensure_not_expanded status &&
749 ensure_not_expanded commit --allow-empty -m empty &&
750 echo >>sparse-index/a &&
751 ensure_not_expanded commit -a -m a &&
752 echo >>sparse-index/a &&
753 ensure_not_expanded commit --include a -m a &&
754 echo >>sparse-index/deep/deeper1/a &&
755 ensure_not_expanded commit --include deep/deeper1/a -m deeper &&
756 ensure_not_expanded checkout rename-out-to-out &&
757 ensure_not_expanded checkout - &&
758 ensure_not_expanded switch rename-out-to-out &&
759 ensure_not_expanded switch - &&
760 git -C sparse-index reset --hard &&
761 ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 &&
762 git -C sparse-index reset --hard &&
763 ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 &&
765 echo >>sparse-index/README.md &&
766 ensure_not_expanded add -A &&
767 echo >>sparse-index/extra.txt &&
768 ensure_not_expanded add extra.txt &&
769 echo >>sparse-index/untracked.txt &&
770 ensure_not_expanded add . &&
772 ensure_not_expanded checkout -f update-deep &&
773 test_config -C sparse-index pull.twohead ort &&
775 sane_unset GIT_TEST_MERGE_ALGORITHM &&
776 for OPERATION in "merge -m merge" cherry-pick rebase
778 ensure_not_expanded merge -m merge update-folder1 &&
779 ensure_not_expanded merge -m merge update-folder2 || return 1
784 test_expect_success
'sparse-index is not expanded: merge conflict in cone' '
787 for side in right left
789 git -C sparse-index checkout -b expand-$side base &&
790 echo $side >sparse-index/deep/a &&
791 git -C sparse-index commit -a -m "$side" || return 1
795 sane_unset GIT_TEST_MERGE_ALGORITHM &&
796 git -C sparse-index config pull.twohead ort &&
797 ensure_not_expanded ! merge -m merged expand-right
801 # NEEDSWORK: a sparse-checkout behaves differently from a full checkout
802 # in this scenario, but it shouldn't.
803 test_expect_success
'reset mixed and checkout orphan' '
806 test_all_match git checkout rename-out-to-in &&
808 # Sparse checkouts do not agree with full checkouts about
809 # how to report a directory/file conflict during a reset.
810 # This command would fail with test_all_match because the
811 # full checkout reports "T folder1/0/1" while a sparse
812 # checkout reports "D folder1/0/1". This matches because
813 # the sparse checkouts skip "adding" the other side of
815 test_sparse_match git reset --mixed HEAD~1 &&
816 test_sparse_match test-tool read-cache --table --expand &&
817 test_sparse_match git status --porcelain=v2 &&
819 # At this point, sparse-checkouts behave differently
820 # from the full-checkout.
821 test_sparse_match git checkout --orphan new-branch &&
822 test_sparse_match test-tool read-cache --table --expand &&
823 test_sparse_match git status --porcelain=v2
826 test_expect_success
'add everything with deep new file' '
829 run_on_sparse git sparse-checkout set deep/deeper1/deepest &&
831 run_on_all touch deep/deeper1/x &&
832 test_all_match git add . &&
833 test_all_match git status --porcelain=v2
836 # NEEDSWORK: 'git checkout' behaves incorrectly in the case of
837 # directory/file conflicts, even without sparse-checkout. Use this
838 # test only as a documentation of the incorrect behavior, not a
839 # measure of how it _should_ behave.
840 test_expect_success
'checkout behaves oddly with df-conflict-1' '
843 test_sparse_match git sparse-checkout disable &&
845 write_script edit-content <<-\EOF &&
846 echo content >>folder1/larger-content
850 run_on_all ../edit-content &&
851 test_all_match git status --porcelain=v2 &&
853 git -C sparse-checkout sparse-checkout init --cone &&
854 git -C sparse-index sparse-checkout init --cone --sparse-index &&
856 test_all_match git status --porcelain=v2 &&
858 # This checkout command should fail, because we have a staged
859 # change to folder1/larger-content, but the destination changes
861 git -C full-checkout checkout df-conflict-1 \
862 1>full-checkout-out \
863 2>full-checkout-err &&
864 git -C sparse-checkout checkout df-conflict-1 \
865 1>sparse-checkout-out \
866 2>sparse-checkout-err &&
867 git -C sparse-index checkout df-conflict-1 \
869 2>sparse-index-err &&
871 # Instead, the checkout deletes the folder1 file and adds the
872 # folder1/larger-content file, leaving all other paths that were
873 # in folder1/ as deleted (without any warning).
874 cat >expect <<-EOF &&
876 A folder1/larger-content
878 test_cmp expect full-checkout-out &&
879 test_cmp expect sparse-checkout-out &&
881 # The sparse-index reports no output
882 test_must_be_empty sparse-index-out &&
884 # stderr: Switched to branch df-conflict-1
885 test_cmp full-checkout-err sparse-checkout-err &&
886 test_cmp full-checkout-err sparse-checkout-err
889 # NEEDSWORK: 'git checkout' behaves incorrectly in the case of
890 # directory/file conflicts, even without sparse-checkout. Use this
891 # test only as a documentation of the incorrect behavior, not a
892 # measure of how it _should_ behave.
893 test_expect_success
'checkout behaves oddly with df-conflict-2' '
896 test_sparse_match git sparse-checkout disable &&
898 write_script edit-content <<-\EOF &&
899 echo content >>folder2/larger-content
903 run_on_all ../edit-content &&
904 test_all_match git status --porcelain=v2 &&
906 git -C sparse-checkout sparse-checkout init --cone &&
907 git -C sparse-index sparse-checkout init --cone --sparse-index &&
909 test_all_match git status --porcelain=v2 &&
911 # This checkout command should fail, because we have a staged
912 # change to folder1/larger-content, but the destination changes
914 git -C full-checkout checkout df-conflict-2 \
915 1>full-checkout-out \
916 2>full-checkout-err &&
917 git -C sparse-checkout checkout df-conflict-2 \
918 1>sparse-checkout-out \
919 2>sparse-checkout-err &&
920 git -C sparse-index checkout df-conflict-2 \
922 2>sparse-index-err &&
924 # The full checkout deviates from the df-conflict-1 case here!
925 # It drops the change to folder1/larger-content and leaves the
926 # folder1 path as-is on disk. The sparse-index behaves the same.
927 test_must_be_empty full-checkout-out &&
928 test_must_be_empty sparse-index-out &&
930 # In the sparse-checkout case, the checkout deletes the folder1
931 # file and adds the folder1/larger-content file, leaving all other
932 # paths that were in folder1/ as deleted (without any warning).
933 cat >expect <<-EOF &&
935 A folder2/larger-content
937 test_cmp expect sparse-checkout-out &&
939 # Switched to branch df-conflict-1
940 test_cmp full-checkout-err sparse-checkout-err &&
941 test_cmp full-checkout-err sparse-index-err