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 -ls >/dev/null
30 git status --porcelain >../status.actual &&
31 test_cmp ../status.expect ../status.actual
34 test_lazy_prereq UNTRACKED_CACHE '
35 { git update-index --test-untracked-cache; ret=$?; } &&
39 if ! test_have_prereq UNTRACKED_CACHE; then
40 skip_all='This system does not support untracked cache'
44 test_expect_success 'core.untrackedCache is unset' '
45 test_must_fail git config --get core.untrackedCache
48 test_expect_success 'setup' '
51 mkdir done dtwo dthree &&
52 touch one two three done/one dtwo/two dthree/three &&
53 git add one two done/one &&
54 : >.git/info/exclude &&
55 git update-index --untracked-cache
58 test_expect_success 'untracked cache is empty' '
59 test-dump-untracked-cache >../actual &&
60 cat >../expect-empty <<EOF &&
61 info/exclude 0000000000000000000000000000000000000000
62 core.excludesfile 0000000000000000000000000000000000000000
63 exclude_per_dir .gitignore
66 test_cmp ../expect-empty ../actual
69 cat >../status.expect <<EOF &&
78 cat >../dump.expect <<EOF &&
79 info/exclude $EMPTY_BLOB
80 core.excludesfile 0000000000000000000000000000000000000000
81 exclude_per_dir .gitignore
83 / 0000000000000000000000000000000000000000 recurse valid
87 /done/ 0000000000000000000000000000000000000000 recurse valid
88 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
90 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
94 test_expect_success 'status first time (empty cache)' '
97 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
98 git status --porcelain >../actual &&
99 test_cmp ../status.expect ../actual &&
100 cat >../trace.expect <<EOF &&
102 gitignore invalidation: 1
103 directory invalidation: 0
106 test_cmp ../trace.expect ../trace
109 test_expect_success 'untracked cache after first status' '
110 test-dump-untracked-cache >../actual &&
111 test_cmp ../dump.expect ../actual
114 test_expect_success 'status second time (fully populated cache)' '
117 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
118 git status --porcelain >../actual &&
119 test_cmp ../status.expect ../actual &&
120 cat >../trace.expect <<EOF &&
122 gitignore invalidation: 0
123 directory invalidation: 0
126 test_cmp ../trace.expect ../trace
129 test_expect_success 'untracked cache after second status' '
130 test-dump-untracked-cache >../actual &&
131 test_cmp ../dump.expect ../actual
134 test_expect_success 'modify in root directory, one dir invalidation' '
138 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
139 git status --porcelain >../actual &&
140 cat >../status.expect <<EOF &&
149 test_cmp ../status.expect ../actual &&
150 cat >../trace.expect <<EOF &&
152 gitignore invalidation: 0
153 directory invalidation: 1
156 test_cmp ../trace.expect ../trace
160 test_expect_success 'verify untracked cache dump' '
161 test-dump-untracked-cache >../actual &&
162 cat >../expect <<EOF &&
163 info/exclude $EMPTY_BLOB
164 core.excludesfile 0000000000000000000000000000000000000000
165 exclude_per_dir .gitignore
167 / 0000000000000000000000000000000000000000 recurse valid
172 /done/ 0000000000000000000000000000000000000000 recurse valid
173 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
175 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
178 test_cmp ../expect ../actual
181 test_expect_success 'new .gitignore invalidates recursively' '
183 echo four >.gitignore &&
185 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
186 git status --porcelain >../actual &&
187 cat >../status.expect <<EOF &&
196 test_cmp ../status.expect ../actual &&
197 cat >../trace.expect <<EOF &&
199 gitignore invalidation: 1
200 directory invalidation: 1
203 test_cmp ../trace.expect ../trace
207 test_expect_success 'verify untracked cache dump' '
208 test-dump-untracked-cache >../actual &&
209 cat >../expect <<EOF &&
210 info/exclude $EMPTY_BLOB
211 core.excludesfile 0000000000000000000000000000000000000000
212 exclude_per_dir .gitignore
214 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
219 /done/ 0000000000000000000000000000000000000000 recurse valid
220 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
222 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
225 test_cmp ../expect ../actual
228 test_expect_success 'new info/exclude invalidates everything' '
230 echo three >>.git/info/exclude &&
232 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
233 git status --porcelain >../actual &&
234 cat >../status.expect <<EOF &&
241 test_cmp ../status.expect ../actual &&
242 cat >../trace.expect <<EOF &&
244 gitignore invalidation: 1
245 directory invalidation: 0
248 test_cmp ../trace.expect ../trace
251 test_expect_success 'verify untracked cache dump' '
252 test-dump-untracked-cache >../actual &&
253 cat >../expect <<EOF &&
254 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
255 core.excludesfile 0000000000000000000000000000000000000000
256 exclude_per_dir .gitignore
258 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
261 /done/ 0000000000000000000000000000000000000000 recurse valid
262 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
263 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
266 test_cmp ../expect ../actual
269 test_expect_success 'move two from tracked to untracked' '
270 git rm --cached two &&
271 test-dump-untracked-cache >../actual &&
272 cat >../expect <<EOF &&
273 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
274 core.excludesfile 0000000000000000000000000000000000000000
275 exclude_per_dir .gitignore
277 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
278 /done/ 0000000000000000000000000000000000000000 recurse valid
279 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
280 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
283 test_cmp ../expect ../actual
286 test_expect_success 'status after the move' '
288 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
289 git status --porcelain >../actual &&
290 cat >../status.expect <<EOF &&
297 test_cmp ../status.expect ../actual &&
298 cat >../trace.expect <<EOF &&
300 gitignore invalidation: 0
301 directory invalidation: 0
304 test_cmp ../trace.expect ../trace
307 test_expect_success 'verify untracked cache dump' '
308 test-dump-untracked-cache >../actual &&
309 cat >../expect <<EOF &&
310 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
311 core.excludesfile 0000000000000000000000000000000000000000
312 exclude_per_dir .gitignore
314 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
318 /done/ 0000000000000000000000000000000000000000 recurse valid
319 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
320 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
323 test_cmp ../expect ../actual
326 test_expect_success 'move two from untracked to tracked' '
328 test-dump-untracked-cache >../actual &&
329 cat >../expect <<EOF &&
330 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
331 core.excludesfile 0000000000000000000000000000000000000000
332 exclude_per_dir .gitignore
334 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
335 /done/ 0000000000000000000000000000000000000000 recurse valid
336 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
337 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
340 test_cmp ../expect ../actual
343 test_expect_success 'status after the move' '
345 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
346 git status --porcelain >../actual &&
347 cat >../status.expect <<EOF &&
354 test_cmp ../status.expect ../actual &&
355 cat >../trace.expect <<EOF &&
357 gitignore invalidation: 0
358 directory invalidation: 0
361 test_cmp ../trace.expect ../trace
364 test_expect_success 'verify untracked cache dump' '
365 test-dump-untracked-cache >../actual &&
366 cat >../expect <<EOF &&
367 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
368 core.excludesfile 0000000000000000000000000000000000000000
369 exclude_per_dir .gitignore
371 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
374 /done/ 0000000000000000000000000000000000000000 recurse valid
375 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
376 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
379 test_cmp ../expect ../actual
382 test_expect_success 'set up for sparse checkout testing' '
383 echo two >done/.gitignore &&
384 echo three >>done/.gitignore &&
385 echo two >done/two &&
386 git add -f done/two done/.gitignore &&
387 git commit -m "first commit"
390 test_expect_success 'status after commit' '
392 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
393 git status --porcelain >../actual &&
394 cat >../status.expect <<EOF &&
398 test_cmp ../status.expect ../actual &&
399 cat >../trace.expect <<EOF &&
401 gitignore invalidation: 0
402 directory invalidation: 0
405 test_cmp ../trace.expect ../trace
408 test_expect_success 'untracked cache correct after commit' '
409 test-dump-untracked-cache >../actual &&
410 cat >../expect <<EOF &&
411 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
412 core.excludesfile 0000000000000000000000000000000000000000
413 exclude_per_dir .gitignore
415 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
418 /done/ 0000000000000000000000000000000000000000 recurse valid
419 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
420 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
423 test_cmp ../expect ../actual
426 test_expect_success 'set up sparse checkout' '
427 echo "done/[a-z]*" >.git/info/sparse-checkout &&
428 test_config core.sparsecheckout true &&
429 git checkout master &&
430 git update-index --force-untracked-cache &&
431 git status --porcelain >/dev/null && # prime the cache
432 test_path_is_missing done/.gitignore &&
433 test_path_is_file done/one
436 test_expect_success 'create/modify files, some of which are gitignored' '
437 echo two bis >done/two &&
438 echo three >done/three && # three is gitignored
439 echo four >done/four && # four is gitignored at a higher level
440 echo five >done/five && # five is not gitignored
441 echo test >base && #we need to ensure that the root dir is touched
446 test_expect_success 'test sparse status with untracked cache' '
449 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
450 git status --porcelain >../status.actual &&
451 cat >../status.expect <<EOF &&
457 test_cmp ../status.expect ../status.actual &&
458 cat >../trace.expect <<EOF &&
460 gitignore invalidation: 1
461 directory invalidation: 2
464 test_cmp ../trace.expect ../trace
467 test_expect_success 'untracked cache correct after status' '
468 test-dump-untracked-cache >../actual &&
469 cat >../expect <<EOF &&
470 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
471 core.excludesfile 0000000000000000000000000000000000000000
472 exclude_per_dir .gitignore
474 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
477 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
479 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
480 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
483 test_cmp ../expect ../actual
486 test_expect_success 'test sparse status again with untracked cache' '
489 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
490 git status --porcelain >../status.actual &&
491 cat >../status.expect <<EOF &&
497 test_cmp ../status.expect ../status.actual &&
498 cat >../trace.expect <<EOF &&
500 gitignore invalidation: 0
501 directory invalidation: 0
504 test_cmp ../trace.expect ../trace
507 test_expect_success 'set up for test of subdir and sparse checkouts' '
509 mkdir done/sub/sub &&
510 echo "sub" > done/sub/sub/file
513 test_expect_success 'test sparse status with untracked cache and subdir' '
516 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
517 git status --porcelain >../status.actual &&
518 cat >../status.expect <<EOF &&
525 test_cmp ../status.expect ../status.actual &&
526 cat >../trace.expect <<EOF &&
528 gitignore invalidation: 0
529 directory invalidation: 1
532 test_cmp ../trace.expect ../trace
535 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
536 test-dump-untracked-cache >../actual &&
537 cat >../expect-from-test-dump <<EOF &&
538 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
539 core.excludesfile 0000000000000000000000000000000000000000
540 exclude_per_dir .gitignore
542 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
545 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
548 /done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
550 /done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
552 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
553 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
556 test_cmp ../expect-from-test-dump ../actual
559 test_expect_success 'test sparse status again with untracked cache and subdir' '
562 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
563 git status --porcelain >../status.actual &&
564 test_cmp ../status.expect ../status.actual &&
565 cat >../trace.expect <<EOF &&
567 gitignore invalidation: 0
568 directory invalidation: 0
571 test_cmp ../trace.expect ../trace
574 test_expect_success 'move entry in subdir from untracked to cached' '
576 git status --porcelain >../status.actual &&
577 cat >../status.expect <<EOF &&
584 test_cmp ../status.expect ../status.actual
587 test_expect_success 'move entry in subdir from cached to untracked' '
588 git rm --cached dtwo/two &&
589 git status --porcelain >../status.actual &&
590 cat >../status.expect <<EOF &&
597 test_cmp ../status.expect ../status.actual
600 test_expect_success '--no-untracked-cache removes the cache' '
601 git update-index --no-untracked-cache &&
602 test-dump-untracked-cache >../actual &&
603 echo "no untracked cache" >../expect-no-uc &&
604 test_cmp ../expect-no-uc ../actual
607 test_expect_success 'git status does not change anything' '
609 test-dump-untracked-cache >../actual &&
610 test_cmp ../expect-no-uc ../actual
613 test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
614 git config core.untrackedCache true &&
615 test-dump-untracked-cache >../actual &&
616 test_cmp ../expect-no-uc ../actual &&
618 test-dump-untracked-cache >../actual &&
619 test_cmp ../expect-from-test-dump ../actual
622 test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
623 git update-index --no-untracked-cache &&
624 test-dump-untracked-cache >../actual &&
625 test_cmp ../expect-no-uc ../actual &&
626 git update-index --untracked-cache &&
627 test-dump-untracked-cache >../actual &&
628 test_cmp ../expect-empty ../actual
631 test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
632 git config core.untrackedCache false &&
633 test-dump-untracked-cache >../actual &&
634 test_cmp ../expect-empty ../actual &&
636 test-dump-untracked-cache >../actual &&
637 test_cmp ../expect-no-uc ../actual
640 test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
641 git update-index --untracked-cache &&
642 test-dump-untracked-cache >../actual &&
643 test_cmp ../expect-empty ../actual
646 test_expect_success 'setting core.untrackedCache to keep' '
647 git config core.untrackedCache keep &&
648 git update-index --untracked-cache &&
649 test-dump-untracked-cache >../actual &&
650 test_cmp ../expect-empty ../actual &&
652 test-dump-untracked-cache >../actual &&
653 test_cmp ../expect-from-test-dump ../actual &&
654 git update-index --no-untracked-cache &&
655 test-dump-untracked-cache >../actual &&
656 test_cmp ../expect-no-uc ../actual &&
657 git update-index --force-untracked-cache &&
658 test-dump-untracked-cache >../actual &&
659 test_cmp ../expect-empty ../actual &&
661 test-dump-untracked-cache >../actual &&
662 test_cmp ../expect-from-test-dump ../actual
665 test_expect_success 'test ident field is working' '
666 mkdir ../other_worktree &&
667 cp -R done dthree dtwo four three ../other_worktree &&
668 GIT_WORK_TREE=../other_worktree git status 2>../err &&
669 echo "warning: untracked cache is disabled on this system or location" >../expect &&
670 test_i18ncmp ../expect ../err
673 test_expect_success 'untracked cache survives a checkout' '
674 git commit --allow-empty -m empty &&
675 test-dump-untracked-cache >../before &&
676 test_when_finished "git checkout master" &&
677 git checkout -b other_branch &&
678 test-dump-untracked-cache >../after &&
679 test_cmp ../before ../after &&
681 test-dump-untracked-cache >../before &&
682 git checkout master &&
683 test-dump-untracked-cache >../after &&
684 test_cmp ../before ../after
687 test_expect_success 'untracked cache survives a commit' '
688 test-dump-untracked-cache >../before &&
690 git commit -m commit &&
691 test-dump-untracked-cache >../after &&
692 test_cmp ../before ../after
695 test_expect_success 'teardown worktree' '
699 test_expect_success SYMLINKS 'setup worktree for symlink test' '
700 git init worktree-symlink &&
701 cd worktree-symlink &&
702 git config core.untrackedCache true &&
704 touch one/file two/file &&
705 git add one/file two/file &&
706 git commit -m"first commit" &&
710 git commit -m"second commit"
713 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
714 git checkout HEAD~ &&
717 git checkout master &&
723 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
724 git config core.untrackedCache false &&
725 git checkout HEAD~ &&
728 git checkout master &&
734 test_expect_success 'setup worktree for non-symlink test' '
735 git init worktree-non-symlink &&
736 cd worktree-non-symlink &&
737 git config core.untrackedCache true &&
739 touch one/file two/file &&
740 git add one/file two/file &&
741 git commit -m"first commit" &&
745 git commit -m"second commit"
748 test_expect_success '"status" after file replacement should be clean with UC=true' '
749 git checkout HEAD~ &&
752 git checkout master &&
755 test-dump-untracked-cache >../actual &&
756 grep -F "recurse valid" ../actual >../actual.grep &&
757 cat >../expect.grep <<EOF &&
758 / 0000000000000000000000000000000000000000 recurse valid
759 /two/ 0000000000000000000000000000000000000000 recurse valid
762 test_cmp ../expect.grep ../actual.grep
765 test_expect_success '"status" after file replacement should be clean with UC=false' '
766 git config core.untrackedCache false &&
767 git checkout HEAD~ &&
770 git checkout master &&