t6300: refactor tests to be shareable

In preparation for adding tests for the new `git refs list` command, refactor the existing t6300 test suite to make its logic shareable. Move the core test logic from `t6300-for-each-ref.sh` into a new `for-each-ref-tests.sh` file. Inside this new script, replace hardcoded calls to "git for-each-ref" with the `$git_for_each_ref` variable. The original `t6300-for-each-ref.sh` script now becomes a simple "driver". It is responsible for setting the default value of the variable and then sourcing the test library. This new structure follows the established pattern used for sharing tests between `git-blame` and `git-annotate` and prepares the test suite for the `refs list` tests to be added in a subsequent commit. Mentored-by: Patrick Steinhardt <ps@pks.im> Mentored-by: shejialuo <shejialuo@gmail.com> Mentored-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Meet Soni <meetsoni3017@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

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