Git 2.47-rc0
[git.git] / t / t1091-sparse-checkout-builtin.sh
blob8c5cd651b4b80ba05ab9fab572e384806a8404dd
1 #!/bin/sh
3 test_description='sparse checkout builtin tests'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
8 GIT_TEST_SPLIT_INDEX=false
9 export GIT_TEST_SPLIT_INDEX
11 TEST_PASSES_SANITIZE_LEAK=true
12 . ./test-lib.sh
14 list_files() {
15 # Do not replace this with 'ls "$1"', as "ls" with BSD-lineage
16 # enables "-A" by default for root and ends up including ".git" and
17 # such in its output. (Note, though, that running the test suite as
18 # root is generally not recommended.)
19 (cd "$1" && printf '%s\n' *)
22 check_files() {
23 list_files "$1" >actual &&
24 shift &&
25 printf "%s\n" $@ >expect &&
26 test_cmp expect actual
29 test_expect_success 'setup' '
30 git init repo &&
32 cd repo &&
33 echo "initial" >a &&
34 mkdir folder1 folder2 deep &&
35 mkdir deep/deeper1 deep/deeper2 &&
36 mkdir deep/deeper1/deepest &&
37 cp a folder1 &&
38 cp a folder2 &&
39 cp a deep &&
40 cp a deep/deeper1 &&
41 cp a deep/deeper2 &&
42 cp a deep/deeper1/deepest &&
43 git add . &&
44 git commit -m "initial commit"
48 test_expect_success 'git sparse-checkout list (not sparse)' '
49 test_must_fail git -C repo sparse-checkout list >list 2>err &&
50 test_must_be_empty list &&
51 test_grep "this worktree is not sparse" err
54 test_expect_success 'git sparse-checkout list (not sparse)' '
55 git -C repo sparse-checkout set &&
56 rm repo/.git/info/sparse-checkout &&
57 git -C repo sparse-checkout list >list 2>err &&
58 test_must_be_empty list &&
59 test_grep "this worktree is not sparse (sparse-checkout file may not exist)" err
62 test_expect_success 'git sparse-checkout list (populated)' '
63 test_when_finished rm -f repo/.git/info/sparse-checkout &&
64 cat >repo/.git/info/sparse-checkout <<-\EOF &&
65 /folder1/*
66 /deep/
67 **/a
68 !*bin*
69 EOF
70 cp repo/.git/info/sparse-checkout expect &&
71 git -C repo sparse-checkout list >list &&
72 test_cmp expect list
75 test_expect_success 'git sparse-checkout init' '
76 git -C repo sparse-checkout init --no-cone &&
77 cat >expect <<-\EOF &&
79 !/*/
80 EOF
81 test_cmp expect repo/.git/info/sparse-checkout &&
82 test_cmp_config -C repo true core.sparsecheckout &&
83 check_files repo a
86 test_expect_success 'git sparse-checkout init in empty repo' '
87 test_when_finished rm -rf empty-repo blank-template &&
88 git init --template= empty-repo &&
89 git -C empty-repo sparse-checkout init
92 test_expect_success 'git sparse-checkout list after init' '
93 git -C repo sparse-checkout list >actual &&
94 cat >expect <<-\EOF &&
96 !/*/
97 EOF
98 test_cmp expect actual
101 test_expect_success 'init with existing sparse-checkout' '
102 echo "*folder*" >> repo/.git/info/sparse-checkout &&
103 git -C repo sparse-checkout init &&
104 cat >expect <<-\EOF &&
106 !/*/
107 *folder*
109 test_cmp expect repo/.git/info/sparse-checkout &&
110 check_files repo a folder1 folder2
113 test_expect_success 'clone --sparse' '
114 git clone --sparse "file://$(pwd)/repo" clone &&
115 git -C clone sparse-checkout reapply --no-cone &&
116 git -C clone sparse-checkout list >actual &&
117 cat >expect <<-\EOF &&
119 !/*/
121 test_cmp expect actual &&
122 check_files clone a
125 test_expect_success 'switching to cone mode with non-cone mode patterns' '
126 git init bad-patterns &&
128 cd bad-patterns &&
129 git sparse-checkout init --no-cone &&
130 git sparse-checkout add dir &&
131 git config --worktree core.sparseCheckoutCone true &&
132 test_must_fail git sparse-checkout add dir 2>err &&
133 grep "existing sparse-checkout patterns do not use cone mode" err
137 test_expect_success 'interaction with clone --no-checkout (unborn index)' '
138 git clone --no-checkout "file://$(pwd)/repo" clone_no_checkout &&
139 git -C clone_no_checkout sparse-checkout init --cone &&
140 git -C clone_no_checkout sparse-checkout set folder1 &&
142 git -C clone_no_checkout sparse-checkout list >actual &&
143 cat >expect <<-\EOF &&
144 folder1
146 test_cmp expect actual &&
148 # nothing checked out, expect "No such file or directory"
149 ! ls clone_no_checkout/* >actual &&
150 test_must_be_empty actual &&
151 test_path_is_missing clone_no_checkout/.git/index &&
153 # No branch is checked out until we manually switch to one
154 git -C clone_no_checkout switch main &&
155 test_path_is_file clone_no_checkout/.git/index &&
156 check_files clone_no_checkout a folder1
159 test_expect_success 'set enables config' '
160 git init worktree-config &&
162 cd worktree-config &&
163 test_commit test file &&
164 test_path_is_missing .git/config.worktree &&
165 git sparse-checkout set nothing &&
166 test_path_is_file .git/config.worktree &&
167 test_cmp_config true core.sparseCheckout
171 test_expect_success 'set sparse-checkout using builtin' '
172 git -C repo sparse-checkout set "/*" "!/*/" "*folder*" &&
173 cat >expect <<-\EOF &&
175 !/*/
176 *folder*
178 git -C repo sparse-checkout list >actual &&
179 test_cmp expect actual &&
180 test_cmp expect repo/.git/info/sparse-checkout &&
181 check_files repo a folder1 folder2
184 test_expect_success 'set sparse-checkout using --stdin' '
185 cat >expect <<-\EOF &&
187 !/*/
188 /folder1/
189 /folder2/
191 git -C repo sparse-checkout set --stdin <expect &&
192 git -C repo sparse-checkout list >actual &&
193 test_cmp expect actual &&
194 test_cmp expect repo/.git/info/sparse-checkout &&
195 check_files repo "a folder1 folder2"
198 test_expect_success 'add to sparse-checkout' '
199 cat repo/.git/info/sparse-checkout >old &&
200 test_when_finished cp old repo/.git/info/sparse-checkout &&
201 cat >add <<-\EOF &&
202 pattern1
203 /folder1/
204 pattern2
206 cat old >expect &&
207 cat add >>expect &&
208 git -C repo sparse-checkout add --stdin <add &&
209 git -C repo sparse-checkout list >actual &&
210 test_cmp expect actual &&
211 test_cmp expect repo/.git/info/sparse-checkout &&
212 check_files repo "a folder1 folder2"
215 test_expect_success 'worktree: add copies sparse-checkout patterns' '
216 cat repo/.git/info/sparse-checkout >old &&
217 test_when_finished cp old repo/.git/info/sparse-checkout &&
218 test_when_finished git -C repo worktree remove ../worktree &&
219 git -C repo sparse-checkout set --no-cone "/*" &&
220 git -C repo worktree add --quiet ../worktree 2>err &&
221 test_must_be_empty err &&
222 new="$(git -C worktree rev-parse --git-path info/sparse-checkout)" &&
223 test_path_is_file "$new" &&
224 test_cmp repo/.git/info/sparse-checkout "$new" &&
225 git -C worktree sparse-checkout set --cone &&
226 test_cmp_config -C worktree true core.sparseCheckoutCone &&
227 test_must_fail git -C repo core.sparseCheckoutCone
230 test_expect_success 'cone mode: match patterns' '
231 git -C repo config --worktree core.sparseCheckoutCone true &&
232 rm -rf repo/a repo/folder1 repo/folder2 &&
233 git -C repo read-tree -mu HEAD 2>err &&
234 test_grep ! "disabling cone patterns" err &&
235 git -C repo reset --hard &&
236 check_files repo a folder1 folder2
239 test_expect_success 'cone mode: warn on bad pattern' '
240 test_when_finished mv sparse-checkout repo/.git/info/ &&
241 cp repo/.git/info/sparse-checkout . &&
242 echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout &&
243 git -C repo read-tree -mu HEAD 2>err &&
244 test_grep "unrecognized negative pattern" err
247 test_expect_success 'sparse-checkout disable' '
248 test_when_finished rm -rf repo/.git/info/sparse-checkout &&
249 git -C repo sparse-checkout disable &&
250 test_path_is_file repo/.git/info/sparse-checkout &&
251 git -C repo config --list >config &&
252 test_must_fail git config core.sparseCheckout &&
253 check_files repo a deep folder1 folder2
256 test_expect_success 'sparse-index enabled and disabled' '
257 git -C repo sparse-checkout init --cone --sparse-index &&
258 test_cmp_config -C repo true index.sparse &&
259 git -C repo ls-files --sparse >sparse &&
260 git -C repo sparse-checkout disable &&
261 git -C repo ls-files --sparse >full &&
263 cat >expect <<-\EOF &&
264 @@ -1,4 +1,7 @@
266 -deep/
267 -folder1/
268 -folder2/
269 +deep/a
270 +deep/deeper1/a
271 +deep/deeper1/deepest/a
272 +deep/deeper2/a
273 +folder1/a
274 +folder2/a
277 diff -u sparse full | tail -n +3 >actual &&
278 test_cmp expect actual &&
280 git -C repo config --list >config &&
281 test_cmp_config -C repo false index.sparse
284 test_expect_success 'cone mode: init and set' '
285 git -C repo sparse-checkout init --cone &&
286 git -C repo config --list >config &&
287 test_grep "core.sparsecheckoutcone=true" config &&
288 list_files repo >dir &&
289 echo a >expect &&
290 test_cmp expect dir &&
291 git -C repo sparse-checkout set deep/deeper1/deepest/ 2>err &&
292 test_must_be_empty err &&
293 check_files repo a deep &&
294 check_files repo/deep a deeper1 &&
295 check_files repo/deep/deeper1 a deepest &&
296 cat >expect <<-\EOF &&
298 !/*/
299 /deep/
300 !/deep/*/
301 /deep/deeper1/
302 !/deep/deeper1/*/
303 /deep/deeper1/deepest/
305 test_cmp expect repo/.git/info/sparse-checkout &&
306 git -C repo sparse-checkout set --stdin 2>err <<-\EOF &&
307 folder1
308 folder2
310 test_must_be_empty err &&
311 check_files repo a folder1 folder2
314 test_expect_success 'cone mode: list' '
315 cat >expect <<-\EOF &&
316 folder1
317 folder2
319 git -C repo sparse-checkout set --stdin <expect &&
320 git -C repo sparse-checkout list >actual 2>err &&
321 test_must_be_empty err &&
322 test_cmp expect actual
325 test_expect_success 'cone mode: set with nested folders' '
326 git -C repo sparse-checkout set deep deep/deeper1/deepest 2>err &&
327 test_line_count = 0 err &&
328 cat >expect <<-\EOF &&
330 !/*/
331 /deep/
333 test_cmp repo/.git/info/sparse-checkout expect
336 test_expect_success 'cone mode: add independent path' '
337 git -C repo sparse-checkout set deep/deeper1 &&
338 git -C repo sparse-checkout add --end-of-options folder1 &&
339 cat >expect <<-\EOF &&
341 !/*/
342 /deep/
343 !/deep/*/
344 /deep/deeper1/
345 /folder1/
347 test_cmp expect repo/.git/info/sparse-checkout &&
348 check_files repo a deep folder1
351 test_expect_success 'cone mode: add sibling path' '
352 git -C repo sparse-checkout set deep/deeper1 &&
353 git -C repo sparse-checkout add deep/deeper2 &&
354 cat >expect <<-\EOF &&
356 !/*/
357 /deep/
358 !/deep/*/
359 /deep/deeper1/
360 /deep/deeper2/
362 test_cmp expect repo/.git/info/sparse-checkout &&
363 check_files repo a deep
366 test_expect_success 'cone mode: add parent path' '
367 git -C repo sparse-checkout set deep/deeper1 folder1 &&
368 git -C repo sparse-checkout add deep &&
369 cat >expect <<-\EOF &&
371 !/*/
372 /deep/
373 /folder1/
375 test_cmp expect repo/.git/info/sparse-checkout &&
376 check_files repo a deep folder1
379 test_expect_success 'not-up-to-date does not block rest of sparsification' '
380 test_when_finished git -C repo sparse-checkout disable &&
381 test_when_finished git -C repo reset --hard &&
382 git -C repo sparse-checkout set deep &&
384 echo update >repo/deep/deeper2/a &&
385 cp repo/.git/info/sparse-checkout expect &&
386 test_write_lines "!/deep/*/" "/deep/deeper1/" >>expect &&
388 git -C repo sparse-checkout set deep/deeper1 2>err &&
390 test_grep "The following paths are not up to date" err &&
391 test_cmp expect repo/.git/info/sparse-checkout &&
392 check_files repo/deep a deeper1 deeper2 &&
393 check_files repo/deep/deeper1 a deepest &&
394 check_files repo/deep/deeper1/deepest a &&
395 check_files repo/deep/deeper2 a
398 test_expect_success 'revert to old sparse-checkout on empty update' '
399 git init empty-test &&
401 echo >file &&
402 git add file &&
403 git commit -m "test" &&
404 git sparse-checkout set nothing 2>err &&
405 test_grep ! "Sparse checkout leaves no entry on working directory" err &&
406 test_grep ! ".git/index.lock" err &&
407 git sparse-checkout set --no-cone file
411 test_expect_success 'fail when lock is taken' '
412 test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
413 touch repo/.git/info/sparse-checkout.lock &&
414 test_must_fail git -C repo sparse-checkout set deep 2>err &&
415 test_grep "Unable to create .*\.lock" err
418 test_expect_success '.gitignore should not warn about cone mode' '
419 git -C repo config --worktree core.sparseCheckoutCone true &&
420 echo "**/bin/*" >repo/.gitignore &&
421 git -C repo reset --hard 2>err &&
422 test_grep ! "disabling cone patterns" err
425 test_expect_success 'sparse-checkout (init|set|disable) warns with dirty status' '
426 git clone repo dirty &&
427 echo dirty >dirty/folder1/a &&
429 git -C dirty sparse-checkout init --no-cone 2>err &&
430 test_grep "warning.*The following paths are not up to date" err &&
432 git -C dirty sparse-checkout set /folder2/* /deep/deeper1/* 2>err &&
433 test_grep "warning.*The following paths are not up to date" err &&
434 test_path_is_file dirty/folder1/a &&
436 git -C dirty sparse-checkout disable 2>err &&
437 test_must_be_empty err &&
439 git -C dirty reset --hard &&
440 git -C dirty sparse-checkout init --no-cone &&
441 git -C dirty sparse-checkout set /folder2/* /deep/deeper1/* &&
442 test_path_is_missing dirty/folder1/a &&
443 git -C dirty sparse-checkout disable &&
444 test_path_is_file dirty/folder1/a
447 test_expect_success 'sparse-checkout (init|set|disable) warns with unmerged status' '
448 git clone repo unmerged &&
450 cat >input <<-EOF &&
451 0 $ZERO_OID folder1/a
452 100644 $(git -C unmerged rev-parse HEAD:folder1/a) 1 folder1/a
454 git -C unmerged update-index --index-info <input &&
456 git -C unmerged sparse-checkout init --no-cone 2>err &&
457 test_grep "warning.*The following paths are unmerged" err &&
459 git -C unmerged sparse-checkout set /folder2/* /deep/deeper1/* 2>err &&
460 test_grep "warning.*The following paths are unmerged" err &&
461 test_path_is_file dirty/folder1/a &&
463 git -C unmerged sparse-checkout disable 2>err &&
464 test_grep "warning.*The following paths are unmerged" err &&
466 git -C unmerged reset --hard &&
467 git -C unmerged sparse-checkout init --no-cone &&
468 git -C unmerged sparse-checkout set /folder2/* /deep/deeper1/* &&
469 git -C unmerged sparse-checkout disable
472 test_expect_failure 'sparse-checkout reapply' '
473 git clone repo tweak &&
475 echo dirty >tweak/deep/deeper2/a &&
477 cat >input <<-EOF &&
478 0 $ZERO_OID folder1/a
479 100644 $(git -C tweak rev-parse HEAD:folder1/a) 1 folder1/a
481 git -C tweak update-index --index-info <input &&
483 git -C tweak sparse-checkout init --cone 2>err &&
484 test_grep "warning.*The following paths are not up to date" err &&
485 test_grep "warning.*The following paths are unmerged" err &&
487 git -C tweak sparse-checkout set folder2 deep/deeper1 2>err &&
488 test_grep "warning.*The following paths are not up to date" err &&
489 test_grep "warning.*The following paths are unmerged" err &&
491 git -C tweak sparse-checkout reapply 2>err &&
492 test_grep "warning.*The following paths are not up to date" err &&
493 test_path_is_file tweak/deep/deeper2/a &&
494 test_grep "warning.*The following paths are unmerged" err &&
495 test_path_is_file tweak/folder1/a &&
497 git -C tweak checkout HEAD deep/deeper2/a &&
498 git -C tweak sparse-checkout reapply 2>err &&
499 test_grep ! "warning.*The following paths are not up to date" err &&
500 test_path_is_missing tweak/deep/deeper2/a &&
501 test_grep "warning.*The following paths are unmerged" err &&
502 test_path_is_file tweak/folder1/a &&
504 # NEEDSWORK: We are asking to update a file outside of the
505 # sparse-checkout cone, but this is no longer allowed.
506 git -C tweak add folder1/a &&
507 git -C tweak sparse-checkout reapply 2>err &&
508 test_must_be_empty err &&
509 test_path_is_missing tweak/deep/deeper2/a &&
510 test_path_is_missing tweak/folder1/a &&
512 git -C tweak sparse-checkout disable
515 test_expect_success 'reapply can handle config options' '
516 git -C repo sparse-checkout init --cone --no-sparse-index &&
517 git -C repo config --worktree --list >actual &&
518 cat >expect <<-\EOF &&
519 core.sparsecheckout=true
520 core.sparsecheckoutcone=true
521 index.sparse=false
523 test_cmp expect actual &&
525 git -C repo sparse-checkout reapply --no-cone --no-sparse-index &&
526 git -C repo config --worktree --list >actual &&
527 cat >expect <<-\EOF &&
528 core.sparsecheckout=true
529 core.sparsecheckoutcone=false
530 index.sparse=false
532 test_cmp expect actual &&
534 git -C repo sparse-checkout reapply --cone --sparse-index &&
535 git -C repo config --worktree --list >actual &&
536 cat >expect <<-\EOF &&
537 core.sparsecheckout=true
538 core.sparsecheckoutcone=true
539 index.sparse=true
541 test_cmp expect actual &&
543 git -C repo sparse-checkout disable
546 test_expect_success 'cone mode: set with core.ignoreCase=true' '
547 rm repo/.git/info/sparse-checkout &&
548 git -C repo sparse-checkout init --cone &&
549 git -C repo -c core.ignoreCase=true sparse-checkout set folder1 &&
550 cat >expect <<-\EOF &&
552 !/*/
553 /folder1/
555 test_cmp expect repo/.git/info/sparse-checkout &&
556 check_files repo a folder1
559 test_expect_success 'setup submodules' '
560 git clone repo super &&
562 cd super &&
563 mkdir modules &&
564 git -c protocol.file.allow=always \
565 submodule add ../repo modules/child &&
566 git add . &&
567 git commit -m "add submodule" &&
568 git sparse-checkout init --cone &&
569 git sparse-checkout set folder1
573 test_expect_success 'interaction with submodules' '
574 check_files super a folder1 modules &&
575 check_files super/modules/child a deep folder1 folder2
578 test_expect_success 'check-rules interaction with submodules' '
579 git -C super ls-tree --name-only -r HEAD >all-files &&
580 git -C super sparse-checkout check-rules >check-rules-matches <all-files &&
582 test_grep ! "modules/" check-rules-matches &&
583 test_grep "folder1/" check-rules-matches
586 test_expect_success 'different sparse-checkouts with worktrees' '
587 git -C repo sparse-checkout set --cone deep folder1 &&
588 git -C repo worktree add --detach ../worktree &&
589 check_files worktree "a deep folder1" &&
590 git -C repo sparse-checkout set --cone folder1 &&
591 git -C worktree sparse-checkout set --cone deep/deeper1 &&
592 check_files repo "a folder1" &&
593 check_files worktree "a deep"
596 test_expect_success 'set using filename keeps file on-disk' '
597 git -C repo sparse-checkout set --skip-checks a deep &&
598 cat >expect <<-\EOF &&
600 !/*/
602 /deep/
604 test_cmp expect repo/.git/info/sparse-checkout &&
605 check_files repo a deep
608 check_read_tree_errors () {
609 REPO=$1
610 FILES=$2
611 ERRORS=$3
612 git -C $REPO -c core.sparseCheckoutCone=false read-tree -mu HEAD 2>err &&
613 test_must_be_empty err &&
614 check_files $REPO "$FILES" &&
615 git -C $REPO read-tree -mu HEAD 2>err &&
616 if test -z "$ERRORS"
617 then
618 test_must_be_empty err
619 else
620 test_grep "$ERRORS" err
621 fi &&
622 check_files $REPO $FILES
625 test_expect_success 'pattern-checks: /A/**' '
626 cat >repo/.git/info/sparse-checkout <<-\EOF &&
628 !/*/
629 /folder1/**
631 check_read_tree_errors repo "a folder1" "disabling cone pattern matching"
634 test_expect_success 'pattern-checks: /A/**/B/' '
635 cat >repo/.git/info/sparse-checkout <<-\EOF &&
637 !/*/
638 /deep/**/deepest
640 check_read_tree_errors repo "a deep" "disabling cone pattern matching" &&
641 check_files repo/deep "deeper1" &&
642 check_files repo/deep/deeper1 "deepest"
645 test_expect_success 'pattern-checks: too short' '
646 cat >repo/.git/info/sparse-checkout <<-\EOF &&
648 !/*/
651 check_read_tree_errors repo "a" "disabling cone pattern matching"
653 test_expect_success 'pattern-checks: not too short' '
654 cat >repo/.git/info/sparse-checkout <<-\EOF &&
656 !/*/
659 git -C repo read-tree -mu HEAD 2>err &&
660 test_must_be_empty err &&
661 check_files repo a
664 test_expect_success 'pattern-checks: trailing "*"' '
665 cat >repo/.git/info/sparse-checkout <<-\EOF &&
667 !/*/
670 check_read_tree_errors repo "a" "disabling cone pattern matching"
673 test_expect_success 'pattern-checks: starting "*"' '
674 cat >repo/.git/info/sparse-checkout <<-\EOF &&
676 !/*/
677 *eep/
679 check_read_tree_errors repo "a deep" "disabling cone pattern matching"
682 test_expect_success 'pattern-checks: non directory pattern' '
683 cat >repo/.git/info/sparse-checkout <<-\EOF &&
684 /deep/deeper1/a
686 check_read_tree_errors repo deep "disabling cone pattern matching" &&
687 check_files repo/deep deeper1 &&
688 check_files repo/deep/deeper1 a
691 test_expect_success 'pattern-checks: contained glob characters' '
692 for c in "[a]" "\\" "?" "*"
694 cat >repo/.git/info/sparse-checkout <<-EOF &&
696 !/*/
697 something$c-else/
699 check_read_tree_errors repo "a" "disabling cone pattern matching" || return 1
700 done
703 test_expect_success BSLASHPSPEC 'pattern-checks: escaped characters' '
704 git clone repo escaped &&
705 TREEOID=$(git -C escaped rev-parse HEAD:folder1) &&
706 NEWTREE=$(git -C escaped mktree <<-EOF
707 $(git -C escaped ls-tree HEAD)
708 040000 tree $TREEOID zbad\\dir
709 040000 tree $TREEOID zdoes*exist
710 040000 tree $TREEOID zglob[!a]?
712 ) &&
713 COMMIT=$(git -C escaped commit-tree $NEWTREE -p HEAD) &&
714 git -C escaped reset --hard $COMMIT &&
715 check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" zglob[!a]? &&
716 git -C escaped sparse-checkout init --cone &&
717 git -C escaped sparse-checkout set --skip-checks zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" "zglob[!a]?" &&
718 cat >expect <<-\EOF &&
720 !/*/
721 /zbad\\dir/
722 !/zbad\\dir/*/
723 /zbad\\dir/bogus/
724 /zdoes\*exist/
725 /zdoes\*not\*exist/
726 /zglob\[!a]\?/
728 test_cmp expect escaped/.git/info/sparse-checkout &&
729 check_read_tree_errors escaped "a zbad\\dir zdoes*exist zglob[!a]?" &&
730 git -C escaped ls-tree -d --name-only HEAD >list-expect &&
731 git -C escaped sparse-checkout set --stdin <list-expect &&
732 cat >expect <<-\EOF &&
734 !/*/
735 /deep/
736 /folder1/
737 /folder2/
738 /zbad\\dir/
739 /zdoes\*exist/
740 /zglob\[!a]\?/
742 test_cmp expect escaped/.git/info/sparse-checkout &&
743 check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" zglob[!a]? &&
744 git -C escaped sparse-checkout list >list-actual &&
745 test_cmp list-expect list-actual
748 test_expect_success MINGW 'cone mode replaces backslashes with slashes' '
749 git -C repo sparse-checkout set deep\\deeper1 &&
750 cat >expect <<-\EOF &&
752 !/*/
753 /deep/
754 !/deep/*/
755 /deep/deeper1/
757 test_cmp expect repo/.git/info/sparse-checkout &&
758 check_files repo a deep &&
759 check_files repo/deep a deeper1
762 test_expect_success 'cone mode clears ignored subdirectories' '
763 rm repo/.git/info/sparse-checkout &&
765 git -C repo sparse-checkout init --cone &&
766 git -C repo sparse-checkout set deep/deeper1 &&
768 cat >repo/.gitignore <<-\EOF &&
769 obj/
773 git -C repo add .gitignore &&
774 git -C repo commit -m ".gitignore" &&
776 mkdir -p repo/obj repo/folder1/obj repo/deep/deeper2/obj &&
777 for file in folder1/obj/a obj/a folder1/file.o folder1.o \
778 deep/deeper2/obj/a deep/deeper2/file.o file.o
780 echo ignored >repo/$file || return 1
781 done &&
783 git -C repo status --porcelain=v2 >out &&
784 test_must_be_empty out &&
786 git -C repo sparse-checkout reapply &&
787 test_path_is_missing repo/folder1 &&
788 test_path_is_missing repo/deep/deeper2 &&
789 test_path_is_dir repo/obj &&
790 test_path_is_file repo/file.o &&
792 git -C repo status --porcelain=v2 >out &&
793 test_must_be_empty out &&
795 git -C repo sparse-checkout set deep/deeper2 &&
796 test_path_is_missing repo/deep/deeper1 &&
797 test_path_is_dir repo/deep/deeper2 &&
798 test_path_is_dir repo/obj &&
799 test_path_is_file repo/file.o &&
801 >repo/deep/deeper2/ignored.o &&
802 >repo/deep/deeper2/untracked &&
804 # When an untracked file is in the way, all untracked files
805 # (even ignored files) are preserved.
806 git -C repo sparse-checkout set folder1 2>err &&
807 grep "contains untracked files" err &&
808 test_path_is_file repo/deep/deeper2/ignored.o &&
809 test_path_is_file repo/deep/deeper2/untracked &&
811 # The rest of the cone matches expectation
812 test_path_is_missing repo/deep/deeper1 &&
813 test_path_is_dir repo/obj &&
814 test_path_is_file repo/file.o &&
816 git -C repo status --porcelain=v2 >out &&
817 echo "? deep/deeper2/untracked" >expect &&
818 test_cmp expect out
821 test_expect_success 'malformed cone-mode patterns' '
822 git -C repo sparse-checkout init --cone &&
823 mkdir -p repo/foo/bar &&
824 touch repo/foo/bar/x repo/foo/y &&
825 cat >repo/.git/info/sparse-checkout <<-\EOF &&
827 !/*/
828 /foo/
829 !/foo/*/
830 /foo/\*/
833 # Listing the patterns will notice the duplicate pattern and
834 # emit a warning. It will list the patterns directly instead
835 # of using the cone-mode translation to a set of directories.
836 git -C repo sparse-checkout list >actual 2>err &&
837 test_cmp repo/.git/info/sparse-checkout actual &&
838 grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err &&
839 grep "warning: disabling cone pattern matching" err
842 test_expect_success 'set from subdir pays attention to prefix' '
843 git -C repo sparse-checkout disable &&
844 git -C repo/deep sparse-checkout set --cone deeper2 ../folder1 &&
846 git -C repo sparse-checkout list >actual &&
848 cat >expect <<-\EOF &&
849 deep/deeper2
850 folder1
852 test_cmp expect actual
855 test_expect_success 'add from subdir pays attention to prefix' '
856 git -C repo sparse-checkout set --cone deep/deeper2 &&
857 git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 &&
859 git -C repo sparse-checkout list >actual &&
861 cat >expect <<-\EOF &&
862 deep/deeper1/deepest
863 deep/deeper2
864 folder1
866 test_cmp expect actual
869 test_expect_success 'set from subdir in non-cone mode throws an error' '
870 git -C repo sparse-checkout disable &&
871 test_must_fail git -C repo/deep sparse-checkout set --no-cone deeper2 ../folder1 2>error &&
873 grep "run from the toplevel directory in non-cone mode" error
876 test_expect_success 'set from subdir in non-cone mode throws an error' '
877 git -C repo sparse-checkout set --no-cone deep/deeper2 &&
878 test_must_fail git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 2>error &&
880 grep "run from the toplevel directory in non-cone mode" error
883 test_expect_success 'by default, cone mode will error out when passed files' '
884 git -C repo sparse-checkout reapply --cone &&
885 test_must_fail git -C repo sparse-checkout add .gitignore 2>error &&
887 grep ".gitignore.*is not a directory" error
890 test_expect_success 'error on mistyped command line options' '
891 test_must_fail git -C repo sparse-checkout add --sikp-checks .gitignore 2>error &&
893 grep "unknown option.*sikp-checks" error
896 test_expect_success 'by default, non-cone mode will warn on individual files' '
897 git -C repo sparse-checkout reapply --no-cone &&
898 git -C repo sparse-checkout add .gitignore 2>warning &&
900 grep "pass a leading slash before paths.*if you want a single file" warning
903 test_expect_success 'setup bare repo' '
904 git clone --bare "file://$(pwd)/repo" bare
906 test_expect_success 'list fails outside work tree' '
907 test_must_fail git -C bare sparse-checkout list 2>err &&
908 test_grep "this operation must be run in a work tree" err
911 test_expect_success 'add fails outside work tree' '
912 test_must_fail git -C bare sparse-checkout add deeper 2>err &&
913 test_grep "this operation must be run in a work tree" err
916 test_expect_success 'set fails outside work tree' '
917 test_must_fail git -C bare sparse-checkout set deeper 2>err &&
918 test_grep "this operation must be run in a work tree" err
921 test_expect_success 'init fails outside work tree' '
922 test_must_fail git -C bare sparse-checkout init 2>err &&
923 test_grep "this operation must be run in a work tree" err
926 test_expect_success 'reapply fails outside work tree' '
927 test_must_fail git -C bare sparse-checkout reapply 2>err &&
928 test_grep "this operation must be run in a work tree" err
931 test_expect_success 'disable fails outside work tree' '
932 test_must_fail git -C bare sparse-checkout disable 2>err &&
933 test_grep "this operation must be run in a work tree" err
936 test_expect_success 'setup clean' '
937 git -C repo clean -fdx
940 test_expect_success 'check-rules cone mode' '
941 cat >rules <<-\EOF &&
942 folder1
943 deep/deeper1/deepest
946 git -C bare ls-tree -r --name-only HEAD >all-files &&
947 git -C bare sparse-checkout check-rules --cone \
948 --rules-file ../rules >check-rules-file <all-files &&
950 git -C repo sparse-checkout set --cone --stdin <rules&&
951 git -C repo ls-files -t >out &&
952 sed -n "/^S /!s/^. //p" out >ls-files &&
954 git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
956 test_grep "deep/deeper1/deepest/a" check-rules-file &&
957 test_grep ! "deep/deeper2" check-rules-file &&
959 test_cmp check-rules-file ls-files &&
960 test_cmp check-rules-file check-rules-default
963 test_expect_success 'check-rules non-cone mode' '
964 cat >rules <<-\EOF &&
965 deep/deeper1/deepest/a
968 git -C bare ls-tree -r --name-only HEAD >all-files &&
969 git -C bare sparse-checkout check-rules --no-cone --rules-file ../rules\
970 >check-rules-file <all-files &&
972 git -C repo sparse-checkout set --no-cone --stdin <rules &&
973 git -C repo ls-files -t >out &&
974 sed -n "/^S /!s/^. //p" out >ls-files &&
976 git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
978 cat >expect <<-\EOF &&
979 deep/deeper1/deepest/a
982 test_cmp expect check-rules-file &&
983 test_cmp check-rules-file ls-files &&
984 test_cmp check-rules-file check-rules-default
987 test_expect_success 'check-rules cone mode is default' '
988 cat >rules <<-\EOF &&
989 folder1
992 cat >all-files <<-\EOF &&
993 toplevel
994 folder2/file
995 folder1/file
998 cat >expect <<-\EOF &&
999 toplevel
1000 folder1/file
1003 git -C repo sparse-checkout set --no-cone &&
1004 git -C repo sparse-checkout check-rules \
1005 --rules-file ../rules >actual <all-files &&
1007 git -C bare sparse-checkout check-rules \
1008 --rules-file ../rules >actual-bare <all-files &&
1010 test_cmp expect actual &&
1011 test_cmp expect actual-bare
1014 test_expect_success 'check-rules quoting' '
1015 cat >rules <<-EOF &&
1016 "folder\" a"
1018 cat >files <<-EOF &&
1019 "folder\" a/file"
1020 "folder\" b/file"
1022 cat >expect <<-EOF &&
1023 "folder\" a/file"
1025 git sparse-checkout check-rules --cone \
1026 --rules-file rules >actual <files &&
1028 test_cmp expect actual
1031 test_expect_success 'check-rules null termination' '
1032 cat >rules <<-EOF &&
1033 "folder\" a"
1036 lf_to_nul >files <<-EOF &&
1037 folder" a/a
1038 folder" a/b
1039 folder" b/fileQ
1042 cat >expect <<-EOF &&
1043 folder" a/aQfolder" a/bQ
1046 git sparse-checkout check-rules --cone -z \
1047 --rules-file rules >actual.nul <files &&
1048 nul_to_q <actual.nul >actual &&
1049 echo >>actual &&
1051 test_cmp expect actual
1055 test_done