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 # Ignore_Untracked_Cache, abbreviated to 3 letters because then people can
34 # compare commands side-by-side, e.g.
35 # iuc status --porcelain >expect &&
36 # git status --porcelain >actual &&
37 # test_cmp expect actual
39 git ls-files -s >../current-index-entries
40 git ls-files -t | sed -ne s/^S.//p >../current-sparse-entries
42 GIT_INDEX_FILE=.git/tmp_index
44 git update-index --index-info <../current-index-entries
45 git update-index --skip-worktree $(cat ../current-sparse-entries)
47 git -c core.untrackedCache=false "$@"
50 rm ../current-index-entries
57 test_lazy_prereq UNTRACKED_CACHE '
58 { git update-index --test-untracked-cache; ret=$?; } &&
62 if ! test_have_prereq UNTRACKED_CACHE; then
63 skip_all='This system does not support untracked cache'
67 test_expect_success 'core.untrackedCache is unset' '
68 test_must_fail git config --get core.untrackedCache
71 test_expect_success 'setup' '
74 mkdir done dtwo dthree &&
75 touch one two three done/one dtwo/two dthree/three &&
76 git add one two done/one &&
77 : >.git/info/exclude &&
78 git update-index --untracked-cache
81 test_expect_success 'untracked cache is empty' '
82 test-tool dump-untracked-cache >../actual &&
83 cat >../expect-empty <<EOF &&
84 info/exclude 0000000000000000000000000000000000000000
85 core.excludesfile 0000000000000000000000000000000000000000
86 exclude_per_dir .gitignore
89 test_cmp ../expect-empty ../actual
92 cat >../status.expect <<EOF &&
101 cat >../dump.expect <<EOF &&
102 info/exclude $EMPTY_BLOB
103 core.excludesfile 0000000000000000000000000000000000000000
104 exclude_per_dir .gitignore
106 / 0000000000000000000000000000000000000000 recurse valid
110 /done/ 0000000000000000000000000000000000000000 recurse valid
111 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
113 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
117 test_expect_success 'status first time (empty cache)' '
120 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
121 git status --porcelain >../actual &&
122 iuc status --porcelain >../status.iuc &&
123 test_cmp ../status.expect ../status.iuc &&
124 test_cmp ../status.expect ../actual &&
125 cat >../trace.expect <<EOF &&
127 gitignore invalidation: 1
128 directory invalidation: 0
131 test_cmp ../trace.expect ../trace
134 test_expect_success 'untracked cache after first status' '
135 test-tool dump-untracked-cache >../actual &&
136 test_cmp ../dump.expect ../actual
139 test_expect_success 'status second time (fully populated cache)' '
142 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
143 git status --porcelain >../actual &&
144 iuc status --porcelain >../status.iuc &&
145 test_cmp ../status.expect ../status.iuc &&
146 test_cmp ../status.expect ../actual &&
147 cat >../trace.expect <<EOF &&
149 gitignore invalidation: 0
150 directory invalidation: 0
153 test_cmp ../trace.expect ../trace
156 test_expect_success 'untracked cache after second status' '
157 test-tool dump-untracked-cache >../actual &&
158 test_cmp ../dump.expect ../actual
161 test_expect_success 'modify in root directory, one dir invalidation' '
165 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
166 git status --porcelain >../actual &&
167 iuc status --porcelain >../status.iuc &&
168 cat >../status.expect <<EOF &&
177 test_cmp ../status.expect ../status.iuc &&
178 test_cmp ../status.expect ../actual &&
179 cat >../trace.expect <<EOF &&
181 gitignore invalidation: 0
182 directory invalidation: 1
185 test_cmp ../trace.expect ../trace
189 test_expect_success 'verify untracked cache dump' '
190 test-tool dump-untracked-cache >../actual &&
191 cat >../expect <<EOF &&
192 info/exclude $EMPTY_BLOB
193 core.excludesfile 0000000000000000000000000000000000000000
194 exclude_per_dir .gitignore
196 / 0000000000000000000000000000000000000000 recurse valid
201 /done/ 0000000000000000000000000000000000000000 recurse valid
202 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
204 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
207 test_cmp ../expect ../actual
210 test_expect_success 'new .gitignore invalidates recursively' '
212 echo four >.gitignore &&
214 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
215 git status --porcelain >../actual &&
216 iuc status --porcelain >../status.iuc &&
217 cat >../status.expect <<EOF &&
226 test_cmp ../status.expect ../status.iuc &&
227 test_cmp ../status.expect ../actual &&
228 cat >../trace.expect <<EOF &&
230 gitignore invalidation: 1
231 directory invalidation: 1
234 test_cmp ../trace.expect ../trace
238 test_expect_success 'verify untracked cache dump' '
239 test-tool dump-untracked-cache >../actual &&
240 cat >../expect <<EOF &&
241 info/exclude $EMPTY_BLOB
242 core.excludesfile 0000000000000000000000000000000000000000
243 exclude_per_dir .gitignore
245 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
250 /done/ 0000000000000000000000000000000000000000 recurse valid
251 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
253 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
256 test_cmp ../expect ../actual
259 test_expect_success 'new info/exclude invalidates everything' '
261 echo three >>.git/info/exclude &&
263 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
264 git status --porcelain >../actual &&
265 iuc status --porcelain >../status.iuc &&
266 cat >../status.expect <<EOF &&
273 test_cmp ../status.expect ../status.iuc &&
274 test_cmp ../status.expect ../actual &&
275 cat >../trace.expect <<EOF &&
277 gitignore invalidation: 1
278 directory invalidation: 0
281 test_cmp ../trace.expect ../trace
284 test_expect_success 'verify untracked cache dump' '
285 test-tool dump-untracked-cache >../actual &&
286 cat >../expect <<EOF &&
287 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
288 core.excludesfile 0000000000000000000000000000000000000000
289 exclude_per_dir .gitignore
291 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
294 /done/ 0000000000000000000000000000000000000000 recurse valid
295 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
296 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
299 test_cmp ../expect ../actual
302 test_expect_success 'move two from tracked to untracked' '
303 git rm --cached two &&
304 test-tool dump-untracked-cache >../actual &&
305 cat >../expect <<EOF &&
306 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
307 core.excludesfile 0000000000000000000000000000000000000000
308 exclude_per_dir .gitignore
310 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
311 /done/ 0000000000000000000000000000000000000000 recurse valid
312 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
313 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
316 test_cmp ../expect ../actual
319 test_expect_success 'status after the move' '
321 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
322 git status --porcelain >../actual &&
323 iuc status --porcelain >../status.iuc &&
324 cat >../status.expect <<EOF &&
331 test_cmp ../status.expect ../status.iuc &&
332 test_cmp ../status.expect ../actual &&
333 cat >../trace.expect <<EOF &&
335 gitignore invalidation: 0
336 directory invalidation: 0
339 test_cmp ../trace.expect ../trace
342 test_expect_success 'verify untracked cache dump' '
343 test-tool dump-untracked-cache >../actual &&
344 cat >../expect <<EOF &&
345 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
346 core.excludesfile 0000000000000000000000000000000000000000
347 exclude_per_dir .gitignore
349 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
353 /done/ 0000000000000000000000000000000000000000 recurse valid
354 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
355 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
358 test_cmp ../expect ../actual
361 test_expect_success 'move two from untracked to tracked' '
363 test-tool dump-untracked-cache >../actual &&
364 cat >../expect <<EOF &&
365 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
366 core.excludesfile 0000000000000000000000000000000000000000
367 exclude_per_dir .gitignore
369 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
370 /done/ 0000000000000000000000000000000000000000 recurse valid
371 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
372 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
375 test_cmp ../expect ../actual
378 test_expect_success 'status after the move' '
380 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
381 git status --porcelain >../actual &&
382 iuc status --porcelain >../status.iuc &&
383 cat >../status.expect <<EOF &&
390 test_cmp ../status.expect ../status.iuc &&
391 test_cmp ../status.expect ../actual &&
392 cat >../trace.expect <<EOF &&
394 gitignore invalidation: 0
395 directory invalidation: 0
398 test_cmp ../trace.expect ../trace
401 test_expect_success 'verify untracked cache dump' '
402 test-tool dump-untracked-cache >../actual &&
403 cat >../expect <<EOF &&
404 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
405 core.excludesfile 0000000000000000000000000000000000000000
406 exclude_per_dir .gitignore
408 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
411 /done/ 0000000000000000000000000000000000000000 recurse valid
412 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
413 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
416 test_cmp ../expect ../actual
419 test_expect_success 'set up for sparse checkout testing' '
420 echo two >done/.gitignore &&
421 echo three >>done/.gitignore &&
422 echo two >done/two &&
423 git add -f done/two done/.gitignore &&
424 git commit -m "first commit"
427 test_expect_success 'status after commit' '
429 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
430 git status --porcelain >../actual &&
431 iuc status --porcelain >../status.iuc &&
432 cat >../status.expect <<EOF &&
436 test_cmp ../status.expect ../status.iuc &&
437 test_cmp ../status.expect ../actual &&
438 cat >../trace.expect <<EOF &&
440 gitignore invalidation: 0
441 directory invalidation: 0
444 test_cmp ../trace.expect ../trace
447 test_expect_success 'untracked cache correct after commit' '
448 test-tool dump-untracked-cache >../actual &&
449 cat >../expect <<EOF &&
450 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
451 core.excludesfile 0000000000000000000000000000000000000000
452 exclude_per_dir .gitignore
454 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
457 /done/ 0000000000000000000000000000000000000000 recurse valid
458 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
459 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
462 test_cmp ../expect ../actual
465 test_expect_success 'set up sparse checkout' '
466 echo "done/[a-z]*" >.git/info/sparse-checkout &&
467 test_config core.sparsecheckout true &&
468 git checkout master &&
469 git update-index --force-untracked-cache &&
470 git status --porcelain >/dev/null && # prime the cache
471 test_path_is_missing done/.gitignore &&
472 test_path_is_file done/one
475 test_expect_success 'create/modify files, some of which are gitignored' '
476 echo two bis >done/two &&
477 echo three >done/three && # three is gitignored
478 echo four >done/four && # four is gitignored at a higher level
479 echo five >done/five && # five is not gitignored
480 echo test >base && #we need to ensure that the root dir is touched
485 test_expect_success 'test sparse status with untracked cache' '
488 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
489 git status --porcelain >../status.actual &&
490 iuc status --porcelain >../status.iuc &&
491 cat >../status.expect <<EOF &&
497 test_cmp ../status.expect ../status.iuc &&
498 test_cmp ../status.expect ../status.actual &&
499 cat >../trace.expect <<EOF &&
501 gitignore invalidation: 1
502 directory invalidation: 2
505 test_cmp ../trace.expect ../trace
508 test_expect_success 'untracked cache correct after status' '
509 test-tool dump-untracked-cache >../actual &&
510 cat >../expect <<EOF &&
511 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
512 core.excludesfile 0000000000000000000000000000000000000000
513 exclude_per_dir .gitignore
515 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
518 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
520 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
521 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
524 test_cmp ../expect ../actual
527 test_expect_success 'test sparse status again with untracked cache' '
530 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
531 git status --porcelain >../status.actual &&
532 iuc status --porcelain >../status.iuc &&
533 cat >../status.expect <<EOF &&
539 test_cmp ../status.expect ../status.iuc &&
540 test_cmp ../status.expect ../status.actual &&
541 cat >../trace.expect <<EOF &&
543 gitignore invalidation: 0
544 directory invalidation: 0
547 test_cmp ../trace.expect ../trace
550 test_expect_success 'set up for test of subdir and sparse checkouts' '
552 mkdir done/sub/sub &&
553 echo "sub" > done/sub/sub/file
556 test_expect_success 'test sparse status with untracked cache and subdir' '
559 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
560 git status --porcelain >../status.actual &&
561 iuc status --porcelain >../status.iuc &&
562 cat >../status.expect <<EOF &&
569 test_cmp ../status.expect ../status.iuc &&
570 test_cmp ../status.expect ../status.actual &&
571 cat >../trace.expect <<EOF &&
573 gitignore invalidation: 0
574 directory invalidation: 1
577 test_cmp ../trace.expect ../trace
580 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
581 test-tool dump-untracked-cache >../actual &&
582 cat >../expect-from-test-dump <<EOF &&
583 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
584 core.excludesfile 0000000000000000000000000000000000000000
585 exclude_per_dir .gitignore
587 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
590 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
593 /done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
595 /done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
597 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
598 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
601 test_cmp ../expect-from-test-dump ../actual
604 test_expect_success 'test sparse status again with untracked cache and subdir' '
607 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
608 git status --porcelain >../status.actual &&
609 iuc status --porcelain >../status.iuc &&
610 test_cmp ../status.expect ../status.iuc &&
611 test_cmp ../status.expect ../status.actual &&
612 cat >../trace.expect <<EOF &&
614 gitignore invalidation: 0
615 directory invalidation: 0
618 test_cmp ../trace.expect ../trace
621 test_expect_success 'move entry in subdir from untracked to cached' '
623 git status --porcelain >../status.actual &&
624 iuc status --porcelain >../status.iuc &&
625 cat >../status.expect <<EOF &&
632 test_cmp ../status.expect ../status.iuc &&
633 test_cmp ../status.expect ../status.actual
636 test_expect_success 'move entry in subdir from cached to untracked' '
637 git rm --cached dtwo/two &&
638 git status --porcelain >../status.actual &&
639 iuc status --porcelain >../status.iuc &&
640 cat >../status.expect <<EOF &&
647 test_cmp ../status.expect ../status.iuc &&
648 test_cmp ../status.expect ../status.actual
651 test_expect_success '--no-untracked-cache removes the cache' '
652 git update-index --no-untracked-cache &&
653 test-tool dump-untracked-cache >../actual &&
654 echo "no untracked cache" >../expect-no-uc &&
655 test_cmp ../expect-no-uc ../actual
658 test_expect_success 'git status does not change anything' '
660 test-tool dump-untracked-cache >../actual &&
661 test_cmp ../expect-no-uc ../actual
664 test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
665 git config core.untrackedCache true &&
666 test-tool dump-untracked-cache >../actual &&
667 test_cmp ../expect-no-uc ../actual &&
669 test-tool dump-untracked-cache >../actual &&
670 test_cmp ../expect-from-test-dump ../actual
673 test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
674 git update-index --no-untracked-cache &&
675 test-tool dump-untracked-cache >../actual &&
676 test_cmp ../expect-no-uc ../actual &&
677 git update-index --untracked-cache &&
678 test-tool dump-untracked-cache >../actual &&
679 test_cmp ../expect-empty ../actual
682 test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
683 git config core.untrackedCache false &&
684 test-tool dump-untracked-cache >../actual &&
685 test_cmp ../expect-empty ../actual &&
687 test-tool dump-untracked-cache >../actual &&
688 test_cmp ../expect-no-uc ../actual
691 test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
692 git update-index --untracked-cache &&
693 test-tool dump-untracked-cache >../actual &&
694 test_cmp ../expect-empty ../actual
697 test_expect_success 'setting core.untrackedCache to keep' '
698 git config core.untrackedCache keep &&
699 git update-index --untracked-cache &&
700 test-tool dump-untracked-cache >../actual &&
701 test_cmp ../expect-empty ../actual &&
703 test-tool dump-untracked-cache >../actual &&
704 test_cmp ../expect-from-test-dump ../actual &&
705 git update-index --no-untracked-cache &&
706 test-tool dump-untracked-cache >../actual &&
707 test_cmp ../expect-no-uc ../actual &&
708 git update-index --force-untracked-cache &&
709 test-tool dump-untracked-cache >../actual &&
710 test_cmp ../expect-empty ../actual &&
712 test-tool dump-untracked-cache >../actual &&
713 test_cmp ../expect-from-test-dump ../actual
716 test_expect_success 'test ident field is working' '
717 mkdir ../other_worktree &&
718 cp -R done dthree dtwo four three ../other_worktree &&
719 GIT_WORK_TREE=../other_worktree git status 2>../err &&
720 echo "warning: untracked cache is disabled on this system or location" >../expect &&
721 test_i18ncmp ../expect ../err
724 test_expect_success 'untracked cache survives a checkout' '
725 git commit --allow-empty -m empty &&
726 test-tool dump-untracked-cache >../before &&
727 test_when_finished "git checkout master" &&
728 git checkout -b other_branch &&
729 test-tool dump-untracked-cache >../after &&
730 test_cmp ../before ../after &&
732 test-tool dump-untracked-cache >../before &&
733 git checkout master &&
734 test-tool dump-untracked-cache >../after &&
735 test_cmp ../before ../after
738 test_expect_success 'untracked cache survives a commit' '
739 test-tool dump-untracked-cache >../before &&
741 git commit -m commit &&
742 test-tool dump-untracked-cache >../after &&
743 test_cmp ../before ../after
746 test_expect_success 'teardown worktree' '
750 test_expect_success SYMLINKS 'setup worktree for symlink test' '
751 git init worktree-symlink &&
752 cd worktree-symlink &&
753 git config core.untrackedCache true &&
755 touch one/file two/file &&
756 git add one/file two/file &&
757 git commit -m"first commit" &&
761 git commit -m"second commit"
764 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
765 git checkout HEAD~ &&
768 git checkout master &&
774 test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
775 git config core.untrackedCache false &&
776 git checkout HEAD~ &&
779 git checkout master &&
785 test_expect_success 'setup worktree for non-symlink test' '
786 git init worktree-non-symlink &&
787 cd worktree-non-symlink &&
788 git config core.untrackedCache true &&
790 touch one/file two/file &&
791 git add one/file two/file &&
792 git commit -m"first commit" &&
796 git commit -m"second commit"
799 test_expect_success '"status" after file replacement should be clean with UC=true' '
800 git checkout HEAD~ &&
803 git checkout master &&
806 test-tool dump-untracked-cache >../actual &&
807 grep -F "recurse valid" ../actual >../actual.grep &&
808 cat >../expect.grep <<EOF &&
809 / 0000000000000000000000000000000000000000 recurse valid
810 /two/ 0000000000000000000000000000000000000000 recurse valid
813 test_cmp ../expect.grep ../actual.grep
816 test_expect_success '"status" after file replacement should be clean with UC=false' '
817 git config core.untrackedCache false &&
818 git checkout HEAD~ &&
821 git checkout master &&