Raw
1 git_for_each_ref=${git_for_each_ref:-git for-each-ref}
2 GNUPGHOME_NOT_USED=$GNUPGHOME
3 . "$TEST_DIRECTORY"/lib-gpg.sh
4 . "$TEST_DIRECTORY"/lib-terminal.sh
5
6 # Mon Jul 3 23:18:43 2006 +0000
7 datestamp=1151968723
8 setdate_and_increment () {
9 GIT_COMMITTER_DATE="$datestamp +0200"
10 datestamp=$(expr "$datestamp" + 1)
11 GIT_AUTHOR_DATE="$datestamp +0200"
12 datestamp=$(expr "$datestamp" + 1)
13 export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
14 }
15
16 test_object_file_size () {
17 oid=$(git rev-parse "$1")
18 path=".git/objects/$(test_oid_to_path $oid)"
19 test_file_size "$path"
20 }
21
22 test_expect_success setup '
23 # setup .mailmap
24 cat >.mailmap <<-EOF &&
25 A Thor <athor@example.com> A U Thor <author@example.com>
26 C Mitter <cmitter@example.com> C O Mitter <committer@example.com>
27 EOF
28
29 setdate_and_increment &&
30 echo "Using $datestamp" > one &&
31 git add one &&
32 git commit -m "Initial" &&
33 git branch -M main &&
34 setdate_and_increment &&
35 git tag -a -m "Tagging at $datestamp" testtag &&
36 git update-ref refs/remotes/origin/main main &&
37 git remote add origin nowhere &&
38 git config branch.main.remote origin &&
39 git config branch.main.merge refs/heads/main &&
40 git remote add myfork elsewhere &&
41 git config remote.pushdefault myfork &&
42 git config push.default current
43 '
44
45 test_atom () {
46 case "$1" in
47 head) ref=refs/heads/main ;;
48 tag) ref=refs/tags/testtag ;;
49 sym) ref=refs/heads/sym ;;
50 *) ref=$1 ;;
51 esac
52 format=$2
53 test_do=test_expect_${4:-success}
54
55 printf '%s\n' "$3" >expected
56 $test_do $PREREQ "basic atom: $ref $format" '
57 ${git_for_each_ref} --format="%($format)" "$ref" >actual &&
58 sanitize_pgp <actual >actual.clean &&
59 test_cmp expected actual.clean
60 '
61
62 # Automatically test "contents:size" atom after testing "contents"
63 if test "$format" = "contents"
64 then
65 # for commit leg, $3 is changed there
66 expect=$(printf '%s' "$3" | wc -c)
67 $test_do $PREREQ "basic atom: $ref contents:size" '
68 type=$(git cat-file -t "$ref") &&
69 case $type in
70 tag)
71 # We cannot use $3 as it expects sanitize_pgp to run
72 git cat-file tag $ref >out &&
73 expect=$(tail -n +6 out | wc -c) &&
74 rm -f out ;;
75 tree | blob)
76 expect="" ;;
77 commit)
78 : "use the calculated expect" ;;
79 *)
80 BUG "unknown object type" ;;
81 esac &&
82 # Leave $expect unquoted to lose possible leading whitespaces
83 echo $expect >expected &&
84 ${git_for_each_ref} --format="%(contents:size)" "$ref" >actual &&
85 test_cmp expected actual
86 '
87 fi
88 }
89
90 hexlen=$(test_oid hexsz)
91
92 test_atom head refname refs/heads/main
93 test_atom head refname: refs/heads/main
94 test_atom head refname:short main
95 test_atom head refname:lstrip=1 heads/main
96 test_atom head refname:lstrip=2 main
97 test_atom head refname:lstrip=-1 main
98 test_atom head refname:lstrip=-2 heads/main
99 test_atom head refname:rstrip=1 refs/heads
100 test_atom head refname:rstrip=2 refs
101 test_atom head refname:rstrip=-1 refs
102 test_atom head refname:rstrip=-2 refs/heads
103 test_atom head refname:strip=1 heads/main
104 test_atom head refname:strip=2 main
105 test_atom head refname:strip=-1 main
106 test_atom head refname:strip=-2 heads/main
107 test_atom head upstream refs/remotes/origin/main
108 test_atom head upstream:short origin/main
109 test_atom head upstream:lstrip=2 origin/main
110 test_atom head upstream:lstrip=-2 origin/main
111 test_atom head upstream:rstrip=2 refs/remotes
112 test_atom head upstream:rstrip=-2 refs/remotes
113 test_atom head upstream:strip=2 origin/main
114 test_atom head upstream:strip=-2 origin/main
115 test_atom head push refs/remotes/myfork/main
116 test_atom head push:short myfork/main
117 test_atom head push:lstrip=1 remotes/myfork/main
118 test_atom head push:lstrip=-1 main
119 test_atom head push:rstrip=1 refs/remotes/myfork
120 test_atom head push:rstrip=-1 refs
121 test_atom head push:strip=1 remotes/myfork/main
122 test_atom head push:strip=-1 main
123 test_atom head objecttype commit
124 test_atom head objectsize $((131 + hexlen))
125 test_atom head objectsize:disk $(test_object_file_size refs/heads/main)
126 test_atom head deltabase $ZERO_OID
127 test_atom head objectname $(git rev-parse refs/heads/main)
128 test_atom head objectname:short $(git rev-parse --short refs/heads/main)
129 test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
130 test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
131 test_atom head tree $(git rev-parse refs/heads/main^{tree})
132 test_atom head tree:short $(git rev-parse --short refs/heads/main^{tree})
133 test_atom head tree:short=1 $(git rev-parse --short=1 refs/heads/main^{tree})
134 test_atom head tree:short=10 $(git rev-parse --short=10 refs/heads/main^{tree})
135 test_atom head parent ''
136 test_atom head parent:short ''
137 test_atom head parent:short=1 ''
138 test_atom head parent:short=10 ''
139 test_atom head numparent 0
140 test_atom head object ''
141 test_atom head type ''
142 test_atom head raw "$(git cat-file commit refs/heads/main)
143 "
144 test_atom head '*objectname' ''
145 test_atom head '*objecttype' ''
146 test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
147 test_atom head authorname 'A U Thor'
148 test_atom head authorname:mailmap 'A Thor'
149 test_atom head authoremail '<author@example.com>'
150 test_atom head authoremail:trim 'author@example.com'
151 test_atom head authoremail:localpart 'author'
152 test_atom head authoremail:trim,localpart 'author'
153 test_atom head authoremail:mailmap '<athor@example.com>'
154 test_atom head authoremail:mailmap,trim 'athor@example.com'
155 test_atom head authoremail:trim,mailmap 'athor@example.com'
156 test_atom head authoremail:mailmap,localpart 'athor'
157 test_atom head authoremail:localpart,mailmap 'athor'
158 test_atom head authoremail:mailmap,trim,localpart,mailmap,trim 'athor'
159 test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
160 test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
161 test_atom head committername 'C O Mitter'
162 test_atom head committername:mailmap 'C Mitter'
163 test_atom head committeremail '<committer@example.com>'
164 test_atom head committeremail:trim 'committer@example.com'
165 test_atom head committeremail:localpart 'committer'
166 test_atom head committeremail:localpart,trim 'committer'
167 test_atom head committeremail:mailmap '<cmitter@example.com>'
168 test_atom head committeremail:mailmap,trim 'cmitter@example.com'
169 test_atom head committeremail:trim,mailmap 'cmitter@example.com'
170 test_atom head committeremail:mailmap,localpart 'cmitter'
171 test_atom head committeremail:localpart,mailmap 'cmitter'
172 test_atom head committeremail:trim,mailmap,trim,trim,localpart 'cmitter'
173 test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
174 test_atom head tag ''
175 test_atom head tagger ''
176 test_atom head taggername ''
177 test_atom head taggeremail ''
178 test_atom head taggeremail:trim ''
179 test_atom head taggeremail:localpart ''
180 test_atom head taggerdate ''
181 test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'
182 test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'
183 test_atom head subject 'Initial'
184 test_atom head subject:sanitize 'Initial'
185 test_atom head contents:subject 'Initial'
186 test_atom head body ''
187 test_atom head contents:body ''
188 test_atom head contents:signature ''
189 test_atom head contents 'Initial
190 '
191 test_atom head HEAD '*'
192
193 test_atom tag refname refs/tags/testtag
194 test_atom tag refname:short testtag
195 test_atom tag upstream ''
196 test_atom tag push ''
197 test_atom tag objecttype tag
198 test_atom tag objectsize $((114 + hexlen))
199 test_atom tag objectsize:disk $(test_object_file_size refs/tags/testtag)
200 test_atom tag '*objectsize:disk' $(test_object_file_size refs/heads/main)
201 test_atom tag deltabase $ZERO_OID
202 test_atom tag '*deltabase' $ZERO_OID
203 test_atom tag objectname $(git rev-parse refs/tags/testtag)
204 test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
205 test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
206 test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
207 test_atom tag tree ''
208 test_atom tag tree:short ''
209 test_atom tag tree:short=1 ''
210 test_atom tag tree:short=10 ''
211 test_atom tag parent ''
212 test_atom tag parent:short ''
213 test_atom tag parent:short=1 ''
214 test_atom tag parent:short=10 ''
215 test_atom tag numparent ''
216 test_atom tag object $(git rev-parse refs/tags/testtag^0)
217 test_atom tag type 'commit'
218 test_atom tag '*objectname' $(git rev-parse refs/tags/testtag^{})
219 test_atom tag '*objecttype' 'commit'
220 test_atom tag author ''
221 test_atom tag authorname ''
222 test_atom tag authorname:mailmap ''
223 test_atom tag authoremail ''
224 test_atom tag authoremail:trim ''
225 test_atom tag authoremail:localpart ''
226 test_atom tag authoremail:trim,localpart ''
227 test_atom tag authoremail:mailmap ''
228 test_atom tag authoremail:mailmap,trim ''
229 test_atom tag authoremail:trim,mailmap ''
230 test_atom tag authoremail:mailmap,localpart ''
231 test_atom tag authoremail:localpart,mailmap ''
232 test_atom tag authoremail:mailmap,trim,localpart,mailmap,trim ''
233 test_atom tag authordate ''
234 test_atom tag committer ''
235 test_atom tag committername ''
236 test_atom tag committername:mailmap ''
237 test_atom tag committeremail ''
238 test_atom tag committeremail:trim ''
239 test_atom tag committeremail:localpart ''
240 test_atom tag committeremail:localpart,trim ''
241 test_atom tag committeremail:mailmap ''
242 test_atom tag committeremail:mailmap,trim ''
243 test_atom tag committeremail:trim,mailmap ''
244 test_atom tag committeremail:mailmap,localpart ''
245 test_atom tag committeremail:localpart,mailmap ''
246 test_atom tag committeremail:trim,mailmap,trim,trim,localpart ''
247 test_atom tag committerdate ''
248 test_atom tag tag 'testtag'
249 test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
250 test_atom tag taggername 'C O Mitter'
251 test_atom tag taggername:mailmap 'C Mitter'
252 test_atom tag taggeremail '<committer@example.com>'
253 test_atom tag taggeremail:trim 'committer@example.com'
254 test_atom tag taggeremail:localpart 'committer'
255 test_atom tag taggeremail:trim,localpart 'committer'
256 test_atom tag taggeremail:mailmap '<cmitter@example.com>'
257 test_atom tag taggeremail:mailmap,trim 'cmitter@example.com'
258 test_atom tag taggeremail:trim,mailmap 'cmitter@example.com'
259 test_atom tag taggeremail:mailmap,localpart 'cmitter'
260 test_atom tag taggeremail:localpart,mailmap 'cmitter'
261 test_atom tag taggeremail:trim,mailmap,trim,localpart,localpart 'cmitter'
262 test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
263 test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
264 test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
265 test_atom tag subject 'Tagging at 1151968727'
266 test_atom tag subject:sanitize 'Tagging-at-1151968727'
267 test_atom tag contents:subject 'Tagging at 1151968727'
268 test_atom tag body ''
269 test_atom tag contents:body ''
270 test_atom tag contents:signature ''
271 test_atom tag contents 'Tagging at 1151968727
272 '
273 test_atom tag HEAD ' '
274
275 test_expect_success 'basic atom: refs/tags/testtag *raw' '
276 git cat-file commit refs/tags/testtag^{} >expected &&
277 ${git_for_each_ref} --format="%(*raw)" refs/tags/testtag >actual &&
278 sanitize_pgp <expected >expected.clean &&
279 echo >>expected.clean &&
280 sanitize_pgp <actual >actual.clean &&
281 test_cmp expected.clean actual.clean
282 '
283
284 test_expect_success 'Check invalid atoms names are errors' '
285 test_must_fail ${git_for_each_ref} --format="%(INVALID)" refs/heads
286 '
287
288 test_expect_success 'Check format specifiers are ignored in naming date atoms' '
289 ${git_for_each_ref} --format="%(authordate)" refs/heads &&
290 ${git_for_each_ref} --format="%(authordate:default) %(authordate)" refs/heads &&
291 ${git_for_each_ref} --format="%(authordate) %(authordate:default)" refs/heads &&
292 ${git_for_each_ref} --format="%(authordate:default) %(authordate:default)" refs/heads
293 '
294
295 test_expect_success 'Check valid format specifiers for date fields' '
296 ${git_for_each_ref} --format="%(authordate:default)" refs/heads &&
297 ${git_for_each_ref} --format="%(authordate:relative)" refs/heads &&
298 ${git_for_each_ref} --format="%(authordate:short)" refs/heads &&
299 ${git_for_each_ref} --format="%(authordate:local)" refs/heads &&
300 ${git_for_each_ref} --format="%(authordate:iso8601)" refs/heads &&
301 ${git_for_each_ref} --format="%(authordate:rfc2822)" refs/heads
302 '
303
304 test_expect_success 'Check invalid format specifiers are errors' '
305 test_must_fail ${git_for_each_ref} --format="%(authordate:INVALID)" refs/heads
306 '
307
308 test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
309 test_must_fail ${git_for_each_ref} --format="%(objectname:short=0)" &&
310 test_must_fail ${git_for_each_ref} --format="%(objectname:short=-1)" &&
311 test_must_fail ${git_for_each_ref} --format="%(objectname:short=foo)"
312 '
313
314 test_bad_atom () {
315 case "$1" in
316 head) ref=refs/heads/main ;;
317 tag) ref=refs/tags/testtag ;;
318 sym) ref=refs/heads/sym ;;
319 *) ref=$1 ;;
320 esac
321 format=$2
322 test_do=test_expect_${4:-success}
323
324 printf '%s\n' "$3" >expect
325 $test_do $PREREQ "err basic atom: $ref $format" '
326 test_must_fail ${git_for_each_ref} \
327 --format="%($format)" "$ref" 2>error &&
328 test_cmp expect error
329 '
330 }
331
332 test_bad_atom head 'authoremail:foo' \
333 'fatal: unrecognized %(authoremail) argument: foo'
334
335 test_bad_atom head 'authoremail:mailmap,trim,bar' \
336 'fatal: unrecognized %(authoremail) argument: bar'
337
338 test_bad_atom head 'authoremail:trim,' \
339 'fatal: unrecognized %(authoremail) argument: '
340
341 test_bad_atom head 'authoremail:mailmaptrim' \
342 'fatal: unrecognized %(authoremail) argument: trim'
343
344 test_bad_atom head 'committeremail: ' \
345 'fatal: unrecognized %(committeremail) argument: '
346
347 test_bad_atom head 'committeremail: trim,foo' \
348 'fatal: unrecognized %(committeremail) argument: trim,foo'
349
350 test_bad_atom head 'committeremail:mailmap,localpart ' \
351 'fatal: unrecognized %(committeremail) argument: '
352
353 test_bad_atom head 'committeremail:trim_localpart' \
354 'fatal: unrecognized %(committeremail) argument: _localpart'
355
356 test_bad_atom head 'committeremail:localpart,,,trim' \
357 'fatal: unrecognized %(committeremail) argument: ,,trim'
358
359 test_bad_atom tag 'taggeremail:mailmap,trim, foo ' \
360 'fatal: unrecognized %(taggeremail) argument: foo '
361
362 test_bad_atom tag 'taggeremail:trim,localpart,' \
363 'fatal: unrecognized %(taggeremail) argument: '
364
365 test_bad_atom tag 'taggeremail:mailmap;localpart trim' \
366 'fatal: unrecognized %(taggeremail) argument: ;localpart trim'
367
368 test_bad_atom tag 'taggeremail:localpart trim' \
369 'fatal: unrecognized %(taggeremail) argument: trim'
370
371 test_bad_atom tag 'taggeremail:mailmap,mailmap,trim,qux,localpart,trim' \
372 'fatal: unrecognized %(taggeremail) argument: qux,localpart,trim'
373
374 test_date () {
375 f=$1 &&
376 committer_date=$2 &&
377 author_date=$3 &&
378 tagger_date=$4 &&
379 cat >expected <<-EOF &&
380 'refs/heads/main' '$committer_date' '$author_date'
381 'refs/tags/testtag' '$tagger_date'
382 EOF
383 (
384 ${git_for_each_ref} --shell \
385 --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \
386 refs/heads &&
387 ${git_for_each_ref} --shell \
388 --format="%(refname) %(taggerdate${f:+:$f})" \
389 refs/tags
390 ) >actual &&
391 test_cmp expected actual
392 }
393
394 test_expect_success 'Check unformatted date fields output' '
395 test_date "" \
396 "Tue Jul 4 01:18:43 2006 +0200" \
397 "Tue Jul 4 01:18:44 2006 +0200" \
398 "Tue Jul 4 01:18:45 2006 +0200"
399 '
400
401 test_expect_success 'Check format "default" formatted date fields output' '
402 test_date default \
403 "Tue Jul 4 01:18:43 2006 +0200" \
404 "Tue Jul 4 01:18:44 2006 +0200" \
405 "Tue Jul 4 01:18:45 2006 +0200"
406 '
407
408 test_expect_success 'Check format "default-local" date fields output' '
409 test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006"
410 '
411
412 # Don't know how to do relative check because I can't know when this script
413 # is going to be run and can't fake the current time to git, and hence can't
414 # provide expected output. Instead, I'll just make sure that "relative"
415 # doesn't exit in error
416 test_expect_success 'Check format "relative" date fields output' '
417 f=relative &&
418 (${git_for_each_ref} --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
419 ${git_for_each_ref} --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual
420 '
421
422 # We just check that this is the same as "relative" for now.
423 test_expect_success 'Check format "relative-local" date fields output' '
424 test_date relative-local \
425 "$(${git_for_each_ref} --format="%(committerdate:relative)" refs/heads)" \
426 "$(${git_for_each_ref} --format="%(authordate:relative)" refs/heads)" \
427 "$(${git_for_each_ref} --format="%(taggerdate:relative)" refs/tags)"
428 '
429
430 test_expect_success 'Check format "short" date fields output' '
431 test_date short 2006-07-04 2006-07-04 2006-07-04
432 '
433
434 test_expect_success 'Check format "short-local" date fields output' '
435 test_date short-local 2006-07-03 2006-07-03 2006-07-03
436 '
437
438 test_expect_success 'Check format "local" date fields output' '
439 test_date local \
440 "Mon Jul 3 23:18:43 2006" \
441 "Mon Jul 3 23:18:44 2006" \
442 "Mon Jul 3 23:18:45 2006"
443 '
444
445 test_expect_success 'Check format "iso8601" date fields output' '
446 test_date iso8601 \
447 "2006-07-04 01:18:43 +0200" \
448 "2006-07-04 01:18:44 +0200" \
449 "2006-07-04 01:18:45 +0200"
450 '
451
452 test_expect_success 'Check format "iso8601-local" date fields output' '
453 test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000"
454 '
455
456 test_expect_success 'Check format "rfc2822" date fields output' '
457 test_date rfc2822 \
458 "Tue, 4 Jul 2006 01:18:43 +0200" \
459 "Tue, 4 Jul 2006 01:18:44 +0200" \
460 "Tue, 4 Jul 2006 01:18:45 +0200"
461 '
462
463 test_expect_success 'Check format "rfc2822-local" date fields output' '
464 test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000"
465 '
466
467 test_expect_success 'Check format "raw" date fields output' '
468 test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200"
469 '
470
471 test_expect_success 'Check format "raw-local" date fields output' '
472 test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000"
473 '
474
475 test_expect_success 'Check format of strftime date fields' '
476 echo "my date is 2006-07-04" >expected &&
477 ${git_for_each_ref} \
478 --format="%(authordate:format:my date is %Y-%m-%d)" \
479 refs/heads >actual &&
480 test_cmp expected actual
481 '
482
483 test_expect_success 'Check format of strftime-local date fields' '
484 echo "my date is 2006-07-03" >expected &&
485 ${git_for_each_ref} \
486 --format="%(authordate:format-local:my date is %Y-%m-%d)" \
487 refs/heads >actual &&
488 test_cmp expected actual
489 '
490
491 test_expect_success 'exercise strftime with odd fields' '
492 echo >expected &&
493 ${git_for_each_ref} --format="%(authordate:format:)" refs/heads >actual &&
494 test_cmp expected actual &&
495 long="long format -- $ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID" &&
496 echo $long >expected &&
497 ${git_for_each_ref} --format="%(authordate:format:$long)" refs/heads >actual &&
498 test_cmp expected actual
499 '
500
501 cat >expected <<\EOF
502 refs/heads/main
503 refs/remotes/origin/main
504 refs/tags/testtag
505 EOF
506
507 test_expect_success 'Verify ascending sort' '
508 ${git_for_each_ref} --format="%(refname)" --sort=refname >actual &&
509 test_cmp expected actual
510 '
511
512
513 cat >expected <<\EOF
514 refs/tags/testtag
515 refs/remotes/origin/main
516 refs/heads/main
517 EOF
518
519 test_expect_success 'Verify descending sort' '
520 ${git_for_each_ref} --format="%(refname)" --sort=-refname >actual &&
521 test_cmp expected actual
522 '
523
524 test_expect_success 'Give help even with invalid sort atoms' '
525 test_expect_code 129 ${git_for_each_ref} --sort=bogus -h >actual 2>&1 &&
526 grep "^usage: ${git_for_each_ref}" actual
527 '
528
529 cat >expected <<\EOF
530 refs/tags/testtag
531 refs/tags/testtag-2
532 EOF
533
534 test_expect_success 'exercise patterns with prefixes' '
535 git tag testtag-2 &&
536 test_when_finished "git tag -d testtag-2" &&
537 ${git_for_each_ref} --format="%(refname)" \
538 refs/tags/testtag refs/tags/testtag-2 >actual &&
539 test_cmp expected actual
540 '
541
542 cat >expected <<\EOF
543 refs/tags/testtag
544 refs/tags/testtag-2
545 EOF
546
547 test_expect_success 'exercise glob patterns with prefixes' '
548 git tag testtag-2 &&
549 test_when_finished "git tag -d testtag-2" &&
550 ${git_for_each_ref} --format="%(refname)" \
551 refs/tags/testtag "refs/tags/testtag-*" >actual &&
552 test_cmp expected actual
553 '
554
555 cat >expected <<\EOF
556 refs/tags/bar
557 refs/tags/baz
558 refs/tags/testtag
559 EOF
560
561 test_expect_success 'exercise patterns with prefix exclusions' '
562 for tag in foo/one foo/two foo/three bar baz
563 do
564 git tag "$tag" || return 1
565 done &&
566 test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
567 ${git_for_each_ref} --format="%(refname)" \
568 refs/tags/ --exclude=refs/tags/foo >actual &&
569 test_cmp expected actual
570 '
571
572 cat >expected <<\EOF
573 refs/tags/bar
574 refs/tags/baz
575 refs/tags/foo/one
576 refs/tags/testtag
577 EOF
578
579 test_expect_success 'exercise patterns with pattern exclusions' '
580 for tag in foo/one foo/two foo/three bar baz
581 do
582 git tag "$tag" || return 1
583 done &&
584 test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
585 ${git_for_each_ref} --format="%(refname)" \
586 refs/tags/ --exclude="refs/tags/foo/t*" >actual &&
587 test_cmp expected actual
588 '
589
590 cat >expected <<\EOF
591 'refs/heads/main'
592 'refs/remotes/origin/main'
593 'refs/tags/testtag'
594 EOF
595
596 test_expect_success 'Quoting style: shell' '
597 ${git_for_each_ref} --shell --format="%(refname)" >actual &&
598 test_cmp expected actual
599 '
600
601 test_expect_success 'Quoting style: perl' '
602 ${git_for_each_ref} --perl --format="%(refname)" >actual &&
603 test_cmp expected actual
604 '
605
606 test_expect_success 'Quoting style: python' '
607 ${git_for_each_ref} --python --format="%(refname)" >actual &&
608 test_cmp expected actual
609 '
610
611 cat >expected <<\EOF
612 "refs/heads/main"
613 "refs/remotes/origin/main"
614 "refs/tags/testtag"
615 EOF
616
617 test_expect_success 'Quoting style: tcl' '
618 ${git_for_each_ref} --tcl --format="%(refname)" >actual &&
619 test_cmp expected actual
620 '
621
622 for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
623 test_expect_success "more than one quoting style: $i" "
624 test_must_fail ${git_for_each_ref} $i 2>err &&
625 grep '^error: more than one quoting style' err
626 "
627 done
628
629 test_expect_success 'setup for upstream:track[short]' '
630 test_commit two
631 '
632
633 test_atom head upstream:track '[ahead 1]'
634 test_atom head upstream:trackshort '>'
635 test_atom head upstream:track,nobracket 'ahead 1'
636 test_atom head upstream:nobracket,track 'ahead 1'
637
638 test_expect_success 'setup for push:track[short]' '
639 test_commit third &&
640 git update-ref refs/remotes/myfork/main main &&
641 git reset main~1
642 '
643
644 test_atom head push:track '[behind 1]'
645 test_atom head push:trackshort '<'
646
647 test_expect_success 'Check that :track[short] cannot be used with other atoms' '
648 test_must_fail ${git_for_each_ref} --format="%(refname:track)" 2>/dev/null &&
649 test_must_fail ${git_for_each_ref} --format="%(refname:trackshort)" 2>/dev/null
650 '
651
652 test_expect_success 'Check that :track[short] works when upstream is invalid' '
653 cat >expected <<-\EOF &&
654 [gone]
655
656 EOF
657 test_when_finished "git config branch.main.merge refs/heads/main" &&
658 git config branch.main.merge refs/heads/does-not-exist &&
659 ${git_for_each_ref} \
660 --format="%(upstream:track)$LF%(upstream:trackshort)" \
661 refs/heads >actual &&
662 test_cmp expected actual
663 '
664
665 test_expect_success 'Check for invalid refname format' '
666 test_must_fail ${git_for_each_ref} --format="%(refname:INVALID)"
667 '
668
669 test_expect_success 'set up color tests' '
670 cat >expected.color <<-EOF &&
671 $(git rev-parse --short refs/heads/main) <GREEN>main<RESET>
672 $(git rev-parse --short refs/remotes/myfork/main) <GREEN>myfork/main<RESET>
673 $(git rev-parse --short refs/remotes/origin/main) <GREEN>origin/main<RESET>
674 $(git rev-parse --short refs/tags/testtag) <GREEN>testtag<RESET>
675 $(git rev-parse --short refs/tags/third) <GREEN>third<RESET>
676 $(git rev-parse --short refs/tags/two) <GREEN>two<RESET>
677 EOF
678 sed "s/<[^>]*>//g" <expected.color >expected.bare &&
679 color_format="%(objectname:short) %(color:green)%(refname:short)"
680 '
681
682 test_expect_success TTY '%(color) shows color with a tty' '
683 test_terminal ${git_for_each_ref} --format="$color_format" >actual.raw &&
684 test_decode_color <actual.raw >actual &&
685 test_cmp expected.color actual
686 '
687
688 test_expect_success '%(color) does not show color without tty' '
689 TERM=vt100 ${git_for_each_ref} --format="$color_format" >actual &&
690 test_cmp expected.bare actual
691 '
692
693 test_expect_success '--color can override tty check' '
694 ${git_for_each_ref} --color --format="$color_format" >actual.raw &&
695 test_decode_color <actual.raw >actual &&
696 test_cmp expected.color actual
697 '
698
699 test_expect_success 'color.ui=always does not override tty check' '
700 git -c color.ui=always ${git_for_each_ref#git} --format="$color_format" >actual &&
701 test_cmp expected.bare actual
702 '
703
704 test_expect_success 'setup for describe atom tests' '
705 git init -b master describe-repo &&
706 (
707 cd describe-repo &&
708
709 test_commit --no-tag one &&
710 git tag tagone &&
711
712 test_commit --no-tag two &&
713 git tag -a -m "tag two" tagtwo
714 )
715 '
716
717 test_expect_success 'describe atom vs git describe' '
718 (
719 cd describe-repo &&
720
721 ${git_for_each_ref} --format="%(objectname)" \
722 refs/tags/ >obj &&
723 while read hash
724 do
725 if desc=$(git describe $hash)
726 then
727 : >expect-contains-good
728 else
729 : >expect-contains-bad
730 fi &&
731 echo "$hash $desc" || return 1
732 done <obj >expect &&
733 test_path_exists expect-contains-good &&
734 test_path_exists expect-contains-bad &&
735
736 ${git_for_each_ref} --format="%(objectname) %(describe)" \
737 refs/tags/ >actual 2>err &&
738 test_cmp expect actual &&
739 test_must_be_empty err
740 )
741 '
742
743 test_expect_success 'describe:tags vs describe --tags' '
744 (
745 cd describe-repo &&
746 git describe --tags >expect &&
747 ${git_for_each_ref} --format="%(describe:tags)" \
748 refs/heads/master >actual &&
749 test_cmp expect actual
750 )
751 '
752
753 test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
754 (
755 cd describe-repo &&
756
757 # Case 1: We have commits between HEAD and the most
758 # recent tag reachable from it
759 test_commit --no-tag file &&
760 git describe --abbrev=14 >expect &&
761 ${git_for_each_ref} --format="%(describe:abbrev=14)" \
762 refs/heads/master >actual &&
763 test_cmp expect actual &&
764
765 # Make sure the hash used is at least 14 digits long
766 sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
767 test 15 -le $(wc -c <hexpart) &&
768
769 # Case 2: We have a tag at HEAD, describe directly gives
770 # the name of the tag
771 git tag -a -m tagged tagname &&
772 git describe --abbrev=14 >expect &&
773 ${git_for_each_ref} --format="%(describe:abbrev=14)" \
774 refs/heads/master >actual &&
775 test_cmp expect actual &&
776 test tagname = $(cat actual)
777 )
778 '
779
780 test_expect_success 'describe:match=... vs describe --match ...' '
781 (
782 cd describe-repo &&
783 git tag -a -m "tag foo" tag-foo &&
784 git describe --match "*-foo" >expect &&
785 ${git_for_each_ref} --format="%(describe:match="*-foo")" \
786 refs/heads/master >actual &&
787 test_cmp expect actual
788 )
789 '
790
791 test_expect_success 'describe:exclude:... vs describe --exclude ...' '
792 (
793 cd describe-repo &&
794 git tag -a -m "tag bar" tag-bar &&
795 git describe --exclude "*-bar" >expect &&
796 ${git_for_each_ref} --format="%(describe:exclude="*-bar")" \
797 refs/heads/master >actual &&
798 test_cmp expect actual
799 )
800 '
801
802 test_expect_success 'deref with describe atom' '
803 (
804 cd describe-repo &&
805 cat >expect <<-\EOF &&
806
807 tagname
808 tagname
809 tagname
810
811 tagtwo
812 EOF
813 ${git_for_each_ref} --format="%(*describe)" >actual &&
814 test_cmp expect actual
815 )
816 '
817
818 test_expect_success 'err on bad describe atom arg' '
819 (
820 cd describe-repo &&
821
822 # The bad arg is the only arg passed to describe atom
823 cat >expect <<-\EOF &&
824 fatal: unrecognized %(describe) argument: baz
825 EOF
826 test_must_fail ${git_for_each_ref} --format="%(describe:baz)" \
827 refs/heads/master 2>actual &&
828 test_cmp expect actual &&
829
830 # The bad arg is in the middle of the option string
831 # passed to the describe atom
832 cat >expect <<-\EOF &&
833 fatal: unrecognized %(describe) argument: qux=1,abbrev=14
834 EOF
835 test_must_fail ${git_for_each_ref} \
836 --format="%(describe:tags,qux=1,abbrev=14)" \
837 ref/heads/master 2>actual &&
838 test_cmp expect actual
839 )
840 '
841
842 cat >expected <<\EOF
843 heads/main
844 tags/main
845 EOF
846
847 test_expect_success 'Check ambiguous head and tag refs (strict)' '
848 git config --bool core.warnambiguousrefs true &&
849 git checkout -b newtag &&
850 echo "Using $datestamp" > one &&
851 git add one &&
852 git commit -m "Branch" &&
853 setdate_and_increment &&
854 git tag -m "Tagging at $datestamp" main &&
855 ${git_for_each_ref} --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
856 test_cmp expected actual
857 '
858
859 cat >expected <<\EOF
860 heads/main
861 main
862 EOF
863
864 test_expect_success 'Check ambiguous head and tag refs (loose)' '
865 git config --bool core.warnambiguousrefs false &&
866 ${git_for_each_ref} --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
867 test_cmp expected actual
868 '
869
870 cat >expected <<\EOF
871 heads/ambiguous
872 ambiguous
873 EOF
874
875 test_expect_success 'Check ambiguous head and tag refs II (loose)' '
876 git checkout main &&
877 git tag ambiguous testtag^0 &&
878 git branch ambiguous testtag^0 &&
879 ${git_for_each_ref} --format "%(refname:short)" refs/heads/ambiguous refs/tags/ambiguous >actual &&
880 test_cmp expected actual
881 '
882
883 test_expect_success 'create tag without tagger' '
884 git tag -a -m "Broken tag" taggerless &&
885 git tag -f taggerless $(git cat-file tag taggerless |
886 sed -e "/^tagger /d" |
887 git hash-object --literally --stdin -w -t tag)
888 '
889
890 test_atom refs/tags/taggerless type 'commit'
891 test_atom refs/tags/taggerless tag 'taggerless'
892 test_atom refs/tags/taggerless tagger ''
893 test_atom refs/tags/taggerless taggername ''
894 test_atom refs/tags/taggerless taggeremail ''
895 test_atom refs/tags/taggerless taggeremail:trim ''
896 test_atom refs/tags/taggerless taggeremail:localpart ''
897 test_atom refs/tags/taggerless taggerdate ''
898 test_atom refs/tags/taggerless committer ''
899 test_atom refs/tags/taggerless committername ''
900 test_atom refs/tags/taggerless committeremail ''
901 test_atom refs/tags/taggerless committeremail:trim ''
902 test_atom refs/tags/taggerless committeremail:localpart ''
903 test_atom refs/tags/taggerless committerdate ''
904 test_atom refs/tags/taggerless subject 'Broken tag'
905
906 test_expect_success 'an unusual tag with an incomplete line' '
907
908 git tag -m "bogo" bogo &&
909 bogo=$(git cat-file tag bogo) &&
910 bogo=$(printf "%s" "$bogo" | git mktag) &&
911 git tag -f bogo "$bogo" &&
912 ${git_for_each_ref} --format "%(body)" refs/tags/bogo
913
914 '
915
916 test_expect_success 'create tag with subject and body content' '
917 cat >>msg <<-\EOF &&
918 the subject line
919
920 first body line
921 second body line
922 EOF
923 git tag -F msg subject-body
924 '
925 test_atom refs/tags/subject-body subject 'the subject line'
926 test_atom refs/tags/subject-body subject:sanitize 'the-subject-line'
927 test_atom refs/tags/subject-body body 'first body line
928 second body line
929 '
930 test_atom refs/tags/subject-body contents 'the subject line
931
932 first body line
933 second body line
934 '
935
936 test_expect_success 'create tag with multiline subject' '
937 cat >msg <<-\EOF &&
938 first subject line
939 second subject line
940
941 first body line
942 second body line
943 EOF
944 git tag -F msg multiline
945 '
946 test_atom refs/tags/multiline subject 'first subject line second subject line'
947 test_atom refs/tags/multiline subject:sanitize 'first-subject-line-second-subject-line'
948 test_atom refs/tags/multiline contents:subject 'first subject line second subject line'
949 test_atom refs/tags/multiline body 'first body line
950 second body line
951 '
952 test_atom refs/tags/multiline contents:body 'first body line
953 second body line
954 '
955 test_atom refs/tags/multiline contents:signature ''
956 test_atom refs/tags/multiline contents 'first subject line
957 second subject line
958
959 first body line
960 second body line
961 '
962
963 test_expect_success GPG 'create signed tags' '
964 git tag -s -m "" signed-empty &&
965 git tag -s -m "subject line" signed-short &&
966 cat >msg <<-\EOF &&
967 subject line
968
969 body contents
970 EOF
971 git tag -s -F msg signed-long
972 '
973
974 sig='-----BEGIN PGP SIGNATURE-----
975 -----END PGP SIGNATURE-----
976 '
977
978 PREREQ=GPG
979 test_atom refs/tags/signed-empty subject ''
980 test_atom refs/tags/signed-empty subject:sanitize ''
981 test_atom refs/tags/signed-empty contents:subject ''
982 test_atom refs/tags/signed-empty body "$sig"
983 test_atom refs/tags/signed-empty contents:body ''
984 test_atom refs/tags/signed-empty contents:signature "$sig"
985 test_atom refs/tags/signed-empty contents "$sig"
986
987 test_expect_success GPG 'basic atom: refs/tags/signed-empty raw' '
988 git cat-file tag refs/tags/signed-empty >expected &&
989 ${git_for_each_ref} --format="%(raw)" refs/tags/signed-empty >actual &&
990 sanitize_pgp <expected >expected.clean &&
991 echo >>expected.clean &&
992 sanitize_pgp <actual >actual.clean &&
993 test_cmp expected.clean actual.clean
994 '
995
996 test_atom refs/tags/signed-short subject 'subject line'
997 test_atom refs/tags/signed-short subject:sanitize 'subject-line'
998 test_atom refs/tags/signed-short contents:subject 'subject line'
999 test_atom refs/tags/signed-short body "$sig"
1000 test_atom refs/tags/signed-short contents:body ''
1001 test_atom refs/tags/signed-short contents:signature "$sig"
1002 test_atom refs/tags/signed-short contents "subject line
1003 $sig"
1004
1005 test_expect_success GPG 'basic atom: refs/tags/signed-short raw' '
1006 git cat-file tag refs/tags/signed-short >expected &&
1007 ${git_for_each_ref} --format="%(raw)" refs/tags/signed-short >actual &&
1008 sanitize_pgp <expected >expected.clean &&
1009 echo >>expected.clean &&
1010 sanitize_pgp <actual >actual.clean &&
1011 test_cmp expected.clean actual.clean
1012 '
1013
1014 test_atom refs/tags/signed-long subject 'subject line'
1015 test_atom refs/tags/signed-long subject:sanitize 'subject-line'
1016 test_atom refs/tags/signed-long contents:subject 'subject line'
1017 test_atom refs/tags/signed-long body "body contents
1018 $sig"
1019 test_atom refs/tags/signed-long contents:body 'body contents
1020 '
1021 test_atom refs/tags/signed-long contents:signature "$sig"
1022 test_atom refs/tags/signed-long contents "subject line
1023
1024 body contents
1025 $sig"
1026
1027 test_expect_success GPG 'basic atom: refs/tags/signed-long raw' '
1028 git cat-file tag refs/tags/signed-long >expected &&
1029 ${git_for_each_ref} --format="%(raw)" refs/tags/signed-long >actual &&
1030 sanitize_pgp <expected >expected.clean &&
1031 echo >>expected.clean &&
1032 sanitize_pgp <actual >actual.clean &&
1033 test_cmp expected.clean actual.clean
1034 '
1035
1036 test_expect_success 'set up refs pointing to tree and blob' '
1037 git update-ref refs/mytrees/first refs/heads/main^{tree} &&
1038 git update-ref refs/myblobs/first refs/heads/main:one
1039 '
1040
1041 test_atom refs/mytrees/first subject ""
1042 test_atom refs/mytrees/first contents:subject ""
1043 test_atom refs/mytrees/first body ""
1044 test_atom refs/mytrees/first contents:body ""
1045 test_atom refs/mytrees/first contents:signature ""
1046 test_atom refs/mytrees/first contents ""
1047
1048 test_expect_success 'basic atom: refs/mytrees/first raw' '
1049 git cat-file tree refs/mytrees/first >expected &&
1050 echo >>expected &&
1051 ${git_for_each_ref} --format="%(raw)" refs/mytrees/first >actual &&
1052 test_cmp expected actual &&
1053 git cat-file -s refs/mytrees/first >expected &&
1054 ${git_for_each_ref} --format="%(raw:size)" refs/mytrees/first >actual &&
1055 test_cmp expected actual
1056 '
1057
1058 test_atom refs/myblobs/first subject ""
1059 test_atom refs/myblobs/first contents:subject ""
1060 test_atom refs/myblobs/first body ""
1061 test_atom refs/myblobs/first contents:body ""
1062 test_atom refs/myblobs/first contents:signature ""
1063 test_atom refs/myblobs/first contents ""
1064
1065 test_expect_success 'basic atom: refs/myblobs/first raw' '
1066 git cat-file blob refs/myblobs/first >expected &&
1067 echo >>expected &&
1068 ${git_for_each_ref} --format="%(raw)" refs/myblobs/first >actual &&
1069 test_cmp expected actual &&
1070 git cat-file -s refs/myblobs/first >expected &&
1071 ${git_for_each_ref} --format="%(raw:size)" refs/myblobs/first >actual &&
1072 test_cmp expected actual
1073 '
1074
1075 test_expect_success 'set up refs pointing to binary blob' '
1076 printf "a\0b\0c" >blob1 &&
1077 printf "a\0c\0b" >blob2 &&
1078 printf "\0a\0b\0c" >blob3 &&
1079 printf "abc" >blob4 &&
1080 printf "\0 \0 \0 " >blob5 &&
1081 printf "\0 \0a\0 " >blob6 &&
1082 printf " " >blob7 &&
1083 >blob8 &&
1084 obj=$(git hash-object -w blob1) &&
1085 git update-ref refs/myblobs/blob1 "$obj" &&
1086 obj=$(git hash-object -w blob2) &&
1087 git update-ref refs/myblobs/blob2 "$obj" &&
1088 obj=$(git hash-object -w blob3) &&
1089 git update-ref refs/myblobs/blob3 "$obj" &&
1090 obj=$(git hash-object -w blob4) &&
1091 git update-ref refs/myblobs/blob4 "$obj" &&
1092 obj=$(git hash-object -w blob5) &&
1093 git update-ref refs/myblobs/blob5 "$obj" &&
1094 obj=$(git hash-object -w blob6) &&
1095 git update-ref refs/myblobs/blob6 "$obj" &&
1096 obj=$(git hash-object -w blob7) &&
1097 git update-ref refs/myblobs/blob7 "$obj" &&
1098 obj=$(git hash-object -w blob8) &&
1099 git update-ref refs/myblobs/blob8 "$obj"
1100 '
1101
1102 test_expect_success 'Verify sorts with raw' '
1103 cat >expected <<-EOF &&
1104 refs/myblobs/blob8
1105 refs/myblobs/blob5
1106 refs/myblobs/blob6
1107 refs/myblobs/blob3
1108 refs/myblobs/blob7
1109 refs/mytrees/first
1110 refs/myblobs/first
1111 refs/myblobs/blob1
1112 refs/myblobs/blob2
1113 refs/myblobs/blob4
1114 refs/heads/main
1115 EOF
1116 ${git_for_each_ref} --format="%(refname)" --sort=raw \
1117 refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
1118 test_cmp expected actual
1119 '
1120
1121 test_expect_success 'Verify sorts with raw:size' '
1122 cat >expected <<-EOF &&
1123 refs/myblobs/blob8
1124 refs/myblobs/blob7
1125 refs/myblobs/blob4
1126 refs/myblobs/blob1
1127 refs/myblobs/blob2
1128 refs/myblobs/blob3
1129 refs/myblobs/blob5
1130 refs/myblobs/blob6
1131 refs/myblobs/first
1132 refs/mytrees/first
1133 refs/heads/main
1134 EOF
1135 ${git_for_each_ref} --format="%(refname)" --sort=raw:size \
1136 refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
1137 test_cmp expected actual
1138 '
1139
1140 test_expect_success 'validate raw atom with %(if:equals)' '
1141 cat >expected <<-EOF &&
1142 not equals
1143 not equals
1144 not equals
1145 not equals
1146 not equals
1147 not equals
1148 refs/myblobs/blob4
1149 not equals
1150 not equals
1151 not equals
1152 not equals
1153 not equals
1154 EOF
1155 ${git_for_each_ref} --format="%(if:equals=abc)%(raw)%(then)%(refname)%(else)not equals%(end)" \
1156 refs/myblobs/ refs/heads/ >actual &&
1157 test_cmp expected actual
1158 '
1159
1160 test_expect_success 'validate raw atom with %(if:notequals)' '
1161 cat >expected <<-EOF &&
1162 refs/heads/ambiguous
1163 refs/heads/main
1164 refs/heads/newtag
1165 refs/myblobs/blob1
1166 refs/myblobs/blob2
1167 refs/myblobs/blob3
1168 equals
1169 refs/myblobs/blob5
1170 refs/myblobs/blob6
1171 refs/myblobs/blob7
1172 refs/myblobs/blob8
1173 refs/myblobs/first
1174 EOF
1175 ${git_for_each_ref} --format="%(if:notequals=abc)%(raw)%(then)%(refname)%(else)equals%(end)" \
1176 refs/myblobs/ refs/heads/ >actual &&
1177 test_cmp expected actual
1178 '
1179
1180 test_expect_success 'empty raw refs with %(if)' '
1181 cat >expected <<-EOF &&
1182 refs/myblobs/blob1 not empty
1183 refs/myblobs/blob2 not empty
1184 refs/myblobs/blob3 not empty
1185 refs/myblobs/blob4 not empty
1186 refs/myblobs/blob5 not empty
1187 refs/myblobs/blob6 not empty
1188 refs/myblobs/blob7 empty
1189 refs/myblobs/blob8 empty
1190 refs/myblobs/first not empty
1191 EOF
1192 ${git_for_each_ref} --format="%(refname) %(if)%(raw)%(then)not empty%(else)empty%(end)" \
1193 refs/myblobs/ >actual &&
1194 test_cmp expected actual
1195 '
1196
1197 test_expect_success '%(raw) with --python must fail' '
1198 test_must_fail ${git_for_each_ref} --format="%(raw)" --python
1199 '
1200
1201 test_expect_success '%(raw) with --tcl must fail' '
1202 test_must_fail ${git_for_each_ref} --format="%(raw)" --tcl
1203 '
1204
1205 test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
1206 ${git_for_each_ref} --format="\$name= %(raw);
1207 print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
1208 cmp blob1 actual &&
1209 ${git_for_each_ref} --format="\$name= %(raw);
1210 print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual &&
1211 cmp blob3 actual &&
1212 ${git_for_each_ref} --format="\$name= %(raw);
1213 print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual &&
1214 cmp blob8 actual &&
1215 ${git_for_each_ref} --format="\$name= %(raw);
1216 print \"\$name\"" refs/myblobs/first --perl | perl >actual &&
1217 cmp one actual &&
1218 git cat-file tree refs/mytrees/first > expected &&
1219 ${git_for_each_ref} --format="\$name= %(raw);
1220 print \"\$name\"" refs/mytrees/first --perl | perl >actual &&
1221 cmp expected actual
1222 '
1223
1224 test_expect_success '%(raw) with --shell must fail' '
1225 test_must_fail ${git_for_each_ref} --format="%(raw)" --shell
1226 '
1227
1228 test_expect_success '%(raw) with --shell and --sort=raw must fail' '
1229 test_must_fail ${git_for_each_ref} --format="%(raw)" --sort=raw --shell
1230 '
1231
1232 test_expect_success '%(raw:size) with --shell' '
1233 ${git_for_each_ref} --format="%(raw:size)" | sed "s/^/$SQ/;s/$/$SQ/" >expect &&
1234 ${git_for_each_ref} --format="%(raw:size)" --shell >actual &&
1235 test_cmp expect actual
1236 '
1237
1238 test_expect_success "${git_for_each_ref} --format compare with cat-file --batch" '
1239 git rev-parse refs/mytrees/first | git cat-file --batch >expected &&
1240 ${git_for_each_ref} --format="%(objectname) %(objecttype) %(objectsize)
1241 %(raw)" refs/mytrees/first >actual &&
1242 test_cmp expected actual
1243 '
1244
1245 test_expect_success 'verify sorts with contents:size' '
1246 cat >expect <<-\EOF &&
1247 refs/heads/main
1248 refs/heads/newtag
1249 refs/heads/ambiguous
1250 EOF
1251 ${git_for_each_ref} --format="%(refname)" \
1252 --sort=contents:size refs/heads/ >actual &&
1253 test_cmp expect actual
1254 '
1255
1256 test_expect_success 'set up multiple-sort tags' '
1257 for when in 100000 200000
1258 do
1259 for email in user1 user2
1260 do
1261 for ref in ref1 ref2
1262 do
1263 GIT_COMMITTER_DATE="@$when +0000" \
1264 GIT_COMMITTER_EMAIL="$email@example.com" \
1265 git tag -m "tag $ref-$when-$email" \
1266 multi-$ref-$when-$email || return 1
1267 done
1268 done
1269 done
1270 '
1271
1272 test_expect_success 'Verify sort with multiple keys' '
1273 cat >expected <<-\EOF &&
1274 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
1275 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
1276 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
1277 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
1278 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
1279 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
1280 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
1281 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
1282 EOF
1283 ${git_for_each_ref} \
1284 --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
1285 --sort=-refname \
1286 --sort=taggeremail \
1287 --sort=taggerdate \
1288 "refs/tags/multi-*" >actual &&
1289 test_cmp expected actual
1290 '
1291
1292 test_expect_success 'equivalent sorts fall back on refname' '
1293 cat >expected <<-\EOF &&
1294 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
1295 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
1296 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
1297 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
1298 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
1299 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
1300 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
1301 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
1302 EOF
1303 ${git_for_each_ref} \
1304 --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
1305 --sort=taggerdate \
1306 "refs/tags/multi-*" >actual &&
1307 test_cmp expected actual
1308 '
1309
1310 test_expect_success '--no-sort cancels the previous sort keys' '
1311 cat >expected <<-\EOF &&
1312 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
1313 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
1314 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
1315 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
1316 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
1317 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
1318 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
1319 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
1320 EOF
1321 ${git_for_each_ref} \
1322 --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
1323 --sort=-refname \
1324 --sort=taggeremail \
1325 --no-sort \
1326 --sort=taggerdate \
1327 "refs/tags/multi-*" >actual &&
1328 test_cmp expected actual
1329 '
1330
1331 test_expect_success '--no-sort without subsequent --sort prints expected refs' '
1332 cat >expected <<-\EOF &&
1333 refs/tags/multi-ref1-100000-user1
1334 refs/tags/multi-ref1-100000-user2
1335 refs/tags/multi-ref1-200000-user1
1336 refs/tags/multi-ref1-200000-user2
1337 refs/tags/multi-ref2-100000-user1
1338 refs/tags/multi-ref2-100000-user2
1339 refs/tags/multi-ref2-200000-user1
1340 refs/tags/multi-ref2-200000-user2
1341 EOF
1342
1343 # Sort the results with `sort` for a consistent comparison against
1344 # expected
1345 ${git_for_each_ref} \
1346 --format="%(refname)" \
1347 --no-sort \
1348 "refs/tags/multi-*" | sort >actual &&
1349 test_cmp expected actual
1350 '
1351
1352 test_expect_success 'set up custom date sorting' '
1353 # Dates:
1354 # - Wed Feb 07 2024 21:34:20 +0000
1355 # - Tue Dec 14 1999 00:05:22 +0000
1356 # - Fri Jun 04 2021 11:26:51 +0000
1357 # - Mon Jan 22 2007 16:44:01 GMT+0000
1358 i=1 &&
1359 for when in 1707341660 945129922 1622806011 1169484241
1360 do
1361 GIT_COMMITTER_DATE="@$when +0000" \
1362 GIT_COMMITTER_EMAIL="user@example.com" \
1363 git tag -m "tag $when" custom-dates-$i &&
1364 i=$(($i+1)) || return 1
1365 done
1366 '
1367
1368 test_expect_success 'sort by date defaults to full timestamp' '
1369 cat >expected <<-\EOF &&
1370 945129922 refs/tags/custom-dates-2
1371 1169484241 refs/tags/custom-dates-4
1372 1622806011 refs/tags/custom-dates-3
1373 1707341660 refs/tags/custom-dates-1
1374 EOF
1375
1376 ${git_for_each_ref} \
1377 --format="%(creatordate:unix) %(refname)" \
1378 --sort=creatordate \
1379 "refs/tags/custom-dates-*" >actual &&
1380 test_cmp expected actual
1381 '
1382
1383 test_expect_success 'sort by custom date format' '
1384 cat >expected <<-\EOF &&
1385 00:05:22 refs/tags/custom-dates-2
1386 11:26:51 refs/tags/custom-dates-3
1387 16:44:01 refs/tags/custom-dates-4
1388 21:34:20 refs/tags/custom-dates-1
1389 EOF
1390
1391 ${git_for_each_ref} \
1392 --format="%(creatordate:format:%H:%M:%S) %(refname)" \
1393 --sort="creatordate:format:%H:%M:%S" \
1394 "refs/tags/custom-dates-*" >actual &&
1395 test_cmp expected actual
1396 '
1397
1398 test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
1399 test_when_finished "git checkout main" &&
1400 ${git_for_each_ref} --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
1401 sed -e "s/^\* / /" actual >expect &&
1402 git checkout --orphan orphaned-branch &&
1403 ${git_for_each_ref} --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
1404 test_cmp expect actual
1405 '
1406
1407 cat >trailers <<EOF
1408 Reviewed-by: A U Thor <author@example.com>
1409 Signed-off-by: A U Thor <author@example.com>
1410 [ v2 updated patch description ]
1411 Acked-by: A U Thor
1412 <author@example.com>
1413 EOF
1414
1415 unfold () {
1416 perl -0pe 's/\n\s+/ /g'
1417 }
1418
1419 test_expect_success 'set up trailers for next test' '
1420 echo "Some contents" > two &&
1421 git add two &&
1422 git commit -F - <<-EOF
1423 trailers: this commit message has trailers
1424
1425 Some message contents
1426
1427 $(cat trailers)
1428 EOF
1429 '
1430
1431 test_trailer_option () {
1432 if test "$#" -eq 3
1433 then
1434 prereq="$1"
1435 shift
1436 fi &&
1437 title=$1 option=$2
1438 cat >expect
1439 test_expect_success $prereq "$title" '
1440 ${git_for_each_ref} --format="%($option)" refs/heads/main >actual &&
1441 test_cmp expect actual &&
1442 ${git_for_each_ref} --format="%(contents:$option)" refs/heads/main >actual &&
1443 test_cmp expect actual
1444 '
1445 }
1446
1447 test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
1448 'trailers:unfold' <<-EOF
1449 $(unfold <trailers)
1450
1451 EOF
1452
1453 test_trailer_option '%(trailers:only) shows only "key: value" trailers' \
1454 'trailers:only' <<-EOF
1455 $(grep -v patch.description <trailers)
1456
1457 EOF
1458
1459 test_trailer_option '%(trailers:only=no,only=true) shows only "key: value" trailers' \
1460 'trailers:only=no,only=true' <<-EOF
1461 $(grep -v patch.description <trailers)
1462
1463 EOF
1464
1465 test_trailer_option '%(trailers:only=yes) shows only "key: value" trailers' \
1466 'trailers:only=yes' <<-EOF
1467 $(grep -v patch.description <trailers)
1468
1469 EOF
1470
1471 test_trailer_option '%(trailers:only=no) shows all trailers' \
1472 'trailers:only=no' <<-EOF
1473 $(cat trailers)
1474
1475 EOF
1476
1477 test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
1478 'trailers:only,unfold' <<-EOF
1479 $(grep -v patch.description <trailers | unfold)
1480
1481 EOF
1482
1483 test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
1484 'trailers:unfold,only' <<-EOF
1485 $(grep -v patch.description <trailers | unfold)
1486
1487 EOF
1488
1489 test_trailer_option '%(trailers:key=foo) shows that trailer' \
1490 'trailers:key=Signed-off-by' <<-EOF
1491 Signed-off-by: A U Thor <author@example.com>
1492
1493 EOF
1494
1495 test_trailer_option '%(trailers:key=foo) is case insensitive' \
1496 'trailers:key=SiGned-oFf-bY' <<-EOF
1497 Signed-off-by: A U Thor <author@example.com>
1498
1499 EOF
1500
1501 test_trailer_option '%(trailers:key=foo:) trailing colon also works' \
1502 'trailers:key=Signed-off-by:' <<-EOF
1503 Signed-off-by: A U Thor <author@example.com>
1504
1505 EOF
1506
1507 test_trailer_option '%(trailers:key=foo) multiple keys' \
1508 'trailers:key=Reviewed-by:,key=Signed-off-by' <<-EOF
1509 Reviewed-by: A U Thor <author@example.com>
1510 Signed-off-by: A U Thor <author@example.com>
1511
1512 EOF
1513
1514 test_trailer_option '%(trailers:key=nonexistent) becomes empty' \
1515 'trailers:key=Shined-off-by:' <<-EOF
1516
1517 EOF
1518
1519 test_trailer_option '%(trailers:key=foo) handles multiple lines even if folded' \
1520 'trailers:key=Acked-by' <<-EOF
1521 $(grep -v patch.description <trailers | grep -v Signed-off-by | grep -v Reviewed-by)
1522
1523 EOF
1524
1525 test_trailer_option '%(trailers:key=foo,unfold) properly unfolds' \
1526 'trailers:key=Signed-Off-by,unfold' <<-EOF
1527 $(unfold <trailers | grep Signed-off-by)
1528
1529 EOF
1530
1531 test_trailer_option '%(trailers:key=foo,only=no) also includes nontrailer lines' \
1532 'trailers:key=Signed-off-by,only=no' <<-EOF
1533 Signed-off-by: A U Thor <author@example.com>
1534 $(grep patch.description <trailers)
1535
1536 EOF
1537
1538 test_trailer_option '%(trailers:key=foo,valueonly) shows only value' \
1539 'trailers:key=Signed-off-by,valueonly' <<-EOF
1540 A U Thor <author@example.com>
1541
1542 EOF
1543
1544 test_trailer_option '%(trailers:separator) changes separator' \
1545 'trailers:separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
1546 Reviewed-by: A U Thor <author@example.com>,Signed-off-by: A U Thor <author@example.com>
1547 EOF
1548
1549 test_trailer_option '%(trailers:key_value_separator) changes key-value separator' \
1550 'trailers:key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
1551 Reviewed-by,A U Thor <author@example.com>
1552 Signed-off-by,A U Thor <author@example.com>
1553
1554 EOF
1555
1556 test_trailer_option '%(trailers:separator,key_value_separator) changes both separators' \
1557 'trailers:separator=%x2C,key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
1558 Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
1559 EOF
1560
1561 test_expect_success 'multiple %(trailers) use their own options' '
1562 git tag -F - tag-with-trailers <<-\EOF &&
1563 body
1564
1565 one: foo
1566 one: bar
1567 two: baz
1568 two: qux
1569 EOF
1570 t1="%(trailers:key=one,key_value_separator=W,separator=X)" &&
1571 t2="%(trailers:key=two,key_value_separator=Y,separator=Z)" &&
1572 ${git_for_each_ref} --format="$t1%0a$t2" refs/tags/tag-with-trailers >actual &&
1573 cat >expect <<-\EOF &&
1574 oneWfooXoneWbar
1575 twoYbazZtwoYqux
1576 EOF
1577 test_cmp expect actual
1578 '
1579
1580 test_failing_trailer_option () {
1581 title=$1 option=$2
1582 cat >expect
1583 test_expect_success "$title" '
1584 # error message cannot be checked under i18n
1585 test_must_fail ${git_for_each_ref} --format="%($option)" refs/heads/main 2>actual &&
1586 test_cmp expect actual &&
1587 test_must_fail ${git_for_each_ref} --format="%(contents:$option)" refs/heads/main 2>actual &&
1588 test_cmp expect actual
1589 '
1590 }
1591
1592 test_failing_trailer_option '%(trailers) rejects unknown trailers arguments' \
1593 'trailers:unsupported' <<-\EOF
1594 fatal: unknown %(trailers) argument: unsupported
1595 EOF
1596
1597 test_failing_trailer_option '%(trailers:key) without value is error' \
1598 'trailers:key' <<-\EOF
1599 fatal: expected %(trailers:key=<value>)
1600 EOF
1601
1602 test_expect_success 'if arguments, %(contents:trailers) shows error if colon is missing' '
1603 cat >expect <<-EOF &&
1604 fatal: unrecognized %(contents) argument: trailersonly
1605 EOF
1606 test_must_fail ${git_for_each_ref} --format="%(contents:trailersonly)" 2>actual &&
1607 test_cmp expect actual
1608 '
1609
1610 test_expect_success 'basic atom: head contents:trailers' '
1611 ${git_for_each_ref} --format="%(contents:trailers)" refs/heads/main >actual &&
1612 sanitize_pgp <actual >actual.clean &&
1613 # ${git_for_each_ref} ends with a blank line
1614 cat >expect <<-EOF &&
1615 $(cat trailers)
1616
1617 EOF
1618 test_cmp expect actual.clean
1619 '
1620
1621 test_expect_success 'basic atom: rest must fail' '
1622 test_must_fail ${git_for_each_ref} --format="%(rest)" refs/heads/main
1623 '
1624
1625 test_expect_success 'HEAD atom does not take arguments' '
1626 test_must_fail ${git_for_each_ref} --format="%(HEAD:foo)" 2>err &&
1627 echo "fatal: %(HEAD) does not take arguments" >expect &&
1628 test_cmp expect err
1629 '
1630
1631 test_expect_success 'subject atom rejects unknown arguments' '
1632 test_must_fail ${git_for_each_ref} --format="%(subject:foo)" 2>err &&
1633 echo "fatal: unrecognized %(subject) argument: foo" >expect &&
1634 test_cmp expect err
1635 '
1636
1637 test_expect_success 'refname atom rejects unknown arguments' '
1638 test_must_fail ${git_for_each_ref} --format="%(refname:foo)" 2>err &&
1639 echo "fatal: unrecognized %(refname) argument: foo" >expect &&
1640 test_cmp expect err
1641 '
1642
1643 test_expect_success 'trailer parsing not fooled by --- line' '
1644 git commit --allow-empty -F - <<-\EOF &&
1645 this is the subject
1646
1647 This is the body. The message has a "---" line which would confuse a
1648 message+patch parser. But here we know we have only a commit message,
1649 so we get it right.
1650
1651 trailer: wrong
1652 ---
1653 This is more body.
1654
1655 trailer: right
1656 EOF
1657
1658 {
1659 echo "trailer: right" &&
1660 echo
1661 } >expect &&
1662 ${git_for_each_ref} --format="%(trailers)" refs/heads/main >actual &&
1663 test_cmp expect actual
1664 '
1665
1666 test_expect_success 'Add symbolic ref for the following tests' '
1667 git symbolic-ref refs/heads/sym refs/heads/main
1668 '
1669
1670 cat >expected <<EOF
1671 refs/heads/main
1672 EOF
1673
1674 test_expect_success 'Verify usage of %(symref) atom' '
1675 ${git_for_each_ref} --format="%(symref)" refs/heads/sym >actual &&
1676 test_cmp expected actual
1677 '
1678
1679 cat >expected <<EOF
1680 heads/main
1681 EOF
1682
1683 test_expect_success 'Verify usage of %(symref:short) atom' '
1684 ${git_for_each_ref} --format="%(symref:short)" refs/heads/sym >actual &&
1685 test_cmp expected actual
1686 '
1687
1688 cat >expected <<EOF
1689 main
1690 heads/main
1691 EOF
1692
1693 test_expect_success 'Verify usage of %(symref:lstrip) atom' '
1694 ${git_for_each_ref} --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
1695 ${git_for_each_ref} --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
1696 test_cmp expected actual &&
1697
1698 ${git_for_each_ref} --format="%(symref:strip=2)" refs/heads/sym > actual &&
1699 ${git_for_each_ref} --format="%(symref:strip=-2)" refs/heads/sym >> actual &&
1700 test_cmp expected actual
1701 '
1702
1703 cat >expected <<EOF
1704 refs
1705 refs/heads
1706 EOF
1707
1708 test_expect_success 'Verify usage of %(symref:rstrip) atom' '
1709 ${git_for_each_ref} --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
1710 ${git_for_each_ref} --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
1711 test_cmp expected actual
1712 '
1713
1714 test_expect_success ':remotename and :remoteref' '
1715 git init remote-tests &&
1716 (
1717 cd remote-tests &&
1718 test_commit initial &&
1719 git branch -M main &&
1720 git remote add from fifth.coffee:blub &&
1721 git config branch.main.remote from &&
1722 git config branch.main.merge refs/heads/stable &&
1723 git remote add to southridge.audio:repo &&
1724 git config remote.to.push "refs/heads/*:refs/heads/pushed/*" &&
1725 git config branch.main.pushRemote to &&
1726 for pair in "%(upstream)=refs/remotes/from/stable" \
1727 "%(upstream:remotename)=from" \
1728 "%(upstream:remoteref)=refs/heads/stable" \
1729 "%(push)=refs/remotes/to/pushed/main" \
1730 "%(push:remotename)=to" \
1731 "%(push:remoteref)=refs/heads/pushed/main"
1732 do
1733 echo "${pair#*=}" >expect &&
1734 ${git_for_each_ref} --format="${pair%=*}" \
1735 refs/heads/main >actual &&
1736 test_cmp expect actual || exit 1
1737 done &&
1738 git branch push-simple &&
1739 git config branch.push-simple.pushRemote from &&
1740 actual="$(${git_for_each_ref} \
1741 --format="%(push:remotename),%(push:remoteref)" \
1742 refs/heads/push-simple)" &&
1743 test from, = "$actual"
1744 )
1745 '
1746
1747 test_expect_success '%(push) with an invalid push-simple config' '
1748 echo "refs/heads/main " >expect &&
1749 git -c push.default=simple \
1750 -c remote.pushdefault=myfork \
1751 for-each-ref \
1752 --format="%(refname) %(push)" refs/heads/main >actual &&
1753 test_cmp expect actual
1754 '
1755
1756 test_expect_success "${git_for_each_ref} --ignore-case ignores case" '
1757 ${git_for_each_ref} --format="%(refname)" refs/heads/MAIN >actual &&
1758 test_must_be_empty actual &&
1759
1760 echo refs/heads/main >expect &&
1761 ${git_for_each_ref} --format="%(refname)" --ignore-case \
1762 refs/heads/MAIN >actual &&
1763 test_cmp expect actual
1764 '
1765
1766 test_expect_success "${git_for_each_ref} --omit-empty works" '
1767 ${git_for_each_ref} --format="%(refname)" >actual &&
1768 test_line_count -gt 1 actual &&
1769 ${git_for_each_ref} --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual &&
1770 echo refs/heads/main >expect &&
1771 test_cmp expect actual
1772 '
1773
1774 test_expect_success "${git_for_each_ref} --ignore-case works on multiple sort keys" '
1775 # name refs numerically to avoid case-insensitive filesystem conflicts
1776 nr=0 &&
1777 for email in a A b B
1778 do
1779 for subject in a A b B
1780 do
1781 GIT_COMMITTER_EMAIL="$email@example.com" \
1782 git tag -m "tag $subject" icase-$(printf %02d $nr) &&
1783 nr=$((nr+1))||
1784 return 1
1785 done
1786 done &&
1787 ${git_for_each_ref} --ignore-case \
1788 --format="%(taggeremail) %(subject) %(refname)" \
1789 --sort=refname \
1790 --sort=subject \
1791 --sort=taggeremail \
1792 refs/tags/icase-* >actual &&
1793 cat >expect <<-\EOF &&
1794 <a@example.com> tag a refs/tags/icase-00
1795 <a@example.com> tag A refs/tags/icase-01
1796 <A@example.com> tag a refs/tags/icase-04
1797 <A@example.com> tag A refs/tags/icase-05
1798 <a@example.com> tag b refs/tags/icase-02
1799 <a@example.com> tag B refs/tags/icase-03
1800 <A@example.com> tag b refs/tags/icase-06
1801 <A@example.com> tag B refs/tags/icase-07
1802 <b@example.com> tag a refs/tags/icase-08
1803 <b@example.com> tag A refs/tags/icase-09
1804 <B@example.com> tag a refs/tags/icase-12
1805 <B@example.com> tag A refs/tags/icase-13
1806 <b@example.com> tag b refs/tags/icase-10
1807 <b@example.com> tag B refs/tags/icase-11
1808 <B@example.com> tag b refs/tags/icase-14
1809 <B@example.com> tag B refs/tags/icase-15
1810 EOF
1811 test_cmp expect actual
1812 '
1813
1814 test_expect_success "${git_for_each_ref} reports broken tags" '
1815 git tag -m "good tag" broken-tag-good HEAD &&
1816 git cat-file tag broken-tag-good >good &&
1817 sed s/commit/blob/ <good >bad &&
1818 bad=$(git hash-object -w -t tag bad) &&
1819 git update-ref refs/tags/broken-tag-bad $bad &&
1820 test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
1821 refs/tags/broken-tag-* &&
1822 test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
1823 refs/tags/broken-tag-bad
1824 '
1825
1826 test_expect_success 'set up tag with signature and no blank lines' '
1827 git tag -F - fake-sig-no-blanks <<-\EOF
1828 this is the subject
1829 -----BEGIN PGP SIGNATURE-----
1830 not a real signature, but we just care about the
1831 subject/body parsing. It is important here that
1832 there are no blank lines in the signature.
1833 -----END PGP SIGNATURE-----
1834 EOF
1835 '
1836
1837 test_atom refs/tags/fake-sig-no-blanks contents:subject 'this is the subject'
1838 test_atom refs/tags/fake-sig-no-blanks contents:body ''
1839 test_atom refs/tags/fake-sig-no-blanks contents:signature "$sig"
1840
1841 test_expect_success 'set up tag with CRLF signature' '
1842 append_cr <<-\EOF |
1843 this is the subject
1844 -----BEGIN PGP SIGNATURE-----
1845
1846 not a real signature, but we just care about
1847 the subject/body parsing. It is important here
1848 that there is a blank line separating this
1849 from the signature header.
1850 -----END PGP SIGNATURE-----
1851 EOF
1852 git tag -F - --cleanup=verbatim fake-sig-crlf
1853 '
1854
1855 test_atom refs/tags/fake-sig-crlf contents:subject 'this is the subject'
1856 test_atom refs/tags/fake-sig-crlf contents:body ''
1857
1858 # CRLF is retained in the signature, so we have to pass our expected value
1859 # through append_cr. But test_atom requires a shell string, which means command
1860 # substitution, and the shell will strip trailing newlines from the output of
1861 # the substitution. Hack around it by adding and then removing a dummy line.
1862 sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
1863 sig_crlf=${sig_crlf%dummy}
1864 test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
1865
1866 test_expect_success 'set up tag with signature and trailers' '
1867 git tag -F - fake-sig-trailer <<-\EOF
1868 this is the subject
1869
1870 this is the body
1871
1872 My-Trailer: foo
1873 -----BEGIN PGP SIGNATURE-----
1874
1875 not a real signature, but we just care about the
1876 subject/body/trailer parsing.
1877 -----END PGP SIGNATURE-----
1878 EOF
1879 '
1880
1881 # use "separator=" here to suppress the terminating newline
1882 test_atom refs/tags/fake-sig-trailer trailers:separator= 'My-Trailer: foo'
1883
1884 test_expect_success "${git_for_each_ref} --stdin: empty" '
1885 >in &&
1886 ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
1887 ${git_for_each_ref} --format="%(refname)" >expect &&
1888 test_cmp expect actual
1889 '
1890
1891 test_expect_success "${git_for_each_ref} --stdin: fails if extra args" '
1892 >in &&
1893 test_must_fail ${git_for_each_ref} --format="%(refname)" \
1894 --stdin refs/heads/extra <in 2>err &&
1895 grep "unknown arguments supplied with --stdin" err
1896 '
1897
1898 test_expect_success "${git_for_each_ref} --stdin: matches" '
1899 cat >in <<-EOF &&
1900 refs/tags/multi*
1901 refs/heads/amb*
1902 EOF
1903
1904 cat >expect <<-EOF &&
1905 refs/heads/ambiguous
1906 refs/tags/multi-ref1-100000-user1
1907 refs/tags/multi-ref1-100000-user2
1908 refs/tags/multi-ref1-200000-user1
1909 refs/tags/multi-ref1-200000-user2
1910 refs/tags/multi-ref2-100000-user1
1911 refs/tags/multi-ref2-100000-user2
1912 refs/tags/multi-ref2-200000-user1
1913 refs/tags/multi-ref2-200000-user2
1914 refs/tags/multiline
1915 EOF
1916
1917 ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
1918 test_cmp expect actual
1919 '
1920
1921 test_expect_success "${git_for_each_ref} with non-existing refs" '
1922 cat >in <<-EOF &&
1923 refs/heads/this-ref-does-not-exist
1924 refs/tags/bogus
1925 EOF
1926
1927 ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
1928 test_must_be_empty actual &&
1929
1930 xargs ${git_for_each_ref} --format="%(refname)" <in >actual &&
1931 test_must_be_empty actual
1932 '
1933
1934 test_expect_success "${git_for_each_ref} with nested tags" '
1935 git tag -am "Normal tag" nested/base HEAD &&
1936 git tag -am "Nested tag" nested/nest1 refs/tags/nested/base &&
1937 git tag -am "Double nested tag" nested/nest2 refs/tags/nested/nest1 &&
1938
1939 head_oid="$(git rev-parse HEAD)" &&
1940 base_tag_oid="$(git rev-parse refs/tags/nested/base)" &&
1941 nest1_tag_oid="$(git rev-parse refs/tags/nested/nest1)" &&
1942 nest2_tag_oid="$(git rev-parse refs/tags/nested/nest2)" &&
1943
1944 cat >expect <<-EOF &&
1945 refs/tags/nested/base $base_tag_oid tag $head_oid commit
1946 refs/tags/nested/nest1 $nest1_tag_oid tag $head_oid commit
1947 refs/tags/nested/nest2 $nest2_tag_oid tag $head_oid commit
1948 EOF
1949
1950 ${git_for_each_ref} \
1951 --format="%(refname) %(objectname) %(objecttype) %(*objectname) %(*objecttype)" \
1952 refs/tags/nested/ >actual &&
1953 test_cmp expect actual
1954 '
1955
1956 test_expect_success 'is-base atom with non-commits' '
1957 ${git_for_each_ref} --format="%(is-base:HEAD) %(refname)" >out 2>err &&
1958 grep "(HEAD) refs/heads/main" out &&
1959
1960 test_line_count = 2 err &&
1961 grep "error: object .* is a commit, not a blob" err &&
1962 grep "error: bad tag pointer to" err
1963 '
1964
1965 GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
1966 TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
1967
1968 test_expect_success GPG 'setup for signature atom using gpg' '
1969 git checkout -b signed &&
1970
1971 test_when_finished "test_unconfig commit.gpgSign" &&
1972
1973 echo "1" >file &&
1974 git add file &&
1975 test_tick &&
1976 git commit -S -m "file: 1" &&
1977 git tag first-signed &&
1978
1979 echo "2" >file &&
1980 test_tick &&
1981 git commit -a -m "file: 2" &&
1982 git tag second-unsigned &&
1983
1984 git config commit.gpgSign 1 &&
1985 echo "3" >file &&
1986 test_tick &&
1987 git commit -a --no-gpg-sign -m "file: 3" &&
1988 git tag third-unsigned &&
1989
1990 test_tick &&
1991 git rebase -f HEAD^^ && git tag second-signed HEAD^ &&
1992 git tag third-signed &&
1993
1994 echo "4" >file &&
1995 test_tick &&
1996 git commit -a -SB7227189 -m "file: 4" &&
1997 git tag fourth-signed &&
1998
1999 echo "5" >file &&
2000 test_tick &&
2001 git commit -a --no-gpg-sign -m "file: 5" &&
2002 git tag fifth-unsigned &&
2003
2004 echo "6" >file &&
2005 test_tick &&
2006 git commit -a --no-gpg-sign -m "file: 6" &&
2007
2008 test_tick &&
2009 git rebase -f HEAD^^ &&
2010 git tag fifth-signed HEAD^ &&
2011 git tag sixth-signed &&
2012
2013 echo "7" >file &&
2014 test_tick &&
2015 git commit -a --no-gpg-sign -m "file: 7" &&
2016 git tag seventh-unsigned
2017 '
2018
2019 test_expect_success GPGSSH 'setup for signature atom using ssh' '
2020 test_when_finished "test_unconfig gpg.format user.signingkey" &&
2021
2022 test_config gpg.format ssh &&
2023 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
2024 echo "8" >file &&
2025 test_tick &&
2026 git add file &&
2027 git commit -S -m "file: 8" &&
2028 git tag eighth-signed-ssh
2029 '
2030
2031 test_expect_success GPG2 'bare signature atom' '
2032 git verify-commit first-signed 2>expect &&
2033 echo >>expect &&
2034 ${git_for_each_ref} refs/tags/first-signed \
2035 --format="%(signature)" >actual &&
2036 test_cmp expect actual
2037 '
2038
2039 test_expect_success GPG 'show good signature with custom format' '
2040 git verify-commit first-signed &&
2041 cat >expect <<-\EOF &&
2042 G
2043 13B6F51ECDDE430D
2044 C O Mitter <committer@example.com>
2045 73D758744BE721698EC54E8713B6F51ECDDE430D
2046 73D758744BE721698EC54E8713B6F51ECDDE430D
2047 EOF
2048 ${git_for_each_ref} refs/tags/first-signed \
2049 --format="$GRADE_FORMAT" >actual &&
2050 test_cmp expect actual
2051 '
2052 test_expect_success GPGSSH 'show good signature with custom format with ssh' '
2053 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
2054 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
2055 cat >expect.tmpl <<-\EOF &&
2056 G
2057 FINGERPRINT
2058 principal with number 1
2059 FINGERPRINT
2060
2061 EOF
2062 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect &&
2063 ${git_for_each_ref} refs/tags/eighth-signed-ssh \
2064 --format="$GRADE_FORMAT" >actual &&
2065 test_cmp expect actual
2066 '
2067
2068 test_expect_success GPG 'signature atom with grade option and bad signature' '
2069 git cat-file commit third-signed >raw &&
2070 sed -e "s/^file: 3/file: 3 forged/" raw >forged1 &&
2071 FORGED1=$(git hash-object -w -t commit forged1) &&
2072 git update-ref refs/tags/third-signed "$FORGED1" &&
2073 test_must_fail git verify-commit "$FORGED1" &&
2074
2075 cat >expect <<-\EOF &&
2076 B
2077 13B6F51ECDDE430D
2078 C O Mitter <committer@example.com>
2079
2080
2081 EOF
2082 ${git_for_each_ref} refs/tags/third-signed \
2083 --format="$GRADE_FORMAT" >actual &&
2084 test_cmp expect actual
2085 '
2086
2087 test_expect_success GPG 'show untrusted signature with custom format' '
2088 cat >expect <<-\EOF &&
2089 U
2090 65A0EEA02E30CAD7
2091 Eris Discordia <discord@example.net>
2092 F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
2093 D4BE22311AD3131E5EDA29A461092E85B7227189
2094 EOF
2095 ${git_for_each_ref} refs/tags/fourth-signed \
2096 --format="$GRADE_FORMAT" >actual &&
2097 test_cmp expect actual
2098 '
2099
2100 test_expect_success GPG 'show untrusted signature with undefined trust level' '
2101 cat >expect <<-\EOF &&
2102 undefined
2103 65A0EEA02E30CAD7
2104 Eris Discordia <discord@example.net>
2105 F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
2106 D4BE22311AD3131E5EDA29A461092E85B7227189
2107 EOF
2108 ${git_for_each_ref} refs/tags/fourth-signed \
2109 --format="$TRUSTLEVEL_FORMAT" >actual &&
2110 test_cmp expect actual
2111 '
2112
2113 test_expect_success GPG 'show untrusted signature with ultimate trust level' '
2114 cat >expect <<-\EOF &&
2115 ultimate
2116 13B6F51ECDDE430D
2117 C O Mitter <committer@example.com>
2118 73D758744BE721698EC54E8713B6F51ECDDE430D
2119 73D758744BE721698EC54E8713B6F51ECDDE430D
2120 EOF
2121 ${git_for_each_ref} refs/tags/sixth-signed \
2122 --format="$TRUSTLEVEL_FORMAT" >actual &&
2123 test_cmp expect actual
2124 '
2125
2126 test_expect_success GPG 'show unknown signature with custom format' '
2127 cat >expect <<-\EOF &&
2128 E
2129 13B6F51ECDDE430D
2130
2131
2132
2133 EOF
2134 GNUPGHOME="$GNUPGHOME_NOT_USED" ${git_for_each_ref} \
2135 refs/tags/sixth-signed --format="$GRADE_FORMAT" >actual &&
2136 test_cmp expect actual
2137 '
2138
2139 test_expect_success GPG 'show lack of signature with custom format' '
2140 cat >expect <<-\EOF &&
2141 N
2142
2143
2144
2145
2146 EOF
2147 ${git_for_each_ref} refs/tags/seventh-unsigned \
2148 --format="$GRADE_FORMAT" >actual &&
2149 test_cmp expect actual
2150 '
2151
2152 test_done