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
18 find . -type d -ls >/dev/null
27 git status --porcelain >../status.actual &&
28 test_cmp ../status.expect ../status.actual
31 test_lazy_prereq UNTRACKED_CACHE '
32 { git update-index --test-untracked-cache; ret=$?; } &&
36 if ! test_have_prereq UNTRACKED_CACHE; then
37 skip_all='This system does not support untracked cache'
41 test_expect_success 'core.untrackedCache is unset' '
42 test_must_fail git config --get core.untrackedCache
45 test_expect_success 'setup' '
48 mkdir done dtwo dthree &&
49 touch one two three done/one dtwo/two dthree/three &&
50 git add one two done/one &&
51 : >.git/info/exclude &&
52 git update-index --untracked-cache
55 test_expect_success 'untracked cache is empty' '
56 test-dump-untracked-cache >../actual &&
57 cat >../expect-empty <<EOF &&
58 info/exclude 0000000000000000000000000000000000000000
59 core.excludesfile 0000000000000000000000000000000000000000
60 exclude_per_dir .gitignore
63 test_cmp ../expect-empty ../actual
66 cat >../status.expect <<EOF &&
75 cat >../dump.expect <<EOF &&
76 info/exclude $EMPTY_BLOB
77 core.excludesfile 0000000000000000000000000000000000000000
78 exclude_per_dir .gitignore
80 / 0000000000000000000000000000000000000000 recurse valid
84 /done/ 0000000000000000000000000000000000000000 recurse valid
85 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
87 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
91 test_expect_success 'status first time (empty cache)' '
94 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
95 git status --porcelain >../actual &&
96 test_cmp ../status.expect ../actual &&
97 cat >../trace.expect <<EOF &&
99 gitignore invalidation: 1
100 directory invalidation: 0
103 test_cmp ../trace.expect ../trace
106 test_expect_success 'untracked cache after first status' '
107 test-dump-untracked-cache >../actual &&
108 test_cmp ../dump.expect ../actual
111 test_expect_success 'status second time (fully populated cache)' '
114 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
115 git status --porcelain >../actual &&
116 test_cmp ../status.expect ../actual &&
117 cat >../trace.expect <<EOF &&
119 gitignore invalidation: 0
120 directory invalidation: 0
123 test_cmp ../trace.expect ../trace
126 test_expect_success 'untracked cache after second status' '
127 test-dump-untracked-cache >../actual &&
128 test_cmp ../dump.expect ../actual
131 test_expect_success 'modify in root directory, one dir invalidation' '
135 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
136 git status --porcelain >../actual &&
137 cat >../status.expect <<EOF &&
146 test_cmp ../status.expect ../actual &&
147 cat >../trace.expect <<EOF &&
149 gitignore invalidation: 0
150 directory invalidation: 1
153 test_cmp ../trace.expect ../trace
157 test_expect_success 'verify untracked cache dump' '
158 test-dump-untracked-cache >../actual &&
159 cat >../expect <<EOF &&
160 info/exclude $EMPTY_BLOB
161 core.excludesfile 0000000000000000000000000000000000000000
162 exclude_per_dir .gitignore
164 / 0000000000000000000000000000000000000000 recurse valid
169 /done/ 0000000000000000000000000000000000000000 recurse valid
170 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
172 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
175 test_cmp ../expect ../actual
178 test_expect_success 'new .gitignore invalidates recursively' '
180 echo four >.gitignore &&
182 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
183 git status --porcelain >../actual &&
184 cat >../status.expect <<EOF &&
193 test_cmp ../status.expect ../actual &&
194 cat >../trace.expect <<EOF &&
196 gitignore invalidation: 1
197 directory invalidation: 1
200 test_cmp ../trace.expect ../trace
204 test_expect_success 'verify untracked cache dump' '
205 test-dump-untracked-cache >../actual &&
206 cat >../expect <<EOF &&
207 info/exclude $EMPTY_BLOB
208 core.excludesfile 0000000000000000000000000000000000000000
209 exclude_per_dir .gitignore
211 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
216 /done/ 0000000000000000000000000000000000000000 recurse valid
217 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
219 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
222 test_cmp ../expect ../actual
225 test_expect_success 'new info/exclude invalidates everything' '
227 echo three >>.git/info/exclude &&
229 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
230 git status --porcelain >../actual &&
231 cat >../status.expect <<EOF &&
238 test_cmp ../status.expect ../actual &&
239 cat >../trace.expect <<EOF &&
241 gitignore invalidation: 1
242 directory invalidation: 0
245 test_cmp ../trace.expect ../trace
248 test_expect_success 'verify untracked cache dump' '
249 test-dump-untracked-cache >../actual &&
250 cat >../expect <<EOF &&
251 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
252 core.excludesfile 0000000000000000000000000000000000000000
253 exclude_per_dir .gitignore
255 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
258 /done/ 0000000000000000000000000000000000000000 recurse valid
259 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
260 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
263 test_cmp ../expect ../actual
266 test_expect_success 'move two from tracked to untracked' '
267 git rm --cached two &&
268 test-dump-untracked-cache >../actual &&
269 cat >../expect <<EOF &&
270 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
271 core.excludesfile 0000000000000000000000000000000000000000
272 exclude_per_dir .gitignore
274 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
275 /done/ 0000000000000000000000000000000000000000 recurse valid
276 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
277 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
280 test_cmp ../expect ../actual
283 test_expect_success 'status after the move' '
285 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
286 git status --porcelain >../actual &&
287 cat >../status.expect <<EOF &&
294 test_cmp ../status.expect ../actual &&
295 cat >../trace.expect <<EOF &&
297 gitignore invalidation: 0
298 directory invalidation: 0
301 test_cmp ../trace.expect ../trace
304 test_expect_success 'verify untracked cache dump' '
305 test-dump-untracked-cache >../actual &&
306 cat >../expect <<EOF &&
307 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
308 core.excludesfile 0000000000000000000000000000000000000000
309 exclude_per_dir .gitignore
311 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
315 /done/ 0000000000000000000000000000000000000000 recurse valid
316 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
317 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
320 test_cmp ../expect ../actual
323 test_expect_success 'move two from untracked to tracked' '
325 test-dump-untracked-cache >../actual &&
326 cat >../expect <<EOF &&
327 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
328 core.excludesfile 0000000000000000000000000000000000000000
329 exclude_per_dir .gitignore
331 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
332 /done/ 0000000000000000000000000000000000000000 recurse valid
333 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
334 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
337 test_cmp ../expect ../actual
340 test_expect_success 'status after the move' '
342 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
343 git status --porcelain >../actual &&
344 cat >../status.expect <<EOF &&
351 test_cmp ../status.expect ../actual &&
352 cat >../trace.expect <<EOF &&
354 gitignore invalidation: 0
355 directory invalidation: 0
358 test_cmp ../trace.expect ../trace
361 test_expect_success 'verify untracked cache dump' '
362 test-dump-untracked-cache >../actual &&
363 cat >../expect <<EOF &&
364 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
365 core.excludesfile 0000000000000000000000000000000000000000
366 exclude_per_dir .gitignore
368 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
371 /done/ 0000000000000000000000000000000000000000 recurse valid
372 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
373 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
376 test_cmp ../expect ../actual
379 test_expect_success 'set up for sparse checkout testing' '
380 echo two >done/.gitignore &&
381 echo three >>done/.gitignore &&
382 echo two >done/two &&
383 git add -f done/two done/.gitignore &&
384 git commit -m "first commit"
387 test_expect_success 'status after commit' '
389 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
390 git status --porcelain >../actual &&
391 cat >../status.expect <<EOF &&
395 test_cmp ../status.expect ../actual &&
396 cat >../trace.expect <<EOF &&
398 gitignore invalidation: 0
399 directory invalidation: 0
402 test_cmp ../trace.expect ../trace
405 test_expect_success 'untracked cache correct after commit' '
406 test-dump-untracked-cache >../actual &&
407 cat >../expect <<EOF &&
408 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
409 core.excludesfile 0000000000000000000000000000000000000000
410 exclude_per_dir .gitignore
412 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
415 /done/ 0000000000000000000000000000000000000000 recurse valid
416 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
417 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
420 test_cmp ../expect ../actual
423 test_expect_success 'set up sparse checkout' '
424 echo "done/[a-z]*" >.git/info/sparse-checkout &&
425 test_config core.sparsecheckout true &&
426 git checkout master &&
427 git update-index --force-untracked-cache &&
428 git status --porcelain >/dev/null && # prime the cache
429 test_path_is_missing done/.gitignore &&
430 test_path_is_file done/one
433 test_expect_success 'create/modify files, some of which are gitignored' '
434 echo two bis >done/two &&
435 echo three >done/three && # three is gitignored
436 echo four >done/four && # four is gitignored at a higher level
437 echo five >done/five && # five is not gitignored
438 echo test >base && #we need to ensure that the root dir is touched
443 test_expect_success 'test sparse status with untracked cache' '
446 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
447 git status --porcelain >../status.actual &&
448 cat >../status.expect <<EOF &&
454 test_cmp ../status.expect ../status.actual &&
455 cat >../trace.expect <<EOF &&
457 gitignore invalidation: 1
458 directory invalidation: 2
461 test_cmp ../trace.expect ../trace
464 test_expect_success 'untracked cache correct after status' '
465 test-dump-untracked-cache >../actual &&
466 cat >../expect <<EOF &&
467 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
468 core.excludesfile 0000000000000000000000000000000000000000
469 exclude_per_dir .gitignore
471 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
474 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
476 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
477 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
480 test_cmp ../expect ../actual
483 test_expect_success 'test sparse status again with untracked cache' '
486 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
487 git status --porcelain >../status.actual &&
488 cat >../status.expect <<EOF &&
494 test_cmp ../status.expect ../status.actual &&
495 cat >../trace.expect <<EOF &&
497 gitignore invalidation: 0
498 directory invalidation: 0
501 test_cmp ../trace.expect ../trace
504 test_expect_success 'set up for test of subdir and sparse checkouts' '
506 mkdir done/sub/sub &&
507 echo "sub" > done/sub/sub/file
510 test_expect_success 'test sparse status with untracked cache and subdir' '
513 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
514 git status --porcelain >../status.actual &&
515 cat >../status.expect <<EOF &&
522 test_cmp ../status.expect ../status.actual &&
523 cat >../trace.expect <<EOF &&
525 gitignore invalidation: 0
526 directory invalidation: 1
529 test_cmp ../trace.expect ../trace
532 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
533 test-dump-untracked-cache >../actual &&
534 cat >../expect-from-test-dump <<EOF &&
535 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
536 core.excludesfile 0000000000000000000000000000000000000000
537 exclude_per_dir .gitignore
539 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
542 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
545 /done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
547 /done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
549 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
550 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
553 test_cmp ../expect-from-test-dump ../actual
556 test_expect_success 'test sparse status again with untracked cache and subdir' '
559 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
560 git status --porcelain >../status.actual &&
561 test_cmp ../status.expect ../status.actual &&
562 cat >../trace.expect <<EOF &&
564 gitignore invalidation: 0
565 directory invalidation: 0
568 test_cmp ../trace.expect ../trace
571 test_expect_success 'move entry in subdir from untracked to cached' '
573 git status --porcelain >../status.actual &&
574 cat >../status.expect <<EOF &&
581 test_cmp ../status.expect ../status.actual
584 test_expect_success 'move entry in subdir from cached to untracked' '
585 git rm --cached dtwo/two &&
586 git status --porcelain >../status.actual &&
587 cat >../status.expect <<EOF &&
594 test_cmp ../status.expect ../status.actual
597 test_expect_success '--no-untracked-cache removes the cache' '
598 git update-index --no-untracked-cache &&
599 test-dump-untracked-cache >../actual &&
600 echo "no untracked cache" >../expect-no-uc &&
601 test_cmp ../expect-no-uc ../actual
604 test_expect_success 'git status does not change anything' '
606 test-dump-untracked-cache >../actual &&
607 test_cmp ../expect-no-uc ../actual
610 test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
611 git config core.untrackedCache true &&
612 test-dump-untracked-cache >../actual &&
613 test_cmp ../expect-no-uc ../actual &&
615 test-dump-untracked-cache >../actual &&
616 test_cmp ../expect-from-test-dump ../actual
619 test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
620 git update-index --no-untracked-cache &&
621 test-dump-untracked-cache >../actual &&
622 test_cmp ../expect-no-uc ../actual &&
623 git update-index --untracked-cache &&
624 test-dump-untracked-cache >../actual &&
625 test_cmp ../expect-empty ../actual
628 test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
629 git config core.untrackedCache false &&
630 test-dump-untracked-cache >../actual &&
631 test_cmp ../expect-empty ../actual &&
633 test-dump-untracked-cache >../actual &&
634 test_cmp ../expect-no-uc ../actual
637 test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
638 git update-index --untracked-cache &&
639 test-dump-untracked-cache >../actual &&
640 test_cmp ../expect-empty ../actual
643 test_expect_success 'setting core.untrackedCache to keep' '
644 git config core.untrackedCache keep &&
645 git update-index --untracked-cache &&
646 test-dump-untracked-cache >../actual &&
647 test_cmp ../expect-empty ../actual &&
649 test-dump-untracked-cache >../actual &&
650 test_cmp ../expect-from-test-dump ../actual &&
651 git update-index --no-untracked-cache &&
652 test-dump-untracked-cache >../actual &&
653 test_cmp ../expect-no-uc ../actual &&
654 git update-index --force-untracked-cache &&
655 test-dump-untracked-cache >../actual &&
656 test_cmp ../expect-empty ../actual &&
658 test-dump-untracked-cache >../actual &&
659 test_cmp ../expect-from-test-dump ../actual
662 test_expect_success 'test ident field is working' '
663 mkdir ../other_worktree &&
664 cp -R done dthree dtwo four three ../other_worktree &&
665 GIT_WORK_TREE=../other_worktree git status 2>../err &&
666 echo "warning: Untracked cache is disabled on this system or location." >../expect &&
667 test_i18ncmp ../expect ../err
670 test_expect_success 'untracked cache survives a checkout' '
671 git commit --allow-empty -m empty &&
672 test-dump-untracked-cache >../before &&
673 test_when_finished "git checkout master" &&
674 git checkout -b other_branch &&
675 test-dump-untracked-cache >../after &&
676 test_cmp ../before ../after &&
678 test-dump-untracked-cache >../before &&
679 git checkout master &&
680 test-dump-untracked-cache >../after &&
681 test_cmp ../before ../after
684 test_expect_success 'untracked cache survives a commit' '
685 test-dump-untracked-cache >../before &&
687 git commit -m commit &&
688 test-dump-untracked-cache >../after &&
689 test_cmp ../before ../after
692 test_expect_success 'teardown worktree' '
696 test_expect_success SYMLINKS 'setup worktree for symlink test' '
697 git init worktree-symlink &&
698 cd worktree-symlink &&
699 git config core.untrackedCache true &&
701 touch one/file two/file &&
702 git add one/file two/file &&
703 git commit -m"first commit" &&
707 git commit -m"second commit"
710 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
711 git checkout HEAD~ &&
714 git checkout master &&
720 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
721 git config core.untrackedCache false &&
722 git checkout HEAD~ &&
725 git checkout master &&
731 test_expect_success 'setup worktree for non-symlink test' '
732 git init worktree-non-symlink &&
733 cd worktree-non-symlink &&
734 git config core.untrackedCache true &&
736 touch one/file two/file &&
737 git add one/file two/file &&
738 git commit -m"first commit" &&
742 git commit -m"second commit"
745 test_expect_success '"status" after file replacement should be clean with UC=true' '
746 git checkout HEAD~ &&
749 git checkout master &&
752 test-dump-untracked-cache >../actual &&
753 grep -F "recurse valid" ../actual >../actual.grep &&
754 cat >../expect.grep <<EOF &&
755 / 0000000000000000000000000000000000000000 recurse valid
756 /two/ 0000000000000000000000000000000000000000 recurse valid
759 test_cmp ../expect.grep ../actual.grep
762 test_expect_success '"status" after file replacement should be clean with UC=false' '
763 git config core.untrackedCache false &&
764 git checkout HEAD~ &&
767 git checkout master &&