6ef520e8237dbad4365eab057149678ba1221dba
1#!/bin/sh
2
3test_description='test untracked cache'
4
5. ./test-lib.sh
6
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.
13#
14# See <20160803174522.5571-1-pclouds@gmail.com> if you want to know
15# more.
16
17GIT_TEST_UNTRACKED_CACHE=true
18export GIT_TEST_UNTRACKED_CACHE
19
20sync_mtime () {
21 find . -type d -ls >/dev/null
22}
23
24avoid_racy() {
25 sleep 1
26}
27
28test_lazy_prereq UNTRACKED_CACHE '
29 { git update-index --test-untracked-cache; ret=$?; } &&
30 test $ret -ne 1
31'
32
33if ! test_have_prereq UNTRACKED_CACHE; then
34 skip_all='This system does not support untracked cache'
35 test_done
36fi
37
38test_expect_success 'core.untrackedCache is unset' '
39 test_must_fail git config --get core.untrackedCache
40'
41
42test_expect_success 'setup' '
43 git init worktree &&
44 cd worktree &&
45 mkdir done dtwo dthree &&
46 touch one two three done/one dtwo/two dthree/three &&
47 git add one two done/one &&
48 : >.git/info/exclude &&
49 git update-index --untracked-cache
50'
51
52test_expect_success 'untracked cache is empty' '
53 test-dump-untracked-cache >../actual &&
54 cat >../expect-empty <<EOF &&
55info/exclude 0000000000000000000000000000000000000000
56core.excludesfile 0000000000000000000000000000000000000000
57exclude_per_dir .gitignore
58flags 00000006
59EOF
60 test_cmp ../expect-empty ../actual
61'
62
63cat >../status.expect <<EOF &&
64A done/one
65A one
66A two
67?? dthree/
68?? dtwo/
69?? three
70EOF
71
72cat >../dump.expect <<EOF &&
73info/exclude $EMPTY_BLOB
74core.excludesfile 0000000000000000000000000000000000000000
75exclude_per_dir .gitignore
76flags 00000006
77/ 0000000000000000000000000000000000000000 recurse valid
78dthree/
79dtwo/
80three
81/done/ 0000000000000000000000000000000000000000 recurse valid
82/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
83three
84/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
85two
86EOF
87
88test_expect_success 'status first time (empty cache)' '
89 avoid_racy &&
90 : >../trace &&
91 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
92 git status --porcelain >../actual &&
93 test_cmp ../status.expect ../actual &&
94 cat >../trace.expect <<EOF &&
95node creation: 3
96gitignore invalidation: 1
97directory invalidation: 0
98opendir: 4
99EOF
100 test_cmp ../trace.expect ../trace
101'
102
103test_expect_success 'untracked cache after first status' '
104 test-dump-untracked-cache >../actual &&
105 test_cmp ../dump.expect ../actual
106'
107
108test_expect_success 'status second time (fully populated cache)' '
109 avoid_racy &&
110 : >../trace &&
111 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
112 git status --porcelain >../actual &&
113 test_cmp ../status.expect ../actual &&
114 cat >../trace.expect <<EOF &&
115node creation: 0
116gitignore invalidation: 0
117directory invalidation: 0
118opendir: 0
119EOF
120 test_cmp ../trace.expect ../trace
121'
122
123test_expect_success 'untracked cache after second status' '
124 test-dump-untracked-cache >../actual &&
125 test_cmp ../dump.expect ../actual
126'
127
128test_expect_success 'modify in root directory, one dir invalidation' '
129 avoid_racy &&
130 : >four &&
131 : >../trace &&
132 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
133 git status --porcelain >../actual &&
134 cat >../status.expect <<EOF &&
135A done/one
136A one
137A two
138?? dthree/
139?? dtwo/
140?? four
141?? three
142EOF
143 test_cmp ../status.expect ../actual &&
144 cat >../trace.expect <<EOF &&
145node creation: 0
146gitignore invalidation: 0
147directory invalidation: 1
148opendir: 1
149EOF
150 test_cmp ../trace.expect ../trace
151
152'
153
154test_expect_success 'verify untracked cache dump' '
155 test-dump-untracked-cache >../actual &&
156 cat >../expect <<EOF &&
157info/exclude $EMPTY_BLOB
158core.excludesfile 0000000000000000000000000000000000000000
159exclude_per_dir .gitignore
160flags 00000006
161/ 0000000000000000000000000000000000000000 recurse valid
162dthree/
163dtwo/
164four
165three
166/done/ 0000000000000000000000000000000000000000 recurse valid
167/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
168three
169/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
170two
171EOF
172 test_cmp ../expect ../actual
173'
174
175test_expect_success 'new .gitignore invalidates recursively' '
176 avoid_racy &&
177 echo four >.gitignore &&
178 : >../trace &&
179 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
180 git status --porcelain >../actual &&
181 cat >../status.expect <<EOF &&
182A done/one
183A one
184A two
185?? .gitignore
186?? dthree/
187?? dtwo/
188?? three
189EOF
190 test_cmp ../status.expect ../actual &&
191 cat >../trace.expect <<EOF &&
192node creation: 0
193gitignore invalidation: 1
194directory invalidation: 1
195opendir: 4
196EOF
197 test_cmp ../trace.expect ../trace
198
199'
200
201test_expect_success 'verify untracked cache dump' '
202 test-dump-untracked-cache >../actual &&
203 cat >../expect <<EOF &&
204info/exclude $EMPTY_BLOB
205core.excludesfile 0000000000000000000000000000000000000000
206exclude_per_dir .gitignore
207flags 00000006
208/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
209.gitignore
210dthree/
211dtwo/
212three
213/done/ 0000000000000000000000000000000000000000 recurse valid
214/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
215three
216/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
217two
218EOF
219 test_cmp ../expect ../actual
220'
221
222test_expect_success 'new info/exclude invalidates everything' '
223 avoid_racy &&
224 echo three >>.git/info/exclude &&
225 : >../trace &&
226 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
227 git status --porcelain >../actual &&
228 cat >../status.expect <<EOF &&
229A done/one
230A one
231A two
232?? .gitignore
233?? dtwo/
234EOF
235 test_cmp ../status.expect ../actual &&
236 cat >../trace.expect <<EOF &&
237node creation: 0
238gitignore invalidation: 1
239directory invalidation: 0
240opendir: 4
241EOF
242 test_cmp ../trace.expect ../trace
243'
244
245test_expect_success 'verify untracked cache dump' '
246 test-dump-untracked-cache >../actual &&
247 cat >../expect <<EOF &&
248info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
249core.excludesfile 0000000000000000000000000000000000000000
250exclude_per_dir .gitignore
251flags 00000006
252/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
253.gitignore
254dtwo/
255/done/ 0000000000000000000000000000000000000000 recurse valid
256/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
257/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
258two
259EOF
260 test_cmp ../expect ../actual
261'
262
263test_expect_success 'move two from tracked to untracked' '
264 git rm --cached two &&
265 test-dump-untracked-cache >../actual &&
266 cat >../expect <<EOF &&
267info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
268core.excludesfile 0000000000000000000000000000000000000000
269exclude_per_dir .gitignore
270flags 00000006
271/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
272/done/ 0000000000000000000000000000000000000000 recurse valid
273/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
274/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
275two
276EOF
277 test_cmp ../expect ../actual
278'
279
280test_expect_success 'status after the move' '
281 : >../trace &&
282 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
283 git status --porcelain >../actual &&
284 cat >../status.expect <<EOF &&
285A done/one
286A one
287?? .gitignore
288?? dtwo/
289?? two
290EOF
291 test_cmp ../status.expect ../actual &&
292 cat >../trace.expect <<EOF &&
293node creation: 0
294gitignore invalidation: 0
295directory invalidation: 0
296opendir: 1
297EOF
298 test_cmp ../trace.expect ../trace
299'
300
301test_expect_success 'verify untracked cache dump' '
302 test-dump-untracked-cache >../actual &&
303 cat >../expect <<EOF &&
304info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
305core.excludesfile 0000000000000000000000000000000000000000
306exclude_per_dir .gitignore
307flags 00000006
308/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
309.gitignore
310dtwo/
311two
312/done/ 0000000000000000000000000000000000000000 recurse valid
313/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
314/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
315two
316EOF
317 test_cmp ../expect ../actual
318'
319
320test_expect_success 'move two from untracked to tracked' '
321 git add two &&
322 test-dump-untracked-cache >../actual &&
323 cat >../expect <<EOF &&
324info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
325core.excludesfile 0000000000000000000000000000000000000000
326exclude_per_dir .gitignore
327flags 00000006
328/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
329/done/ 0000000000000000000000000000000000000000 recurse valid
330/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
331/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
332two
333EOF
334 test_cmp ../expect ../actual
335'
336
337test_expect_success 'status after the move' '
338 : >../trace &&
339 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
340 git status --porcelain >../actual &&
341 cat >../status.expect <<EOF &&
342A done/one
343A one
344A two
345?? .gitignore
346?? dtwo/
347EOF
348 test_cmp ../status.expect ../actual &&
349 cat >../trace.expect <<EOF &&
350node creation: 0
351gitignore invalidation: 0
352directory invalidation: 0
353opendir: 1
354EOF
355 test_cmp ../trace.expect ../trace
356'
357
358test_expect_success 'verify untracked cache dump' '
359 test-dump-untracked-cache >../actual &&
360 cat >../expect <<EOF &&
361info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
362core.excludesfile 0000000000000000000000000000000000000000
363exclude_per_dir .gitignore
364flags 00000006
365/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
366.gitignore
367dtwo/
368/done/ 0000000000000000000000000000000000000000 recurse valid
369/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
370/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
371two
372EOF
373 test_cmp ../expect ../actual
374'
375
376test_expect_success 'set up for sparse checkout testing' '
377 echo two >done/.gitignore &&
378 echo three >>done/.gitignore &&
379 echo two >done/two &&
380 git add -f done/two done/.gitignore &&
381 git commit -m "first commit"
382'
383
384test_expect_success 'status after commit' '
385 : >../trace &&
386 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
387 git status --porcelain >../actual &&
388 cat >../status.expect <<EOF &&
389?? .gitignore
390?? dtwo/
391EOF
392 test_cmp ../status.expect ../actual &&
393 cat >../trace.expect <<EOF &&
394node creation: 0
395gitignore invalidation: 0
396directory invalidation: 0
397opendir: 2
398EOF
399 test_cmp ../trace.expect ../trace
400'
401
402test_expect_success 'untracked cache correct after commit' '
403 test-dump-untracked-cache >../actual &&
404 cat >../expect <<EOF &&
405info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
406core.excludesfile 0000000000000000000000000000000000000000
407exclude_per_dir .gitignore
408flags 00000006
409/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
410.gitignore
411dtwo/
412/done/ 0000000000000000000000000000000000000000 recurse valid
413/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
414/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
415two
416EOF
417 test_cmp ../expect ../actual
418'
419
420test_expect_success 'set up sparse checkout' '
421 echo "done/[a-z]*" >.git/info/sparse-checkout &&
422 test_config core.sparsecheckout true &&
423 git checkout master &&
424 git update-index --force-untracked-cache &&
425 git status --porcelain >/dev/null && # prime the cache
426 test_path_is_missing done/.gitignore &&
427 test_path_is_file done/one
428'
429
430test_expect_success 'create/modify files, some of which are gitignored' '
431 echo two bis >done/two &&
432 echo three >done/three && # three is gitignored
433 echo four >done/four && # four is gitignored at a higher level
434 echo five >done/five && # five is not gitignored
435 echo test >base && #we need to ensure that the root dir is touched
436 rm base &&
437 sync_mtime
438'
439
440test_expect_success 'test sparse status with untracked cache' '
441 : >../trace &&
442 avoid_racy &&
443 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
444 git status --porcelain >../status.actual &&
445 cat >../status.expect <<EOF &&
446 M done/two
447?? .gitignore
448?? done/five
449?? dtwo/
450EOF
451 test_cmp ../status.expect ../status.actual &&
452 cat >../trace.expect <<EOF &&
453node creation: 0
454gitignore invalidation: 1
455directory invalidation: 2
456opendir: 2
457EOF
458 test_cmp ../trace.expect ../trace
459'
460
461test_expect_success 'untracked cache correct after status' '
462 test-dump-untracked-cache >../actual &&
463 cat >../expect <<EOF &&
464info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
465core.excludesfile 0000000000000000000000000000000000000000
466exclude_per_dir .gitignore
467flags 00000006
468/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
469.gitignore
470dtwo/
471/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
472five
473/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
474/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
475two
476EOF
477 test_cmp ../expect ../actual
478'
479
480test_expect_success 'test sparse status again with untracked cache' '
481 avoid_racy &&
482 : >../trace &&
483 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
484 git status --porcelain >../status.actual &&
485 cat >../status.expect <<EOF &&
486 M done/two
487?? .gitignore
488?? done/five
489?? dtwo/
490EOF
491 test_cmp ../status.expect ../status.actual &&
492 cat >../trace.expect <<EOF &&
493node creation: 0
494gitignore invalidation: 0
495directory invalidation: 0
496opendir: 0
497EOF
498 test_cmp ../trace.expect ../trace
499'
500
501test_expect_success 'set up for test of subdir and sparse checkouts' '
502 mkdir done/sub &&
503 mkdir done/sub/sub &&
504 echo "sub" > done/sub/sub/file
505'
506
507test_expect_success 'test sparse status with untracked cache and subdir' '
508 avoid_racy &&
509 : >../trace &&
510 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
511 git status --porcelain >../status.actual &&
512 cat >../status.expect <<EOF &&
513 M done/two
514?? .gitignore
515?? done/five
516?? done/sub/
517?? dtwo/
518EOF
519 test_cmp ../status.expect ../status.actual &&
520 cat >../trace.expect <<EOF &&
521node creation: 2
522gitignore invalidation: 0
523directory invalidation: 1
524opendir: 3
525EOF
526 test_cmp ../trace.expect ../trace
527'
528
529test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
530 test-dump-untracked-cache >../actual &&
531 cat >../expect-from-test-dump <<EOF &&
532info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
533core.excludesfile 0000000000000000000000000000000000000000
534exclude_per_dir .gitignore
535flags 00000006
536/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
537.gitignore
538dtwo/
539/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
540five
541sub/
542/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
543sub/
544/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
545file
546/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
547/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
548two
549EOF
550 test_cmp ../expect-from-test-dump ../actual
551'
552
553test_expect_success 'test sparse status again with untracked cache and subdir' '
554 avoid_racy &&
555 : >../trace &&
556 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
557 git status --porcelain >../status.actual &&
558 test_cmp ../status.expect ../status.actual &&
559 cat >../trace.expect <<EOF &&
560node creation: 0
561gitignore invalidation: 0
562directory invalidation: 0
563opendir: 0
564EOF
565 test_cmp ../trace.expect ../trace
566'
567
568test_expect_success 'move entry in subdir from untracked to cached' '
569 git add dtwo/two &&
570 git status --porcelain >../status.actual &&
571 cat >../status.expect <<EOF &&
572 M done/two
573A dtwo/two
574?? .gitignore
575?? done/five
576?? done/sub/
577EOF
578 test_cmp ../status.expect ../status.actual
579'
580
581test_expect_success 'move entry in subdir from cached to untracked' '
582 git rm --cached dtwo/two &&
583 git status --porcelain >../status.actual &&
584 cat >../status.expect <<EOF &&
585 M done/two
586?? .gitignore
587?? done/five
588?? done/sub/
589?? dtwo/
590EOF
591 test_cmp ../status.expect ../status.actual
592'
593
594test_expect_success '--no-untracked-cache removes the cache' '
595 git update-index --no-untracked-cache &&
596 test-dump-untracked-cache >../actual &&
597 echo "no untracked cache" >../expect-no-uc &&
598 test_cmp ../expect-no-uc ../actual
599'
600
601test_expect_success 'git status does not change anything' '
602 git status &&
603 test-dump-untracked-cache >../actual &&
604 test_cmp ../expect-no-uc ../actual
605'
606
607test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
608 git config core.untrackedCache true &&
609 test-dump-untracked-cache >../actual &&
610 test_cmp ../expect-no-uc ../actual &&
611 git status &&
612 test-dump-untracked-cache >../actual &&
613 test_cmp ../expect-from-test-dump ../actual
614'
615
616test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
617 git update-index --no-untracked-cache &&
618 test-dump-untracked-cache >../actual &&
619 test_cmp ../expect-no-uc ../actual &&
620 git update-index --untracked-cache &&
621 test-dump-untracked-cache >../actual &&
622 test_cmp ../expect-empty ../actual
623'
624
625test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
626 git config core.untrackedCache false &&
627 test-dump-untracked-cache >../actual &&
628 test_cmp ../expect-empty ../actual &&
629 git status &&
630 test-dump-untracked-cache >../actual &&
631 test_cmp ../expect-no-uc ../actual
632'
633
634test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
635 git update-index --untracked-cache &&
636 test-dump-untracked-cache >../actual &&
637 test_cmp ../expect-empty ../actual
638'
639
640test_expect_success 'setting core.untrackedCache to keep' '
641 git config core.untrackedCache keep &&
642 git update-index --untracked-cache &&
643 test-dump-untracked-cache >../actual &&
644 test_cmp ../expect-empty ../actual &&
645 git status &&
646 test-dump-untracked-cache >../actual &&
647 test_cmp ../expect-from-test-dump ../actual &&
648 git update-index --no-untracked-cache &&
649 test-dump-untracked-cache >../actual &&
650 test_cmp ../expect-no-uc ../actual &&
651 git update-index --force-untracked-cache &&
652 test-dump-untracked-cache >../actual &&
653 test_cmp ../expect-empty ../actual &&
654 git status &&
655 test-dump-untracked-cache >../actual &&
656 test_cmp ../expect-from-test-dump ../actual
657'
658
659test_expect_success 'test ident field is working' '
660 mkdir ../other_worktree &&
661 cp -R done dthree dtwo four three ../other_worktree &&
662 GIT_WORK_TREE=../other_worktree git status 2>../err &&
663 echo "warning: Untracked cache is disabled on this system or location." >../expect &&
664 test_i18ncmp ../expect ../err
665'
666
667test_expect_success 'untracked cache survives a checkout' '
668 git commit --allow-empty -m empty &&
669 test-dump-untracked-cache >../before &&
670 test_when_finished "git checkout master" &&
671 git checkout -b other_branch &&
672 test-dump-untracked-cache >../after &&
673 test_cmp ../before ../after &&
674 test_commit test &&
675 test-dump-untracked-cache >../before &&
676 git checkout master &&
677 test-dump-untracked-cache >../after &&
678 test_cmp ../before ../after
679'
680
681test_expect_success 'untracked cache survives a commit' '
682 test-dump-untracked-cache >../before &&
683 git add done/two &&
684 git commit -m commit &&
685 test-dump-untracked-cache >../after &&
686 test_cmp ../before ../after
687'
688
689test_done