Raw
1 #!/bin/sh
2
3 test_description='direct path-walk API tests'
4
5 . ./test-lib.sh
6
7 test_expect_success 'setup test repository' '
8 git checkout -b base &&
9
10 # Create tree objects that are only reachable via tags,
11 # not from any commit in the history.
12 child_blob_oid=$(echo "child blob content" | git hash-object -t blob -w --stdin) &&
13 child_tree_oid=$(printf "100644 blob %s\tfile\n" "$child_blob_oid" | git mktree) &&
14 tree_tag_oid=$(printf "040000 tree %s\tchild\n" "$child_tree_oid" | git mktree) &&
15 git tag -a -m "tree" tree-tag "$tree_tag_oid" &&
16 file2_blob_oid=$(echo "tagged tree file2" | git hash-object -t blob -w --stdin) &&
17 tree_tag2_oid=$(printf "040000 tree %s\tchild\n100644 blob %s\tfile2\n" "$child_tree_oid" "$file2_blob_oid" | git mktree) &&
18 git tag tree-tag2 "$tree_tag2_oid" &&
19
20 echo blob >file &&
21 blob_oid=$(git hash-object -t blob -w --stdin <file) &&
22 git tag -a -m "blob" blob-tag "$blob_oid" &&
23 echo blob2 >file2 &&
24 blob2_oid=$(git hash-object -t blob -w --stdin <file2) &&
25 git tag blob-tag2 "$blob2_oid" &&
26
27 rm -fr file file2 &&
28
29 mkdir left &&
30 mkdir right &&
31 echo a >a &&
32 echo b >left/b &&
33 echo c >right/c &&
34 git add . &&
35 git commit -m "first" &&
36 git tag -m "first" first HEAD &&
37
38 echo d >right/d &&
39 git add right &&
40 git commit -m "second" &&
41 git tag -a -m "second (under)" second.1 HEAD &&
42 git tag -a -m "second (top)" second.2 second.1 &&
43
44 # Set up file/dir collision in history.
45 rm a &&
46 mkdir a &&
47 echo a >a/a &&
48 echo bb >left/b &&
49 git add a left &&
50 git commit -m "third" &&
51 git tag -a -m "third" third &&
52
53 git checkout -b topic HEAD~1 &&
54 echo cc >right/c &&
55 git commit -a -m "topic" &&
56 git tag -a -m "fourth" fourth
57 '
58
59 test_expect_success 'all' '
60 test-tool path-walk -- --all >out &&
61
62 cat >expect <<-EOF &&
63 0:commit::$(git rev-parse topic)
64 0:commit::$(git rev-parse base)
65 0:commit::$(git rev-parse base~1)
66 0:commit::$(git rev-parse base~2)
67 1:tag:/tags:$(git rev-parse refs/tags/first)
68 1:tag:/tags:$(git rev-parse refs/tags/second.1)
69 1:tag:/tags:$(git rev-parse refs/tags/second.2)
70 1:tag:/tags:$(git rev-parse refs/tags/third)
71 1:tag:/tags:$(git rev-parse refs/tags/fourth)
72 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
73 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
74 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
75 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
76 3:tree::$(git rev-parse topic^{tree})
77 3:tree::$(git rev-parse base^{tree})
78 3:tree::$(git rev-parse base~1^{tree})
79 3:tree::$(git rev-parse base~2^{tree})
80 4:blob:a:$(git rev-parse base~2:a)
81 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
82 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
83 6:blob:file2:$(git rev-parse refs/tags/tree-tag2^{}:file2)
84 7:tree:a/:$(git rev-parse base:a)
85 8:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
86 9:blob:child/file:$(git rev-parse refs/tags/tree-tag:child/file)
87 10:tree:left/:$(git rev-parse base:left)
88 10:tree:left/:$(git rev-parse base~2:left)
89 11:blob:left/b:$(git rev-parse base~2:left/b)
90 11:blob:left/b:$(git rev-parse base:left/b)
91 12:tree:right/:$(git rev-parse topic:right)
92 12:tree:right/:$(git rev-parse base~1:right)
93 12:tree:right/:$(git rev-parse base~2:right)
94 13:blob:right/c:$(git rev-parse base~2:right/c)
95 13:blob:right/c:$(git rev-parse topic:right/c)
96 14:blob:right/d:$(git rev-parse base~1:right/d)
97 blobs:10
98 commits:4
99 tags:7
100 trees:13
101 EOF
102
103 test_cmp_sorted expect out
104 '
105
106 test_expect_success 'indexed objects' '
107 test_when_finished git reset --hard &&
108
109 # stage change into index, adding a blob but
110 # also invalidating the cache-tree for the root
111 # and the "left" directory.
112 echo bogus >left/c &&
113 git add left &&
114
115 test-tool path-walk -- --indexed-objects >out &&
116
117 cat >expect <<-EOF &&
118 0:blob:a:$(git rev-parse HEAD:a)
119 1:blob:left/b:$(git rev-parse HEAD:left/b)
120 2:blob:left/c:$(git rev-parse :left/c)
121 3:blob:right/c:$(git rev-parse HEAD:right/c)
122 4:blob:right/d:$(git rev-parse HEAD:right/d)
123 5:tree:right/:$(git rev-parse topic:right)
124 blobs:5
125 commits:0
126 tags:0
127 trees:1
128 EOF
129
130 test_cmp_sorted expect out
131 '
132
133 test_expect_success 'branches and indexed objects mix well' '
134 test_when_finished git reset --hard &&
135
136 # stage change into index, adding a blob but
137 # also invalidating the cache-tree for the root
138 # and the "right" directory.
139 echo fake >right/d &&
140 git add right &&
141
142 test-tool path-walk -- --indexed-objects --branches >out &&
143
144 cat >expect <<-EOF &&
145 0:commit::$(git rev-parse topic)
146 0:commit::$(git rev-parse base)
147 0:commit::$(git rev-parse base~1)
148 0:commit::$(git rev-parse base~2)
149 1:tree::$(git rev-parse topic^{tree})
150 1:tree::$(git rev-parse base^{tree})
151 1:tree::$(git rev-parse base~1^{tree})
152 1:tree::$(git rev-parse base~2^{tree})
153 2:tree:a/:$(git rev-parse refs/tags/third:a)
154 3:tree:left/:$(git rev-parse base:left)
155 3:tree:left/:$(git rev-parse base~2:left)
156 4:blob:left/b:$(git rev-parse base:left/b)
157 4:blob:left/b:$(git rev-parse base~2:left/b)
158 5:tree:right/:$(git rev-parse topic:right)
159 5:tree:right/:$(git rev-parse base~1:right)
160 5:tree:right/:$(git rev-parse base~2:right)
161 6:blob:right/c:$(git rev-parse base~2:right/c)
162 6:blob:right/c:$(git rev-parse topic:right/c)
163 7:blob:right/d:$(git rev-parse base~1:right/d)
164 7:blob:right/d:$(git rev-parse :right/d)
165 8:blob:a:$(git rev-parse base~2:a)
166 blobs:7
167 commits:4
168 tags:0
169 trees:10
170 EOF
171
172 test_cmp_sorted expect out
173 '
174
175 test_expect_success 'base & topic, sparse' '
176 cat >patterns <<-EOF &&
177 /*
178 !/*/
179 /left/
180 EOF
181
182 test-tool path-walk --stdin-pl -- base topic <patterns >out &&
183
184 cat >expect <<-EOF &&
185 0:commit::$(git rev-parse topic)
186 0:commit::$(git rev-parse base)
187 0:commit::$(git rev-parse base~1)
188 0:commit::$(git rev-parse base~2)
189 1:tree::$(git rev-parse topic^{tree})
190 1:tree::$(git rev-parse base^{tree})
191 1:tree::$(git rev-parse base~1^{tree})
192 1:tree::$(git rev-parse base~2^{tree})
193 2:blob:a:$(git rev-parse base~2:a)
194 3:tree:left/:$(git rev-parse base:left)
195 3:tree:left/:$(git rev-parse base~2:left)
196 4:blob:left/b:$(git rev-parse base~2:left/b)
197 4:blob:left/b:$(git rev-parse base:left/b)
198 blobs:3
199 commits:4
200 tags:0
201 trees:6
202 EOF
203
204 test_cmp_sorted expect out
205 '
206
207 test_expect_success 'base & topic, sparse, no tree pruning' '
208 cat >patterns <<-EOF &&
209 /*
210 !/*/
211 /left/
212 EOF
213
214 test-tool path-walk --stdin-pl --no-pl-sparse-trees \
215 -- base topic <patterns >out &&
216
217 cat >expect <<-EOF &&
218 0:commit::$(git rev-parse topic)
219 0:commit::$(git rev-parse base)
220 0:commit::$(git rev-parse base~1)
221 0:commit::$(git rev-parse base~2)
222 1:tree::$(git rev-parse topic^{tree})
223 1:tree::$(git rev-parse base^{tree})
224 1:tree::$(git rev-parse base~1^{tree})
225 1:tree::$(git rev-parse base~2^{tree})
226 2:blob:a:$(git rev-parse base~2:a)
227 3:tree:a/:$(git rev-parse base:a)
228 4:tree:left/:$(git rev-parse base:left)
229 4:tree:left/:$(git rev-parse base~2:left)
230 5:blob:left/b:$(git rev-parse base~2:left/b)
231 5:blob:left/b:$(git rev-parse base:left/b)
232 6:tree:right/:$(git rev-parse topic:right)
233 6:tree:right/:$(git rev-parse base~1:right)
234 6:tree:right/:$(git rev-parse base~2:right)
235 blobs:3
236 commits:4
237 tags:0
238 trees:10
239 EOF
240
241 test_cmp_sorted expect out
242 '
243
244 test_expect_success 'topic only' '
245 test-tool path-walk -- topic >out &&
246
247 cat >expect <<-EOF &&
248 0:commit::$(git rev-parse topic)
249 0:commit::$(git rev-parse base~1)
250 0:commit::$(git rev-parse base~2)
251 1:tree::$(git rev-parse topic^{tree})
252 1:tree::$(git rev-parse base~1^{tree})
253 1:tree::$(git rev-parse base~2^{tree})
254 2:blob:a:$(git rev-parse base~2:a)
255 3:tree:left/:$(git rev-parse base~2:left)
256 4:blob:left/b:$(git rev-parse base~2:left/b)
257 5:tree:right/:$(git rev-parse topic:right)
258 5:tree:right/:$(git rev-parse base~1:right)
259 5:tree:right/:$(git rev-parse base~2:right)
260 6:blob:right/c:$(git rev-parse base~2:right/c)
261 6:blob:right/c:$(git rev-parse topic:right/c)
262 7:blob:right/d:$(git rev-parse base~1:right/d)
263 blobs:5
264 commits:3
265 tags:0
266 trees:7
267 EOF
268
269 test_cmp_sorted expect out
270 '
271
272 test_expect_success 'topic, not base' '
273 test-tool path-walk -- topic --not base >out &&
274
275 cat >expect <<-EOF &&
276 0:commit::$(git rev-parse topic)
277 1:tree::$(git rev-parse topic^{tree})
278 2:blob:a:$(git rev-parse topic:a):UNINTERESTING
279 3:tree:left/:$(git rev-parse topic:left):UNINTERESTING
280 4:blob:left/b:$(git rev-parse topic:left/b):UNINTERESTING
281 5:tree:right/:$(git rev-parse topic:right)
282 6:blob:right/c:$(git rev-parse topic:right/c)
283 7:blob:right/d:$(git rev-parse topic:right/d):UNINTERESTING
284 blobs:4
285 commits:1
286 tags:0
287 trees:3
288 EOF
289
290 test_cmp_sorted expect out
291 '
292
293 test_expect_success 'fourth, blob-tag2, not base' '
294 test-tool path-walk -- fourth blob-tag2 --not base >out &&
295
296 cat >expect <<-EOF &&
297 0:commit::$(git rev-parse topic)
298 1:tag:/tags:$(git rev-parse fourth)
299 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
300 3:tree::$(git rev-parse topic^{tree})
301 4:blob:a:$(git rev-parse base~1:a):UNINTERESTING
302 5:tree:left/:$(git rev-parse base~1:left):UNINTERESTING
303 6:blob:left/b:$(git rev-parse base~1:left/b):UNINTERESTING
304 7:tree:right/:$(git rev-parse topic:right)
305 8:blob:right/c:$(git rev-parse topic:right/c)
306 9:blob:right/d:$(git rev-parse base~1:right/d):UNINTERESTING
307 blobs:5
308 commits:1
309 tags:1
310 trees:3
311 EOF
312
313 test_cmp_sorted expect out
314 '
315
316 test_expect_success 'topic, not base, only blobs' '
317 test-tool path-walk --no-trees --no-commits \
318 -- topic --not base >out &&
319
320 cat >expect <<-EOF &&
321 0:blob:a:$(git rev-parse topic:a):UNINTERESTING
322 1:blob:left/b:$(git rev-parse topic:left/b):UNINTERESTING
323 2:blob:right/c:$(git rev-parse topic:right/c)
324 3:blob:right/d:$(git rev-parse topic:right/d):UNINTERESTING
325 blobs:4
326 commits:0
327 tags:0
328 trees:0
329 EOF
330
331 test_cmp_sorted expect out
332 '
333
334 # No, this doesn't make a lot of sense for the path-walk API,
335 # but it is possible to do.
336 test_expect_success 'topic, not base, only commits' '
337 test-tool path-walk --no-blobs --no-trees \
338 -- topic --not base >out &&
339
340 cat >expect <<-EOF &&
341 0:commit::$(git rev-parse topic)
342 commits:1
343 blobs:0
344 tags:0
345 trees:0
346 EOF
347
348 test_cmp_sorted expect out
349 '
350
351 test_expect_success 'topic, not base, only trees' '
352 test-tool path-walk --no-blobs --no-commits \
353 -- topic --not base >out &&
354
355 cat >expect <<-EOF &&
356 0:tree::$(git rev-parse topic^{tree})
357 1:tree:left/:$(git rev-parse topic:left):UNINTERESTING
358 2:tree:right/:$(git rev-parse topic:right)
359 commits:0
360 blobs:0
361 tags:0
362 trees:3
363 EOF
364
365 test_cmp_sorted expect out
366 '
367
368 test_expect_success 'topic, not base, boundary' '
369 test-tool path-walk -- --boundary topic --not base >out &&
370
371 cat >expect <<-EOF &&
372 0:commit::$(git rev-parse topic)
373 0:commit::$(git rev-parse base~1):UNINTERESTING
374 1:tree::$(git rev-parse topic^{tree})
375 1:tree::$(git rev-parse base~1^{tree}):UNINTERESTING
376 2:blob:a:$(git rev-parse base~1:a):UNINTERESTING
377 3:tree:left/:$(git rev-parse base~1:left):UNINTERESTING
378 4:blob:left/b:$(git rev-parse base~1:left/b):UNINTERESTING
379 5:tree:right/:$(git rev-parse topic:right)
380 5:tree:right/:$(git rev-parse base~1:right):UNINTERESTING
381 6:blob:right/c:$(git rev-parse base~1:right/c):UNINTERESTING
382 6:blob:right/c:$(git rev-parse topic:right/c)
383 7:blob:right/d:$(git rev-parse base~1:right/d):UNINTERESTING
384 blobs:5
385 commits:2
386 tags:0
387 trees:5
388 EOF
389
390 test_cmp_sorted expect out
391 '
392
393 test_expect_success 'topic, not base, boundary with pruning' '
394 test-tool path-walk --prune -- --boundary topic --not base >out &&
395
396 cat >expect <<-EOF &&
397 0:commit::$(git rev-parse topic)
398 0:commit::$(git rev-parse base~1):UNINTERESTING
399 1:tree::$(git rev-parse topic^{tree})
400 1:tree::$(git rev-parse base~1^{tree}):UNINTERESTING
401 2:tree:right/:$(git rev-parse topic:right)
402 2:tree:right/:$(git rev-parse base~1:right):UNINTERESTING
403 3:blob:right/c:$(git rev-parse base~1:right/c):UNINTERESTING
404 3:blob:right/c:$(git rev-parse topic:right/c)
405 blobs:2
406 commits:2
407 tags:0
408 trees:4
409 EOF
410
411 test_cmp_sorted expect out
412 '
413
414 test_expect_success 'topic, not base, --edge-aggressive with pruning' '
415 test-tool path-walk --prune --edge-aggressive -- topic --not base >out &&
416
417 cat >expect <<-EOF &&
418 0:commit::$(git rev-parse topic)
419 1:tree::$(git rev-parse topic^{tree})
420 1:tree::$(git rev-parse base^{tree}):UNINTERESTING
421 2:tree:right/:$(git rev-parse topic:right)
422 2:tree:right/:$(git rev-parse base:right):UNINTERESTING
423 3:blob:right/c:$(git rev-parse base:right/c):UNINTERESTING
424 3:blob:right/c:$(git rev-parse topic:right/c)
425 blobs:2
426 commits:1
427 tags:0
428 trees:4
429 EOF
430
431 test_cmp_sorted expect out
432 '
433
434 test_expect_success 'trees are reported exactly once' '
435 test_when_finished "rm -rf unique-trees" &&
436 test_create_repo unique-trees &&
437 (
438 cd unique-trees &&
439 mkdir initial &&
440 test_commit initial/file &&
441 git switch -c move-to-top &&
442 git mv initial/file.t ./ &&
443 test_tick &&
444 git commit -m moved &&
445 git update-ref refs/heads/other HEAD
446 ) &&
447 test-tool -C unique-trees path-walk -- --all >out &&
448 tree=$(git -C unique-trees rev-parse HEAD:) &&
449 grep "$tree" out >out-filtered &&
450 test_line_count = 1 out-filtered
451 '
452
453 test_expect_success 'all, blob:none filter' '
454 test-tool path-walk --filter=blob:none -- --all >out &&
455
456 cat >expect <<-EOF &&
457 0:commit::$(git rev-parse topic)
458 0:commit::$(git rev-parse base)
459 0:commit::$(git rev-parse base~1)
460 0:commit::$(git rev-parse base~2)
461 1:tag:/tags:$(git rev-parse refs/tags/first)
462 1:tag:/tags:$(git rev-parse refs/tags/second.1)
463 1:tag:/tags:$(git rev-parse refs/tags/second.2)
464 1:tag:/tags:$(git rev-parse refs/tags/third)
465 1:tag:/tags:$(git rev-parse refs/tags/fourth)
466 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
467 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
468 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
469 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
470 3:tree::$(git rev-parse topic^{tree})
471 3:tree::$(git rev-parse base^{tree})
472 3:tree::$(git rev-parse base~1^{tree})
473 3:tree::$(git rev-parse base~2^{tree})
474 4:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
475 4:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
476 5:tree:a/:$(git rev-parse base:a)
477 6:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
478 7:tree:left/:$(git rev-parse base:left)
479 7:tree:left/:$(git rev-parse base~2:left)
480 8:tree:right/:$(git rev-parse topic:right)
481 8:tree:right/:$(git rev-parse base~1:right)
482 8:tree:right/:$(git rev-parse base~2:right)
483 blobs:2
484 commits:4
485 tags:7
486 trees:13
487 EOF
488
489 test_cmp_sorted expect out
490 '
491
492 test_expect_success 'topic only, blob:none filter' '
493 test-tool path-walk --filter=blob:none -- topic >out &&
494
495 cat >expect <<-EOF &&
496 0:commit::$(git rev-parse topic)
497 0:commit::$(git rev-parse base~1)
498 0:commit::$(git rev-parse base~2)
499 1:tree::$(git rev-parse topic^{tree})
500 1:tree::$(git rev-parse base~1^{tree})
501 1:tree::$(git rev-parse base~2^{tree})
502 2:tree:left/:$(git rev-parse base~2:left)
503 3:tree:right/:$(git rev-parse topic:right)
504 3:tree:right/:$(git rev-parse base~1:right)
505 3:tree:right/:$(git rev-parse base~2:right)
506 blobs:0
507 commits:3
508 tags:0
509 trees:7
510 EOF
511
512 test_cmp_sorted expect out
513 '
514
515 test_expect_success 'all, blob:limit=0 filter' '
516 test-tool path-walk --filter=blob:limit=0 -- --all >out &&
517
518 cat >expect <<-EOF &&
519 0:commit::$(git rev-parse topic)
520 0:commit::$(git rev-parse base)
521 0:commit::$(git rev-parse base~1)
522 0:commit::$(git rev-parse base~2)
523 1:tag:/tags:$(git rev-parse refs/tags/first)
524 1:tag:/tags:$(git rev-parse refs/tags/second.1)
525 1:tag:/tags:$(git rev-parse refs/tags/second.2)
526 1:tag:/tags:$(git rev-parse refs/tags/third)
527 1:tag:/tags:$(git rev-parse refs/tags/fourth)
528 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
529 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
530 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
531 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
532 3:tree::$(git rev-parse topic^{tree})
533 3:tree::$(git rev-parse base^{tree})
534 3:tree::$(git rev-parse base~1^{tree})
535 3:tree::$(git rev-parse base~2^{tree})
536 4:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
537 4:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
538 5:tree:a/:$(git rev-parse base:a)
539 6:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
540 7:tree:left/:$(git rev-parse base:left)
541 7:tree:left/:$(git rev-parse base~2:left)
542 8:tree:right/:$(git rev-parse topic:right)
543 8:tree:right/:$(git rev-parse base~1:right)
544 8:tree:right/:$(git rev-parse base~2:right)
545 blobs:2
546 commits:4
547 tags:7
548 trees:13
549 EOF
550
551 test_cmp_sorted expect out
552 '
553
554 test_expect_success 'all, blob:limit=3 filter' '
555 test-tool path-walk --filter=blob:limit=3 -- --all >out &&
556
557 cat >expect <<-EOF &&
558 0:commit::$(git rev-parse topic)
559 0:commit::$(git rev-parse base)
560 0:commit::$(git rev-parse base~1)
561 0:commit::$(git rev-parse base~2)
562 1:tag:/tags:$(git rev-parse refs/tags/first)
563 1:tag:/tags:$(git rev-parse refs/tags/second.1)
564 1:tag:/tags:$(git rev-parse refs/tags/second.2)
565 1:tag:/tags:$(git rev-parse refs/tags/third)
566 1:tag:/tags:$(git rev-parse refs/tags/fourth)
567 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
568 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
569 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
570 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
571 3:tree::$(git rev-parse topic^{tree})
572 3:tree::$(git rev-parse base^{tree})
573 3:tree::$(git rev-parse base~1^{tree})
574 3:tree::$(git rev-parse base~2^{tree})
575 4:blob:a:$(git rev-parse base~2:a)
576 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
577 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
578 6:tree:a/:$(git rev-parse base:a)
579 7:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
580 8:tree:left/:$(git rev-parse base:left)
581 8:tree:left/:$(git rev-parse base~2:left)
582 9:blob:left/b:$(git rev-parse base~2:left/b)
583 10:tree:right/:$(git rev-parse topic:right)
584 10:tree:right/:$(git rev-parse base~1:right)
585 10:tree:right/:$(git rev-parse base~2:right)
586 11:blob:right/c:$(git rev-parse base~2:right/c)
587 12:blob:right/d:$(git rev-parse base~1:right/d)
588 blobs:6
589 commits:4
590 tags:7
591 trees:13
592 EOF
593
594 test_cmp_sorted expect out
595 '
596
597 test_expect_success 'all, tree:0 filter' '
598 test-tool path-walk --filter=tree:0 -- --all >out &&
599
600 cat >expect <<-EOF &&
601 0:commit::$(git rev-parse topic)
602 0:commit::$(git rev-parse base)
603 0:commit::$(git rev-parse base~1)
604 0:commit::$(git rev-parse base~2)
605 1:tag:/tags:$(git rev-parse refs/tags/first)
606 1:tag:/tags:$(git rev-parse refs/tags/second.1)
607 1:tag:/tags:$(git rev-parse refs/tags/second.2)
608 1:tag:/tags:$(git rev-parse refs/tags/third)
609 1:tag:/tags:$(git rev-parse refs/tags/fourth)
610 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
611 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
612 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
613 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
614 3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{tree})
615 3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2)
616 blobs:2
617 commits:4
618 tags:7
619 trees:2
620 EOF
621
622 test_cmp_sorted expect out
623 '
624
625 test_expect_success 'topic only, tree:0 filter' '
626 test-tool path-walk --filter=tree:0 -- topic >out &&
627
628 cat >expect <<-EOF &&
629 0:commit::$(git rev-parse topic)
630 0:commit::$(git rev-parse base~1)
631 0:commit::$(git rev-parse base~2)
632 blobs:0
633 commits:3
634 tags:0
635 trees:0
636 EOF
637
638 test_cmp_sorted expect out
639 '
640
641 test_expect_success 'tree:1 filter is rejected' '
642 test_must_fail test-tool path-walk --filter=tree:1 -- --all 2>err &&
643 test_grep "tree:1 filter not supported by the path-walk API" err
644 '
645
646 test_expect_success 'all, object:type=commit filter' '
647 test-tool path-walk --filter=object:type=commit -- --all >out &&
648
649 cat >expect <<-EOF &&
650 0:commit::$(git rev-parse topic)
651 0:commit::$(git rev-parse base)
652 0:commit::$(git rev-parse base~1)
653 0:commit::$(git rev-parse base~2)
654 blobs:0
655 commits:4
656 tags:0
657 trees:0
658 EOF
659
660 test_cmp_sorted expect out
661 '
662
663 test_expect_success 'all, object:type=tag filter' '
664 test-tool path-walk --filter=object:type=tag -- --all >out &&
665
666 cat >expect <<-EOF &&
667 0:tag:/tags:$(git rev-parse refs/tags/first)
668 0:tag:/tags:$(git rev-parse refs/tags/second.1)
669 0:tag:/tags:$(git rev-parse refs/tags/second.2)
670 0:tag:/tags:$(git rev-parse refs/tags/third)
671 0:tag:/tags:$(git rev-parse refs/tags/fourth)
672 0:tag:/tags:$(git rev-parse refs/tags/tree-tag)
673 0:tag:/tags:$(git rev-parse refs/tags/blob-tag)
674 blobs:0
675 commits:0
676 tags:7
677 trees:0
678 EOF
679
680 test_cmp_sorted expect out
681 '
682
683 test_expect_success 'all, object:type=tree filter' '
684 test-tool path-walk --filter=object:type=tree -- --all >out &&
685
686 cat >expect <<-EOF &&
687 0:tree::$(git rev-parse topic^{tree})
688 0:tree::$(git rev-parse base^{tree})
689 0:tree::$(git rev-parse base~1^{tree})
690 0:tree::$(git rev-parse base~2^{tree})
691 1:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
692 1:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
693 2:tree:a/:$(git rev-parse base:a)
694 3:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
695 4:tree:left/:$(git rev-parse base:left)
696 4:tree:left/:$(git rev-parse base~2:left)
697 5:tree:right/:$(git rev-parse topic:right)
698 5:tree:right/:$(git rev-parse base~1:right)
699 5:tree:right/:$(git rev-parse base~2:right)
700 blobs:0
701 commits:0
702 tags:0
703 trees:13
704 EOF
705
706 test_cmp_sorted expect out
707 '
708
709 test_expect_success 'all, object:type=blob filter' '
710 test-tool path-walk --filter=object:type=blob -- --all >out &&
711
712 cat >expect <<-EOF &&
713 0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
714 0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
715 1:blob:a:$(git rev-parse base~2:a)
716 2:blob:left/b:$(git rev-parse base:left/b)
717 2:blob:left/b:$(git rev-parse base~2:left/b)
718 3:blob:right/c:$(git rev-parse base~2:right/c)
719 3:blob:right/c:$(git rev-parse topic:right/c)
720 4:blob:right/d:$(git rev-parse base~1:right/d)
721 blobs:8
722 commits:0
723 tags:0
724 trees:0
725 EOF
726
727 test_cmp_sorted expect out
728 '
729
730 test_expect_success 'all, combine:blob:none+tree:0 filter' '
731 test-tool path-walk \
732 --filter=combine:blob:none+tree:0 -- --all >out &&
733
734 cat >expect <<-EOF &&
735 0:commit::$(git rev-parse topic)
736 0:commit::$(git rev-parse base)
737 0:commit::$(git rev-parse base~1)
738 0:commit::$(git rev-parse base~2)
739 1:tag:/tags:$(git rev-parse refs/tags/first)
740 1:tag:/tags:$(git rev-parse refs/tags/second.1)
741 1:tag:/tags:$(git rev-parse refs/tags/second.2)
742 1:tag:/tags:$(git rev-parse refs/tags/third)
743 1:tag:/tags:$(git rev-parse refs/tags/fourth)
744 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
745 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
746 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
747 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
748 3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{tree})
749 3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2)
750 blobs:2
751 commits:4
752 tags:7
753 trees:2
754 EOF
755
756 test_cmp_sorted expect out
757 '
758
759 test_expect_success 'all, combine:object:type=blob+blob:limit=3 filter' '
760 test-tool path-walk \
761 --filter=combine:object:type=blob+blob:limit=3 \
762 -- --all >out &&
763
764 cat >expect <<-EOF &&
765 0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
766 0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
767 1:blob:a:$(git rev-parse base~2:a)
768 2:blob:left/b:$(git rev-parse base~2:left/b)
769 3:blob:right/c:$(git rev-parse base~2:right/c)
770 4:blob:right/d:$(git rev-parse base~1:right/d)
771 blobs:6
772 commits:0
773 tags:0
774 trees:0
775 EOF
776
777 test_cmp_sorted expect out
778 '
779
780 test_expect_success 'all, combine of disjoint object:types is empty' '
781 test-tool path-walk \
782 --filter=combine:object:type=blob+object:type=tree \
783 -- --all >out &&
784
785 cat >expect <<-EOF &&
786 blobs:0
787 commits:0
788 tags:0
789 trees:0
790 EOF
791
792 test_cmp_sorted expect out
793 '
794
795 test_expect_success 'combine: rejects unsupported subfilters' '
796 test_must_fail test-tool path-walk \
797 --filter=combine:tree:1+blob:none -- --all 2>err &&
798 test_grep "tree:1 filter not supported by the path-walk API" err
799 '
800
801 test_expect_success 'setup sparse filter blob' '
802 # Cone-mode patterns: include root, exclude all dirs, include left/
803 cat >patterns <<-\EOF &&
804 /*
805 !/*/
806 /left/
807 EOF
808 sparse_oid=$(git hash-object -w -t blob patterns)
809 '
810
811 test_expect_success 'all, sparse:oid filter' '
812 test-tool path-walk --filter=sparse:oid=$sparse_oid -- --all >out &&
813
814 cat >expect <<-EOF &&
815 0:commit::$(git rev-parse topic)
816 0:commit::$(git rev-parse base)
817 0:commit::$(git rev-parse base~1)
818 0:commit::$(git rev-parse base~2)
819 1:tag:/tags:$(git rev-parse refs/tags/first)
820 1:tag:/tags:$(git rev-parse refs/tags/second.1)
821 1:tag:/tags:$(git rev-parse refs/tags/second.2)
822 1:tag:/tags:$(git rev-parse refs/tags/third)
823 1:tag:/tags:$(git rev-parse refs/tags/fourth)
824 1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
825 1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
826 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
827 2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
828 3:tree::$(git rev-parse topic^{tree})
829 3:tree::$(git rev-parse base^{tree})
830 3:tree::$(git rev-parse base~1^{tree})
831 3:tree::$(git rev-parse base~2^{tree})
832 4:blob:a:$(git rev-parse base~2:a)
833 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
834 5:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
835 6:blob:file2:$(git rev-parse refs/tags/tree-tag2^{}:file2)
836 7:tree:a/:$(git rev-parse base:a)
837 8:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
838 9:tree:left/:$(git rev-parse base:left)
839 9:tree:left/:$(git rev-parse base~2:left)
840 10:blob:left/b:$(git rev-parse base~2:left/b)
841 10:blob:left/b:$(git rev-parse base:left/b)
842 11:tree:right/:$(git rev-parse topic:right)
843 11:tree:right/:$(git rev-parse base~1:right)
844 11:tree:right/:$(git rev-parse base~2:right)
845 blobs:6
846 commits:4
847 tags:7
848 trees:13
849 EOF
850
851 test_cmp_sorted expect out
852 '
853
854 test_expect_success 'topic only, sparse:oid filter' '
855 test-tool path-walk --filter=sparse:oid=$sparse_oid -- topic >out &&
856
857 cat >expect <<-EOF &&
858 0:commit::$(git rev-parse topic)
859 0:commit::$(git rev-parse base~1)
860 0:commit::$(git rev-parse base~2)
861 1:tree::$(git rev-parse topic^{tree})
862 1:tree::$(git rev-parse base~1^{tree})
863 1:tree::$(git rev-parse base~2^{tree})
864 2:blob:a:$(git rev-parse base~2:a)
865 3:tree:left/:$(git rev-parse base~2:left)
866 4:blob:left/b:$(git rev-parse base~2:left/b)
867 5:tree:right/:$(git rev-parse topic:right)
868 5:tree:right/:$(git rev-parse base~1:right)
869 5:tree:right/:$(git rev-parse base~2:right)
870 blobs:2
871 commits:3
872 tags:0
873 trees:7
874 EOF
875
876 test_cmp_sorted expect out
877 '
878
879 # Demonstrate the SEEN flag ordering issue: when the same tree/blob OID
880 # appears at two sibling paths where one is in-cone and the other is
881 # out-of-cone, the path-walk must still discover blobs at the in-cone
882 # path even when the shared tree OID was first encountered out-of-cone.
883 # Since sparse:oid includes all trees, the out-of-cone tree (aaa/) is
884 # walked first, and its blob is skipped. The path-walk then re-walks
885 # the same tree OID at the in-cone path (zzz/) to find the blob there.
886
887 test_expect_success 'setup shared tree OID across cone boundary' '
888 git checkout --orphan shared-tree &&
889 git rm -rf . &&
890 mkdir aaa zzz &&
891 echo "shared content" >aaa/file &&
892 echo "shared content" >zzz/file &&
893 echo "root file" >rootfile &&
894 git add aaa zzz rootfile &&
895 git commit -m "aaa and zzz have same tree OID" &&
896
897 # Verify they really share a tree OID
898 aaa_tree=$(git rev-parse HEAD:aaa) &&
899 zzz_tree=$(git rev-parse HEAD:zzz) &&
900 test "$aaa_tree" = "$zzz_tree" &&
901
902 # Cone pattern: include root + zzz/ (not aaa/)
903 cat >shared-patterns <<-\EOF &&
904 /*
905 !/*/
906 /zzz/
907 EOF
908 shared_sparse_oid=$(git hash-object -w -t blob shared-patterns)
909 '
910
911 test_expect_success 'sparse:oid with shared tree OID across cone boundary' '
912 test-tool path-walk \
913 --filter=sparse:oid=$shared_sparse_oid \
914 -- shared-tree >out &&
915
916 cat >expect <<-EOF &&
917 0:commit::$(git rev-parse shared-tree)
918 1:tree::$(git rev-parse shared-tree^{tree})
919 2:blob:rootfile:$(git rev-parse shared-tree:rootfile)
920 3:tree:aaa/:$(git rev-parse shared-tree:aaa)
921 4:tree:zzz/:$(git rev-parse shared-tree:zzz)
922 5:blob:zzz/file:$(git rev-parse shared-tree:zzz/file)
923 blobs:2
924 commits:1
925 tags:0
926 trees:3
927 EOF
928
929 test_cmp_sorted expect out
930 '
931
932 test_done