3 test_description='test untracked cache'
7 # On some filesystems (e.g. FreeBSD's ext2 and ufs) directory mtime
8 # is updated lazily after contents in the directory changes, which
9 # forces the untracked cache code to take the slow path. A test
10 # that wants to make sure that the fast path works correctly should
11 # call this helper to make mtime of the containing directory in sync
12 # with the reality before checking the fast path behaviour.
14 # See <20160803174522.5571-1-pclouds@gmail.com> if you want to know
17 GIT_FORCE_UNTRACKED_CACHE=true
18 export GIT_FORCE_UNTRACKED_CACHE
21 find . -type d -exec ls -ld {} + >/dev/null
29 git status --porcelain >../status.actual &&
30 test_must_be_empty ../status.actual
33 test_lazy_prereq UNTRACKED_CACHE '
34 { git update-index --test-untracked-cache; ret=$?; } &&
38 if ! test_have_prereq UNTRACKED_CACHE; then
39 skip_all='This system does not support untracked cache'
43 test_expect_success 'core.untrackedCache is unset' '
44 test_must_fail git config --get core.untrackedCache
47 test_expect_success 'setup' '
50 mkdir done dtwo dthree &&
51 touch one two three done/one dtwo/two dthree/three &&
52 git add one two done/one &&
53 : >.git/info/exclude &&
54 git update-index --untracked-cache
57 test_expect_success 'untracked cache is empty' '
58 test-tool dump-untracked-cache >../actual &&
59 cat >../expect-empty <<EOF &&
60 info/exclude 0000000000000000000000000000000000000000
61 core.excludesfile 0000000000000000000000000000000000000000
62 exclude_per_dir .gitignore
65 test_cmp ../expect-empty ../actual
68 cat >../status.expect <<EOF &&
77 cat >../dump.expect <<EOF &&
78 info/exclude $EMPTY_BLOB
79 core.excludesfile 0000000000000000000000000000000000000000
80 exclude_per_dir .gitignore
82 / 0000000000000000000000000000000000000000 recurse valid
86 /done/ 0000000000000000000000000000000000000000 recurse valid
87 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
89 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
93 test_expect_success 'status first time (empty cache)' '
96 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
97 git status --porcelain >../actual &&
98 test_cmp ../status.expect ../actual &&
99 cat >../trace.expect <<EOF &&
101 gitignore invalidation: 1
102 directory invalidation: 0
105 test_cmp ../trace.expect ../trace
108 test_expect_success 'untracked cache after first status' '
109 test-tool dump-untracked-cache >../actual &&
110 test_cmp ../dump.expect ../actual
113 test_expect_success 'status second time (fully populated cache)' '
116 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
117 git status --porcelain >../actual &&
118 test_cmp ../status.expect ../actual &&
119 cat >../trace.expect <<EOF &&
121 gitignore invalidation: 0
122 directory invalidation: 0
125 test_cmp ../trace.expect ../trace
128 test_expect_success 'untracked cache after second status' '
129 test-tool dump-untracked-cache >../actual &&
130 test_cmp ../dump.expect ../actual
133 test_expect_success 'modify in root directory, one dir invalidation' '
137 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
138 git status --porcelain >../actual &&
139 cat >../status.expect <<EOF &&
148 test_cmp ../status.expect ../actual &&
149 cat >../trace.expect <<EOF &&
151 gitignore invalidation: 0
152 directory invalidation: 1
155 test_cmp ../trace.expect ../trace
159 test_expect_success 'verify untracked cache dump' '
160 test-tool dump-untracked-cache >../actual &&
161 cat >../expect <<EOF &&
162 info/exclude $EMPTY_BLOB
163 core.excludesfile 0000000000000000000000000000000000000000
164 exclude_per_dir .gitignore
166 / 0000000000000000000000000000000000000000 recurse valid
171 /done/ 0000000000000000000000000000000000000000 recurse valid
172 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
174 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
177 test_cmp ../expect ../actual
180 test_expect_success 'new .gitignore invalidates recursively' '
182 echo four >.gitignore &&
184 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
185 git status --porcelain >../actual &&
186 cat >../status.expect <<EOF &&
195 test_cmp ../status.expect ../actual &&
196 cat >../trace.expect <<EOF &&
198 gitignore invalidation: 1
199 directory invalidation: 1
202 test_cmp ../trace.expect ../trace
206 test_expect_success 'verify untracked cache dump' '
207 test-tool dump-untracked-cache >../actual &&
208 cat >../expect <<EOF &&
209 info/exclude $EMPTY_BLOB
210 core.excludesfile 0000000000000000000000000000000000000000
211 exclude_per_dir .gitignore
213 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
218 /done/ 0000000000000000000000000000000000000000 recurse valid
219 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
221 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
224 test_cmp ../expect ../actual
227 test_expect_success 'new info/exclude invalidates everything' '
229 echo three >>.git/info/exclude &&
231 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
232 git status --porcelain >../actual &&
233 cat >../status.expect <<EOF &&
240 test_cmp ../status.expect ../actual &&
241 cat >../trace.expect <<EOF &&
243 gitignore invalidation: 1
244 directory invalidation: 0
247 test_cmp ../trace.expect ../trace
250 test_expect_success 'verify untracked cache dump' '
251 test-tool dump-untracked-cache >../actual &&
252 cat >../expect <<EOF &&
253 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
254 core.excludesfile 0000000000000000000000000000000000000000
255 exclude_per_dir .gitignore
257 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
260 /done/ 0000000000000000000000000000000000000000 recurse valid
261 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
262 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
265 test_cmp ../expect ../actual
268 test_expect_success 'move two from tracked to untracked' '
269 git rm --cached two &&
270 test-tool dump-untracked-cache >../actual &&
271 cat >../expect <<EOF &&
272 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
273 core.excludesfile 0000000000000000000000000000000000000000
274 exclude_per_dir .gitignore
276 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
277 /done/ 0000000000000000000000000000000000000000 recurse valid
278 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
279 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
282 test_cmp ../expect ../actual
285 test_expect_success 'status after the move' '
287 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
288 git status --porcelain >../actual &&
289 cat >../status.expect <<EOF &&
296 test_cmp ../status.expect ../actual &&
297 cat >../trace.expect <<EOF &&
299 gitignore invalidation: 0
300 directory invalidation: 0
303 test_cmp ../trace.expect ../trace
306 test_expect_success 'verify untracked cache dump' '
307 test-tool dump-untracked-cache >../actual &&
308 cat >../expect <<EOF &&
309 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
310 core.excludesfile 0000000000000000000000000000000000000000
311 exclude_per_dir .gitignore
313 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
317 /done/ 0000000000000000000000000000000000000000 recurse valid
318 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
319 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
322 test_cmp ../expect ../actual
325 test_expect_success 'move two from untracked to tracked' '
327 test-tool dump-untracked-cache >../actual &&
328 cat >../expect <<EOF &&
329 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
330 core.excludesfile 0000000000000000000000000000000000000000
331 exclude_per_dir .gitignore
333 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
334 /done/ 0000000000000000000000000000000000000000 recurse valid
335 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
336 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
339 test_cmp ../expect ../actual
342 test_expect_success 'status after the move' '
344 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
345 git status --porcelain >../actual &&
346 cat >../status.expect <<EOF &&
353 test_cmp ../status.expect ../actual &&
354 cat >../trace.expect <<EOF &&
356 gitignore invalidation: 0
357 directory invalidation: 0
360 test_cmp ../trace.expect ../trace
363 test_expect_success 'verify untracked cache dump' '
364 test-tool dump-untracked-cache >../actual &&
365 cat >../expect <<EOF &&
366 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
367 core.excludesfile 0000000000000000000000000000000000000000
368 exclude_per_dir .gitignore
370 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
373 /done/ 0000000000000000000000000000000000000000 recurse valid
374 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
375 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
378 test_cmp ../expect ../actual
381 test_expect_success 'set up for sparse checkout testing' '
382 echo two >done/.gitignore &&
383 echo three >>done/.gitignore &&
384 echo two >done/two &&
385 git add -f done/two done/.gitignore &&
386 git commit -m "first commit"
389 test_expect_success 'status after commit' '
391 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
392 git status --porcelain >../actual &&
393 cat >../status.expect <<EOF &&
397 test_cmp ../status.expect ../actual &&
398 cat >../trace.expect <<EOF &&
400 gitignore invalidation: 0
401 directory invalidation: 0
404 test_cmp ../trace.expect ../trace
407 test_expect_success 'untracked cache correct after commit' '
408 test-tool dump-untracked-cache >../actual &&
409 cat >../expect <<EOF &&
410 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
411 core.excludesfile 0000000000000000000000000000000000000000
412 exclude_per_dir .gitignore
414 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
417 /done/ 0000000000000000000000000000000000000000 recurse valid
418 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
419 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
422 test_cmp ../expect ../actual
425 test_expect_success 'set up sparse checkout' '
426 echo "done/[a-z]*" >.git/info/sparse-checkout &&
427 test_config core.sparsecheckout true &&
428 git checkout master &&
429 git update-index --force-untracked-cache &&
430 git status --porcelain >/dev/null && # prime the cache
431 test_path_is_missing done/.gitignore &&
432 test_path_is_file done/one
435 test_expect_success 'create/modify files, some of which are gitignored' '
436 echo two bis >done/two &&
437 echo three >done/three && # three is gitignored
438 echo four >done/four && # four is gitignored at a higher level
439 echo five >done/five && # five is not gitignored
440 echo test >base && #we need to ensure that the root dir is touched
445 test_expect_success 'test sparse status with untracked cache' '
448 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
449 git status --porcelain >../status.actual &&
450 cat >../status.expect <<EOF &&
456 test_cmp ../status.expect ../status.actual &&
457 cat >../trace.expect <<EOF &&
459 gitignore invalidation: 1
460 directory invalidation: 2
463 test_cmp ../trace.expect ../trace
466 test_expect_success 'untracked cache correct after status' '
467 test-tool dump-untracked-cache >../actual &&
468 cat >../expect <<EOF &&
469 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
470 core.excludesfile 0000000000000000000000000000000000000000
471 exclude_per_dir .gitignore
473 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
476 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
478 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
479 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
482 test_cmp ../expect ../actual
485 test_expect_success 'test sparse status again with untracked cache' '
488 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
489 git status --porcelain >../status.actual &&
490 cat >../status.expect <<EOF &&
496 test_cmp ../status.expect ../status.actual &&
497 cat >../trace.expect <<EOF &&
499 gitignore invalidation: 0
500 directory invalidation: 0
503 test_cmp ../trace.expect ../trace
506 test_expect_success 'set up for test of subdir and sparse checkouts' '
508 mkdir done/sub/sub &&
509 echo "sub" > done/sub/sub/file
512 test_expect_success 'test sparse status with untracked cache and subdir' '
515 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
516 git status --porcelain >../status.actual &&
517 cat >../status.expect <<EOF &&
524 test_cmp ../status.expect ../status.actual &&
525 cat >../trace.expect <<EOF &&
527 gitignore invalidation: 0
528 directory invalidation: 1
531 test_cmp ../trace.expect ../trace
534 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
535 test-tool dump-untracked-cache >../actual &&
536 cat >../expect-from-test-dump <<EOF &&
537 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
538 core.excludesfile 0000000000000000000000000000000000000000
539 exclude_per_dir .gitignore
541 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
544 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
547 /done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
549 /done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
551 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
552 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
555 test_cmp ../expect-from-test-dump ../actual
558 test_expect_success 'test sparse status again with untracked cache and subdir' '
561 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
562 git status --porcelain >../status.actual &&
563 test_cmp ../status.expect ../status.actual &&
564 cat >../trace.expect <<EOF &&
566 gitignore invalidation: 0
567 directory invalidation: 0
570 test_cmp ../trace.expect ../trace
573 test_expect_success 'move entry in subdir from untracked to cached' '
575 git status --porcelain >../status.actual &&
576 cat >../status.expect <<EOF &&
583 test_cmp ../status.expect ../status.actual
586 test_expect_success 'move entry in subdir from cached to untracked' '
587 git rm --cached dtwo/two &&
588 git status --porcelain >../status.actual &&
589 cat >../status.expect <<EOF &&
596 test_cmp ../status.expect ../status.actual
599 test_expect_success '--no-untracked-cache removes the cache' '
600 git update-index --no-untracked-cache &&
601 test-tool dump-untracked-cache >../actual &&
602 echo "no untracked cache" >../expect-no-uc &&
603 test_cmp ../expect-no-uc ../actual
606 test_expect_success 'git status does not change anything' '
608 test-tool dump-untracked-cache >../actual &&
609 test_cmp ../expect-no-uc ../actual
612 test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
613 git config core.untrackedCache true &&
614 test-tool dump-untracked-cache >../actual &&
615 test_cmp ../expect-no-uc ../actual &&
617 test-tool dump-untracked-cache >../actual &&
618 test_cmp ../expect-from-test-dump ../actual
621 test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
622 git update-index --no-untracked-cache &&
623 test-tool dump-untracked-cache >../actual &&
624 test_cmp ../expect-no-uc ../actual &&
625 git update-index --untracked-cache &&
626 test-tool dump-untracked-cache >../actual &&
627 test_cmp ../expect-empty ../actual
630 test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
631 git config core.untrackedCache false &&
632 test-tool dump-untracked-cache >../actual &&
633 test_cmp ../expect-empty ../actual &&
635 test-tool dump-untracked-cache >../actual &&
636 test_cmp ../expect-no-uc ../actual
639 test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
640 git update-index --untracked-cache &&
641 test-tool dump-untracked-cache >../actual &&
642 test_cmp ../expect-empty ../actual
645 test_expect_success 'setting core.untrackedCache to keep' '
646 git config core.untrackedCache keep &&
647 git update-index --untracked-cache &&
648 test-tool dump-untracked-cache >../actual &&
649 test_cmp ../expect-empty ../actual &&
651 test-tool dump-untracked-cache >../actual &&
652 test_cmp ../expect-from-test-dump ../actual &&
653 git update-index --no-untracked-cache &&
654 test-tool dump-untracked-cache >../actual &&
655 test_cmp ../expect-no-uc ../actual &&
656 git update-index --force-untracked-cache &&
657 test-tool dump-untracked-cache >../actual &&
658 test_cmp ../expect-empty ../actual &&
660 test-tool dump-untracked-cache >../actual &&
661 test_cmp ../expect-from-test-dump ../actual
664 test_expect_success 'test ident field is working' '
665 mkdir ../other_worktree &&
666 cp -R done dthree dtwo four three ../other_worktree &&
667 GIT_WORK_TREE=../other_worktree git status 2>../err &&
668 echo "warning: untracked cache is disabled on this system or location" >../expect &&
669 test_i18ncmp ../expect ../err
672 test_expect_success 'untracked cache survives a checkout' '
673 git commit --allow-empty -m empty &&
674 test-tool dump-untracked-cache >../before &&
675 test_when_finished "git checkout master" &&
676 git checkout -b other_branch &&
677 test-tool dump-untracked-cache >../after &&
678 test_cmp ../before ../after &&
680 test-tool dump-untracked-cache >../before &&
681 git checkout master &&
682 test-tool dump-untracked-cache >../after &&
683 test_cmp ../before ../after
686 test_expect_success 'untracked cache survives a commit' '
687 test-tool dump-untracked-cache >../before &&
689 git commit -m commit &&
690 test-tool dump-untracked-cache >../after &&
691 test_cmp ../before ../after
694 test_expect_success 'teardown worktree' '
698 test_expect_success SYMLINKS 'setup worktree for symlink test' '
699 git init worktree-symlink &&
700 cd worktree-symlink &&
701 git config core.untrackedCache true &&
703 touch one/file two/file &&
704 git add one/file two/file &&
705 git commit -m"first commit" &&
709 git commit -m"second commit"
712 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
713 git checkout HEAD~ &&
716 git checkout master &&
722 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
723 git config core.untrackedCache false &&
724 git checkout HEAD~ &&
727 git checkout master &&
733 test_expect_success 'setup worktree for non-symlink test' '
734 git init worktree-non-symlink &&
735 cd worktree-non-symlink &&
736 git config core.untrackedCache true &&
738 touch one/file two/file &&
739 git add one/file two/file &&
740 git commit -m"first commit" &&
744 git commit -m"second commit"
747 test_expect_success '"status" after file replacement should be clean with UC=true' '
748 git checkout HEAD~ &&
751 git checkout master &&
754 test-tool dump-untracked-cache >../actual &&
755 grep -F "recurse valid" ../actual >../actual.grep &&
756 cat >../expect.grep <<EOF &&
757 / 0000000000000000000000000000000000000000 recurse valid
758 /two/ 0000000000000000000000000000000000000000 recurse valid
761 test_cmp ../expect.grep ../actual.grep
764 test_expect_success '"status" after file replacement should be clean with UC=false' '
765 git config core.untrackedCache false &&
766 git checkout HEAD~ &&
769 git checkout master &&