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 echo test >base && #we need to ensure that the root dir is touched
417 rm base
418'
419
420test_expect_success 'test sparse status with untracked cache' '
421 : >../trace &&
422 avoid_racy &&
423 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
424 git status --porcelain >../status.actual &&
425 cat >../status.expect <<EOF &&
426 M done/two
427?? .gitignore
428?? done/five
429?? dtwo/
430EOF
431 test_cmp ../status.expect ../status.actual &&
432 cat >../trace.expect <<EOF &&
433node creation: 0
434gitignore invalidation: 1
435directory invalidation: 2
436opendir: 2
437EOF
438 test_cmp ../trace.expect ../trace
439'
440
441test_expect_success 'untracked cache correct after status' '
442 test-dump-untracked-cache >../actual &&
443 cat >../expect <<EOF &&
444info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
445core.excludesfile 0000000000000000000000000000000000000000
446exclude_per_dir .gitignore
447flags 00000006
448/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
449.gitignore
450dtwo/
451/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
452five
453/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
454/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
455two
456EOF
457 test_cmp ../expect ../actual
458'
459
460test_expect_success 'test sparse status again with untracked cache' '
461 avoid_racy &&
462 : >../trace &&
463 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
464 git status --porcelain >../status.actual &&
465 cat >../status.expect <<EOF &&
466 M done/two
467?? .gitignore
468?? done/five
469?? dtwo/
470EOF
471 test_cmp ../status.expect ../status.actual &&
472 cat >../trace.expect <<EOF &&
473node creation: 0
474gitignore invalidation: 0
475directory invalidation: 0
476opendir: 0
477EOF
478 test_cmp ../trace.expect ../trace
479'
480
481test_expect_success 'set up for test of subdir and sparse checkouts' '
482 mkdir done/sub &&
483 mkdir done/sub/sub &&
484 echo "sub" > done/sub/sub/file
485'
486
487test_expect_success 'test sparse status with untracked cache and subdir' '
488 avoid_racy &&
489 : >../trace &&
490 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
491 git status --porcelain >../status.actual &&
492 cat >../status.expect <<EOF &&
493 M done/two
494?? .gitignore
495?? done/five
496?? done/sub/
497?? dtwo/
498EOF
499 test_cmp ../status.expect ../status.actual &&
500 cat >../trace.expect <<EOF &&
501node creation: 2
502gitignore invalidation: 0
503directory invalidation: 1
504opendir: 3
505EOF
506 test_cmp ../trace.expect ../trace
507'
508
509test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
510 test-dump-untracked-cache >../actual &&
511 cat >../expect <<EOF &&
512info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
513core.excludesfile 0000000000000000000000000000000000000000
514exclude_per_dir .gitignore
515flags 00000006
516/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
517.gitignore
518dtwo/
519/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
520five
521sub/
522/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
523sub/
524/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
525file
526/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
527/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
528two
529EOF
530 test_cmp ../expect ../actual
531'
532
533test_expect_success 'test sparse status again with untracked cache and subdir' '
534 avoid_racy &&
535 : >../trace &&
536 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
537 git status --porcelain >../status.actual &&
538 test_cmp ../status.expect ../status.actual &&
539 cat >../trace.expect <<EOF &&
540node creation: 0
541gitignore invalidation: 0
542directory invalidation: 0
543opendir: 0
544EOF
545 test_cmp ../trace.expect ../trace
546'
547
548test_expect_success 'move entry in subdir from untracked to cached' '
549 git add dtwo/two &&
550 git status --porcelain >../status.actual &&
551 cat >../status.expect <<EOF &&
552 M done/two
553A dtwo/two
554?? .gitignore
555?? done/five
556?? done/sub/
557EOF
558 test_cmp ../status.expect ../status.actual
559'
560
561test_expect_success 'move entry in subdir from cached to untracked' '
562 git rm --cached dtwo/two &&
563 git status --porcelain >../status.actual &&
564 cat >../status.expect <<EOF &&
565 M done/two
566?? .gitignore
567?? done/five
568?? done/sub/
569?? dtwo/
570EOF
571 test_cmp ../status.expect ../status.actual
572'
573
574test_done