Merge branch 'js/t4130-rename-without-ino'
[git] / t / t7063-status-untracked-cache.sh
1 #!/bin/sh
2
3 test_description='test untracked cache'
4
5 . ./test-lib.sh
6
7 avoid_racy() {
8         sleep 1
9 }
10
11 test_lazy_prereq UNTRACKED_CACHE '
12         { git update-index --test-untracked-cache; ret=$?; } &&
13         test $ret -ne 1
14 '
15
16 if ! test_have_prereq UNTRACKED_CACHE; then
17         skip_all='This system does not support untracked cache'
18         test_done
19 fi
20
21 test_expect_success 'core.untrackedCache is unset' '
22         test_must_fail git config --get core.untrackedCache
23 '
24
25 test_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
35 test_expect_success 'untracked cache is empty' '
36         test-dump-untracked-cache >../actual &&
37         cat >../expect-empty <<EOF &&
38 info/exclude 0000000000000000000000000000000000000000
39 core.excludesfile 0000000000000000000000000000000000000000
40 exclude_per_dir .gitignore
41 flags 00000006
42 EOF
43         test_cmp ../expect-empty ../actual
44 '
45
46 cat >../status.expect <<EOF &&
47 A  done/one
48 A  one
49 A  two
50 ?? dthree/
51 ?? dtwo/
52 ?? three
53 EOF
54
55 cat >../dump.expect <<EOF &&
56 info/exclude $EMPTY_BLOB
57 core.excludesfile 0000000000000000000000000000000000000000
58 exclude_per_dir .gitignore
59 flags 00000006
60 / 0000000000000000000000000000000000000000 recurse valid
61 dthree/
62 dtwo/
63 three
64 /done/ 0000000000000000000000000000000000000000 recurse valid
65 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
66 three
67 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
68 two
69 EOF
70
71 test_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 &&
78 node creation: 3
79 gitignore invalidation: 1
80 directory invalidation: 0
81 opendir: 4
82 EOF
83         test_cmp ../trace.expect ../trace
84 '
85
86 test_expect_success 'untracked cache after first status' '
87         test-dump-untracked-cache >../actual &&
88         test_cmp ../dump.expect ../actual
89 '
90
91 test_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 &&
98 node creation: 0
99 gitignore invalidation: 0
100 directory invalidation: 0
101 opendir: 0
102 EOF
103         test_cmp ../trace.expect ../trace
104 '
105
106 test_expect_success 'untracked cache after second status' '
107         test-dump-untracked-cache >../actual &&
108         test_cmp ../dump.expect ../actual
109 '
110
111 test_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 &&
118 A  done/one
119 A  one
120 A  two
121 ?? dthree/
122 ?? dtwo/
123 ?? four
124 ?? three
125 EOF
126         test_cmp ../status.expect ../actual &&
127         cat >../trace.expect <<EOF &&
128 node creation: 0
129 gitignore invalidation: 0
130 directory invalidation: 1
131 opendir: 1
132 EOF
133         test_cmp ../trace.expect ../trace
134
135 '
136
137 test_expect_success 'verify untracked cache dump' '
138         test-dump-untracked-cache >../actual &&
139         cat >../expect <<EOF &&
140 info/exclude $EMPTY_BLOB
141 core.excludesfile 0000000000000000000000000000000000000000
142 exclude_per_dir .gitignore
143 flags 00000006
144 / 0000000000000000000000000000000000000000 recurse valid
145 dthree/
146 dtwo/
147 four
148 three
149 /done/ 0000000000000000000000000000000000000000 recurse valid
150 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
151 three
152 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
153 two
154 EOF
155         test_cmp ../expect ../actual
156 '
157
158 test_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 &&
165 A  done/one
166 A  one
167 A  two
168 ?? .gitignore
169 ?? dthree/
170 ?? dtwo/
171 ?? three
172 EOF
173         test_cmp ../status.expect ../actual &&
174         cat >../trace.expect <<EOF &&
175 node creation: 0
176 gitignore invalidation: 1
177 directory invalidation: 1
178 opendir: 4
179 EOF
180         test_cmp ../trace.expect ../trace
181
182 '
183
184 test_expect_success 'verify untracked cache dump' '
185         test-dump-untracked-cache >../actual &&
186         cat >../expect <<EOF &&
187 info/exclude $EMPTY_BLOB
188 core.excludesfile 0000000000000000000000000000000000000000
189 exclude_per_dir .gitignore
190 flags 00000006
191 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
192 .gitignore
193 dthree/
194 dtwo/
195 three
196 /done/ 0000000000000000000000000000000000000000 recurse valid
197 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
198 three
199 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
200 two
201 EOF
202         test_cmp ../expect ../actual
203 '
204
205 test_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 &&
212 A  done/one
213 A  one
214 A  two
215 ?? .gitignore
216 ?? dtwo/
217 EOF
218         test_cmp ../status.expect ../actual &&
219         cat >../trace.expect <<EOF &&
220 node creation: 0
221 gitignore invalidation: 1
222 directory invalidation: 0
223 opendir: 4
224 EOF
225         test_cmp ../trace.expect ../trace
226 '
227
228 test_expect_success 'verify untracked cache dump' '
229         test-dump-untracked-cache >../actual &&
230         cat >../expect <<EOF &&
231 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
232 core.excludesfile 0000000000000000000000000000000000000000
233 exclude_per_dir .gitignore
234 flags 00000006
235 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
236 .gitignore
237 dtwo/
238 /done/ 0000000000000000000000000000000000000000 recurse valid
239 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
240 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
241 two
242 EOF
243         test_cmp ../expect ../actual
244 '
245
246 test_expect_success 'move two from tracked to untracked' '
247         git rm --cached two &&
248         test-dump-untracked-cache >../actual &&
249         cat >../expect <<EOF &&
250 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
251 core.excludesfile 0000000000000000000000000000000000000000
252 exclude_per_dir .gitignore
253 flags 00000006
254 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
255 /done/ 0000000000000000000000000000000000000000 recurse valid
256 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
257 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
258 two
259 EOF
260         test_cmp ../expect ../actual
261 '
262
263 test_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 &&
268 A  done/one
269 A  one
270 ?? .gitignore
271 ?? dtwo/
272 ?? two
273 EOF
274         test_cmp ../status.expect ../actual &&
275         cat >../trace.expect <<EOF &&
276 node creation: 0
277 gitignore invalidation: 0
278 directory invalidation: 0
279 opendir: 1
280 EOF
281         test_cmp ../trace.expect ../trace
282 '
283
284 test_expect_success 'verify untracked cache dump' '
285         test-dump-untracked-cache >../actual &&
286         cat >../expect <<EOF &&
287 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
288 core.excludesfile 0000000000000000000000000000000000000000
289 exclude_per_dir .gitignore
290 flags 00000006
291 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
292 .gitignore
293 dtwo/
294 two
295 /done/ 0000000000000000000000000000000000000000 recurse valid
296 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
297 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
298 two
299 EOF
300         test_cmp ../expect ../actual
301 '
302
303 test_expect_success 'move two from untracked to tracked' '
304         git add two &&
305         test-dump-untracked-cache >../actual &&
306         cat >../expect <<EOF &&
307 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
308 core.excludesfile 0000000000000000000000000000000000000000
309 exclude_per_dir .gitignore
310 flags 00000006
311 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
312 /done/ 0000000000000000000000000000000000000000 recurse valid
313 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
314 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
315 two
316 EOF
317         test_cmp ../expect ../actual
318 '
319
320 test_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 &&
325 A  done/one
326 A  one
327 A  two
328 ?? .gitignore
329 ?? dtwo/
330 EOF
331         test_cmp ../status.expect ../actual &&
332         cat >../trace.expect <<EOF &&
333 node creation: 0
334 gitignore invalidation: 0
335 directory invalidation: 0
336 opendir: 1
337 EOF
338         test_cmp ../trace.expect ../trace
339 '
340
341 test_expect_success 'verify untracked cache dump' '
342         test-dump-untracked-cache >../actual &&
343         cat >../expect <<EOF &&
344 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
345 core.excludesfile 0000000000000000000000000000000000000000
346 exclude_per_dir .gitignore
347 flags 00000006
348 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
349 .gitignore
350 dtwo/
351 /done/ 0000000000000000000000000000000000000000 recurse valid
352 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
353 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
354 two
355 EOF
356         test_cmp ../expect ../actual
357 '
358
359 test_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
367 test_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/
374 EOF
375         test_cmp ../status.expect ../actual &&
376         cat >../trace.expect <<EOF &&
377 node creation: 0
378 gitignore invalidation: 0
379 directory invalidation: 0
380 opendir: 2
381 EOF
382         test_cmp ../trace.expect ../trace
383 '
384
385 test_expect_success 'untracked cache correct after commit' '
386         test-dump-untracked-cache >../actual &&
387         cat >../expect <<EOF &&
388 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
389 core.excludesfile 0000000000000000000000000000000000000000
390 exclude_per_dir .gitignore
391 flags 00000006
392 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
393 .gitignore
394 dtwo/
395 /done/ 0000000000000000000000000000000000000000 recurse valid
396 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
397 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
398 two
399 EOF
400         test_cmp ../expect ../actual
401 '
402
403 test_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
413 test_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
422 test_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/
432 EOF
433         test_cmp ../status.expect ../status.actual &&
434         cat >../trace.expect <<EOF &&
435 node creation: 0
436 gitignore invalidation: 1
437 directory invalidation: 2
438 opendir: 2
439 EOF
440         test_cmp ../trace.expect ../trace
441 '
442
443 test_expect_success 'untracked cache correct after status' '
444         test-dump-untracked-cache >../actual &&
445         cat >../expect <<EOF &&
446 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
447 core.excludesfile 0000000000000000000000000000000000000000
448 exclude_per_dir .gitignore
449 flags 00000006
450 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
451 .gitignore
452 dtwo/
453 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
454 five
455 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
456 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
457 two
458 EOF
459         test_cmp ../expect ../actual
460 '
461
462 test_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/
472 EOF
473         test_cmp ../status.expect ../status.actual &&
474         cat >../trace.expect <<EOF &&
475 node creation: 0
476 gitignore invalidation: 0
477 directory invalidation: 0
478 opendir: 0
479 EOF
480         test_cmp ../trace.expect ../trace
481 '
482
483 test_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
489 test_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/
500 EOF
501         test_cmp ../status.expect ../status.actual &&
502         cat >../trace.expect <<EOF &&
503 node creation: 2
504 gitignore invalidation: 0
505 directory invalidation: 1
506 opendir: 3
507 EOF
508         test_cmp ../trace.expect ../trace
509 '
510
511 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
512         test-dump-untracked-cache >../actual &&
513         cat >../expect-from-test-dump <<EOF &&
514 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
515 core.excludesfile 0000000000000000000000000000000000000000
516 exclude_per_dir .gitignore
517 flags 00000006
518 / e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
519 .gitignore
520 dtwo/
521 /done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
522 five
523 sub/
524 /done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
525 sub/
526 /done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
527 file
528 /dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
529 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
530 two
531 EOF
532         test_cmp ../expect-from-test-dump ../actual
533 '
534
535 test_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 &&
542 node creation: 0
543 gitignore invalidation: 0
544 directory invalidation: 0
545 opendir: 0
546 EOF
547         test_cmp ../trace.expect ../trace
548 '
549
550 test_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
555 A  dtwo/two
556 ?? .gitignore
557 ?? done/five
558 ?? done/sub/
559 EOF
560         test_cmp ../status.expect ../status.actual
561 '
562
563 test_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/
572 EOF
573         test_cmp ../status.expect ../status.actual
574 '
575
576 test_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
583 test_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
589 test_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
598 test_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
607 test_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
616 test_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
622 test_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
641 test_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_i18ncmp ../expect ../err
647 '
648
649 test_done