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