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