]> git.ipfire.org Git - thirdparty/git.git/blob - t/t4014-format-patch.sh
bisect: document command line arguments for "bisect start"
[thirdparty/git.git] / t / t4014-format-patch.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Junio C Hamano
4 #
5
6 test_description='various format-patch tests'
7
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10
11 . ./test-lib.sh
12 . "$TEST_DIRECTORY"/lib-terminal.sh
13
14 test_expect_success setup '
15 test_write_lines 1 2 3 4 5 6 7 8 9 10 >file &&
16 cat file >elif &&
17 git add file elif &&
18 test_tick &&
19 git commit -m Initial &&
20 git checkout -b side &&
21
22 test_write_lines 1 2 5 6 A B C 7 8 9 10 >file &&
23 test_chmod +x elif &&
24 test_tick &&
25 git commit -m "Side changes #1" &&
26
27 test_write_lines D E F >>file &&
28 git update-index file &&
29 test_tick &&
30 git commit -m "Side changes #2" &&
31 git tag C2 &&
32
33 test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >file &&
34 git update-index file &&
35 test_tick &&
36 git commit -m "Side changes #3 with \\n backslash-n in it." &&
37
38 git checkout main &&
39 git diff-tree -p C2 >patch &&
40 git apply --index <patch &&
41 test_tick &&
42 git commit -m "Main accepts moral equivalent of #2" &&
43
44 git checkout side &&
45 git checkout -b patchid &&
46 test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >file2 &&
47 test_write_lines 1 2 3 A 4 B C 7 8 9 10 D E F 5 6 >file3 &&
48 test_write_lines 8 9 10 >file &&
49 git add file file2 file3 &&
50 test_tick &&
51 git commit -m "patchid 1" &&
52 test_write_lines 4 A B 7 8 9 10 >file2 &&
53 test_write_lines 8 9 10 5 6 >file3 &&
54 git add file2 file3 &&
55 test_tick &&
56 git commit -m "patchid 2" &&
57 test_write_lines 10 5 6 >file &&
58 git add file &&
59 test_tick &&
60 git commit -m "patchid 3" &&
61
62 git checkout main
63 '
64
65 test_expect_success 'format-patch --ignore-if-in-upstream' '
66 git format-patch --stdout main..side >patch0 &&
67 grep "^From " patch0 >from0 &&
68 test_line_count = 3 from0
69 '
70
71 test_expect_success 'format-patch --ignore-if-in-upstream' '
72 git format-patch --stdout \
73 --ignore-if-in-upstream main..side >patch1 &&
74 grep "^From " patch1 >from1 &&
75 test_line_count = 2 from1
76 '
77
78 test_expect_success 'format-patch --ignore-if-in-upstream handles tags' '
79 git tag -a v1 -m tag side &&
80 git tag -a v2 -m tag main &&
81 git format-patch --stdout --ignore-if-in-upstream v2..v1 >patch1 &&
82 grep "^From " patch1 >from1 &&
83 test_line_count = 2 from1
84 '
85
86 test_expect_success "format-patch doesn't consider merge commits" '
87 git checkout -b feature main &&
88 echo "Another line" >>file &&
89 test_tick &&
90 git commit -am "Feature branch change #1" &&
91 echo "Yet another line" >>file &&
92 test_tick &&
93 git commit -am "Feature branch change #2" &&
94 git checkout -b merger main &&
95 test_tick &&
96 git merge --no-ff feature &&
97 git format-patch -3 --stdout >patch &&
98 grep "^From " patch >from &&
99 test_line_count = 3 from
100 '
101
102 test_expect_success 'format-patch result applies' '
103 git checkout -b rebuild-0 main &&
104 git am -3 patch0 &&
105 git rev-list main.. >list &&
106 test_line_count = 2 list
107 '
108
109 test_expect_success 'format-patch --ignore-if-in-upstream result applies' '
110 git checkout -b rebuild-1 main &&
111 git am -3 patch1 &&
112 git rev-list main.. >list &&
113 test_line_count = 2 list
114 '
115
116 test_expect_success 'commit did not screw up the log message' '
117 git cat-file commit side >actual &&
118 grep "^Side .* with .* backslash-n" actual
119 '
120
121 test_expect_success 'format-patch did not screw up the log message' '
122 grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
123 grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
124 '
125
126 test_expect_success 'replay did not screw up the log message' '
127 git cat-file commit rebuild-1 >actual &&
128 grep "^Side .* with .* backslash-n" actual
129 '
130
131 test_expect_success 'extra headers' '
132 git config format.headers "To: R E Cipient <rcipient@example.com>
133 " &&
134 git config --add format.headers "Cc: S E Cipient <scipient@example.com>
135 " &&
136 git format-patch --stdout main..side >patch2 &&
137 sed -e "/^\$/q" patch2 >hdrs2 &&
138 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
139 grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
140 '
141
142 test_expect_success 'extra headers without newlines' '
143 git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
144 git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
145 git format-patch --stdout main..side >patch3 &&
146 sed -e "/^\$/q" patch3 >hdrs3 &&
147 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
148 grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
149 '
150
151 test_expect_success 'extra headers with multiple To:s' '
152 git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
153 git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
154 git format-patch --stdout main..side >patch4 &&
155 sed -e "/^\$/q" patch4 >hdrs4 &&
156 grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
157 grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
158 '
159
160 test_expect_success 'additional command line cc (ascii)' '
161 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
162 git format-patch --cc="S E Cipient <scipient@example.com>" --stdout main..side >patch5 &&
163 sed -e "/^\$/q" patch5 >hdrs5 &&
164 grep "^Cc: R E Cipient <rcipient@example.com>,\$" hdrs5 &&
165 grep "^ *S E Cipient <scipient@example.com>\$" hdrs5
166 '
167
168 test_expect_failure 'additional command line cc (rfc822)' '
169 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
170 git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout main..side >patch5 &&
171 sed -e "/^\$/q" patch5 >hdrs5 &&
172 grep "^Cc: R E Cipient <rcipient@example.com>,\$" hdrs5 &&
173 grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" hdrs5
174 '
175
176 test_expect_success 'command line headers' '
177 git config --unset-all format.headers &&
178 git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout main..side >patch6 &&
179 sed -e "/^\$/q" patch6 >hdrs6 &&
180 grep "^Cc: R E Cipient <rcipient@example.com>\$" hdrs6
181 '
182
183 test_expect_success 'configuration headers and command line headers' '
184 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
185 git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout main..side >patch7 &&
186 sed -e "/^\$/q" patch7 >hdrs7 &&
187 grep "^Cc: R E Cipient <rcipient@example.com>,\$" hdrs7 &&
188 grep "^ *S E Cipient <scipient@example.com>\$" hdrs7
189 '
190
191 test_expect_success 'command line To: header (ascii)' '
192 git config --unset-all format.headers &&
193 git format-patch --to="R E Cipient <rcipient@example.com>" --stdout main..side >patch8 &&
194 sed -e "/^\$/q" patch8 >hdrs8 &&
195 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs8
196 '
197
198 test_expect_failure 'command line To: header (rfc822)' '
199 git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout main..side >patch8 &&
200 sed -e "/^\$/q" patch8 >hdrs8 &&
201 grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" hdrs8
202 '
203
204 test_expect_failure 'command line To: header (rfc2047)' '
205 git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout main..side >patch8 &&
206 sed -e "/^\$/q" patch8 >hdrs8 &&
207 grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" hdrs8
208 '
209
210 test_expect_success 'configuration To: header (ascii)' '
211 git config format.to "R E Cipient <rcipient@example.com>" &&
212 git format-patch --stdout main..side >patch9 &&
213 sed -e "/^\$/q" patch9 >hdrs9 &&
214 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs9
215 '
216
217 test_expect_failure 'configuration To: header (rfc822)' '
218 git config format.to "R. E. Cipient <rcipient@example.com>" &&
219 git format-patch --stdout main..side >patch9 &&
220 sed -e "/^\$/q" patch9 >hdrs9 &&
221 grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" hdrs9
222 '
223
224 test_expect_failure 'configuration To: header (rfc2047)' '
225 git config format.to "R Ä Cipient <rcipient@example.com>" &&
226 git format-patch --stdout main..side >patch9 &&
227 sed -e "/^\$/q" patch9 >hdrs9 &&
228 grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" hdrs9
229 '
230
231 # check_patch <patch>: Verify that <patch> looks like a half-sane
232 # patch email to avoid a false positive with !grep
233 check_patch () {
234 grep -e "^From:" "$1" &&
235 grep -e "^Date:" "$1" &&
236 grep -e "^Subject:" "$1"
237 }
238
239 test_expect_success 'format.from=false' '
240 git -c format.from=false format-patch --stdout main..side >patch &&
241 sed -e "/^\$/q" patch >hdrs &&
242 check_patch patch &&
243 ! grep "^From: C O Mitter <committer@example.com>\$" hdrs
244 '
245
246 test_expect_success 'format.from=true' '
247 git -c format.from=true format-patch --stdout main..side >patch &&
248 sed -e "/^\$/q" patch >hdrs &&
249 check_patch hdrs &&
250 grep "^From: C O Mitter <committer@example.com>\$" hdrs
251 '
252
253 test_expect_success 'format.from with address' '
254 git -c format.from="F R Om <from@example.com>" format-patch --stdout main..side >patch &&
255 sed -e "/^\$/q" patch >hdrs &&
256 check_patch hdrs &&
257 grep "^From: F R Om <from@example.com>\$" hdrs
258 '
259
260 test_expect_success '--no-from overrides format.from' '
261 git -c format.from="F R Om <from@example.com>" format-patch --no-from --stdout main..side >patch &&
262 sed -e "/^\$/q" patch >hdrs &&
263 check_patch hdrs &&
264 ! grep "^From: F R Om <from@example.com>\$" hdrs
265 '
266
267 test_expect_success '--from overrides format.from' '
268 git -c format.from="F R Om <from@example.com>" format-patch --from --stdout main..side >patch &&
269 sed -e "/^\$/q" patch >hdrs &&
270 check_patch hdrs &&
271 ! grep "^From: F R Om <from@example.com>\$" hdrs
272 '
273
274 test_expect_success '--no-to overrides config.to' '
275 git config --replace-all format.to \
276 "R E Cipient <rcipient@example.com>" &&
277 git format-patch --no-to --stdout main..side >patch10 &&
278 sed -e "/^\$/q" patch10 >hdrs10 &&
279 check_patch hdrs10 &&
280 ! grep "^To: R E Cipient <rcipient@example.com>\$" hdrs10
281 '
282
283 test_expect_success '--no-to and --to replaces config.to' '
284 git config --replace-all format.to \
285 "Someone <someone@out.there>" &&
286 git format-patch --no-to --to="Someone Else <else@out.there>" \
287 --stdout main..side >patch11 &&
288 sed -e "/^\$/q" patch11 >hdrs11 &&
289 check_patch hdrs11 &&
290 ! grep "^To: Someone <someone@out.there>\$" hdrs11 &&
291 grep "^To: Someone Else <else@out.there>\$" hdrs11
292 '
293
294 test_expect_success '--no-cc overrides config.cc' '
295 git config --replace-all format.cc \
296 "C E Cipient <rcipient@example.com>" &&
297 git format-patch --no-cc --stdout main..side >patch12 &&
298 sed -e "/^\$/q" patch12 >hdrs12 &&
299 check_patch hdrs12 &&
300 ! grep "^Cc: C E Cipient <rcipient@example.com>\$" hdrs12
301 '
302
303 test_expect_success '--no-add-header overrides config.headers' '
304 git config --replace-all format.headers \
305 "Header1: B E Cipient <rcipient@example.com>" &&
306 git format-patch --no-add-header --stdout main..side >patch13 &&
307 sed -e "/^\$/q" patch13 >hdrs13 &&
308 check_patch hdrs13 &&
309 ! grep "^Header1: B E Cipient <rcipient@example.com>\$" hdrs13
310 '
311
312 test_expect_success 'multiple files' '
313 rm -rf patches/ &&
314 git checkout side &&
315 git format-patch -o patches/ main &&
316 ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch
317 '
318
319 test_expect_success 'filename length limit' '
320 test_when_finished "rm -f 000*" &&
321 rm -rf 000[1-9]-*.patch &&
322 for len in 15 25 35
323 do
324 git format-patch --filename-max-length=$len -3 side &&
325 max=$(
326 for patch in 000[1-9]-*.patch
327 do
328 echo "$patch" | wc -c || exit 1
329 done |
330 sort -nr |
331 head -n 1
332 ) &&
333 test $max -le $len || return 1
334 done
335 '
336
337 test_expect_success 'filename length limit from config' '
338 test_when_finished "rm -f 000*" &&
339 rm -rf 000[1-9]-*.patch &&
340 for len in 15 25 35
341 do
342 git -c format.filenameMaxLength=$len format-patch -3 side &&
343 max=$(
344 for patch in 000[1-9]-*.patch
345 do
346 echo "$patch" | wc -c || exit 1
347 done |
348 sort -nr |
349 head -n 1
350 ) &&
351 test $max -le $len || return 1
352 done
353 '
354
355 test_expect_success 'filename limit applies only to basename' '
356 test_when_finished "rm -rf patches/" &&
357 rm -rf patches/ &&
358 for len in 15 25 35
359 do
360 git format-patch -o patches --filename-max-length=$len -3 side &&
361 max=$(
362 for patch in patches/000[1-9]-*.patch
363 do
364 echo "${patch#patches/}" | wc -c || exit 1
365 done |
366 sort -nr |
367 head -n 1
368 ) &&
369 test $max -le $len || return 1
370 done
371 '
372
373 test_expect_success 'reroll count' '
374 rm -fr patches &&
375 git format-patch -o patches --cover-letter --reroll-count 4 main..side >list &&
376 ! grep -v "^patches/v4-000[0-3]-" list &&
377 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
378 ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
379 '
380
381 test_expect_success 'reroll count (-v)' '
382 rm -fr patches &&
383 git format-patch -o patches --cover-letter -v4 main..side >list &&
384 ! grep -v "^patches/v4-000[0-3]-" list &&
385 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
386 ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
387 '
388
389 test_expect_success 'reroll count (-v) with a fractional number' '
390 rm -fr patches &&
391 git format-patch -o patches --cover-letter -v4.4 main..side >list &&
392 ! grep -v "^patches/v4.4-000[0-3]-" list &&
393 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
394 ! grep -v "^Subject: \[PATCH v4.4 [0-3]/3\] " subjects
395 '
396
397 test_expect_success 'reroll (-v) count with a non number' '
398 rm -fr patches &&
399 git format-patch -o patches --cover-letter -v4rev2 main..side >list &&
400 ! grep -v "^patches/v4rev2-000[0-3]-" list &&
401 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
402 ! grep -v "^Subject: \[PATCH v4rev2 [0-3]/3\] " subjects
403 '
404
405 test_expect_success 'reroll (-v) count with a non-pathname character' '
406 rm -fr patches &&
407 git format-patch -o patches --cover-letter -v4---..././../--1/.2// main..side >list &&
408 ! grep -v "patches/v4-\.-\.-\.-1-\.2-000[0-3]-" list &&
409 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
410 ! grep -v "^Subject: \[PATCH v4---\.\.\./\./\.\./--1/\.2// [0-3]/3\] " subjects
411 '
412
413 check_threading () {
414 expect="$1" &&
415 shift &&
416 git format-patch --stdout "$@" >patch &&
417 # Prints everything between the Message-ID and In-Reply-To,
418 # and replaces all Message-ID-lookalikes by a sequence number
419 perl -ne '
420 if (/^(message-id|references|in-reply-to)/i) {
421 $printing = 1;
422 } elsif (/^\S/) {
423 $printing = 0;
424 }
425 if ($printing) {
426 $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
427 for $k (keys %h) {s/$k/$h{$k}/};
428 print;
429 }
430 print "---\n" if /^From /i;
431 ' <patch >actual &&
432 test_cmp "$expect" actual
433 }
434
435 cat >>expect.no-threading <<EOF
436 ---
437 ---
438 ---
439 EOF
440
441 test_expect_success 'no threading' '
442 git checkout side &&
443 check_threading expect.no-threading main
444 '
445
446 cat >expect.thread <<EOF
447 ---
448 Message-Id: <0>
449 ---
450 Message-Id: <1>
451 In-Reply-To: <0>
452 References: <0>
453 ---
454 Message-Id: <2>
455 In-Reply-To: <0>
456 References: <0>
457 EOF
458
459 test_expect_success 'thread' '
460 check_threading expect.thread --thread main
461 '
462
463 cat >expect.in-reply-to <<EOF
464 ---
465 Message-Id: <0>
466 In-Reply-To: <1>
467 References: <1>
468 ---
469 Message-Id: <2>
470 In-Reply-To: <1>
471 References: <1>
472 ---
473 Message-Id: <3>
474 In-Reply-To: <1>
475 References: <1>
476 EOF
477
478 test_expect_success 'thread in-reply-to' '
479 check_threading expect.in-reply-to --in-reply-to="<test.message>" \
480 --thread main
481 '
482
483 cat >expect.cover-letter <<EOF
484 ---
485 Message-Id: <0>
486 ---
487 Message-Id: <1>
488 In-Reply-To: <0>
489 References: <0>
490 ---
491 Message-Id: <2>
492 In-Reply-To: <0>
493 References: <0>
494 ---
495 Message-Id: <3>
496 In-Reply-To: <0>
497 References: <0>
498 EOF
499
500 test_expect_success 'thread cover-letter' '
501 check_threading expect.cover-letter --cover-letter --thread main
502 '
503
504 cat >expect.cl-irt <<EOF
505 ---
506 Message-Id: <0>
507 In-Reply-To: <1>
508 References: <1>
509 ---
510 Message-Id: <2>
511 In-Reply-To: <0>
512 References: <1>
513 <0>
514 ---
515 Message-Id: <3>
516 In-Reply-To: <0>
517 References: <1>
518 <0>
519 ---
520 Message-Id: <4>
521 In-Reply-To: <0>
522 References: <1>
523 <0>
524 EOF
525
526 test_expect_success 'thread cover-letter in-reply-to' '
527 check_threading expect.cl-irt --cover-letter \
528 --in-reply-to="<test.message>" --thread main
529 '
530
531 test_expect_success 'thread explicit shallow' '
532 check_threading expect.cl-irt --cover-letter \
533 --in-reply-to="<test.message>" --thread=shallow main
534 '
535
536 cat >expect.deep <<EOF
537 ---
538 Message-Id: <0>
539 ---
540 Message-Id: <1>
541 In-Reply-To: <0>
542 References: <0>
543 ---
544 Message-Id: <2>
545 In-Reply-To: <1>
546 References: <0>
547 <1>
548 EOF
549
550 test_expect_success 'thread deep' '
551 check_threading expect.deep --thread=deep main
552 '
553
554 cat >expect.deep-irt <<EOF
555 ---
556 Message-Id: <0>
557 In-Reply-To: <1>
558 References: <1>
559 ---
560 Message-Id: <2>
561 In-Reply-To: <0>
562 References: <1>
563 <0>
564 ---
565 Message-Id: <3>
566 In-Reply-To: <2>
567 References: <1>
568 <0>
569 <2>
570 EOF
571
572 test_expect_success 'thread deep in-reply-to' '
573 check_threading expect.deep-irt --thread=deep \
574 --in-reply-to="<test.message>" main
575 '
576
577 cat >expect.deep-cl <<EOF
578 ---
579 Message-Id: <0>
580 ---
581 Message-Id: <1>
582 In-Reply-To: <0>
583 References: <0>
584 ---
585 Message-Id: <2>
586 In-Reply-To: <1>
587 References: <0>
588 <1>
589 ---
590 Message-Id: <3>
591 In-Reply-To: <2>
592 References: <0>
593 <1>
594 <2>
595 EOF
596
597 test_expect_success 'thread deep cover-letter' '
598 check_threading expect.deep-cl --cover-letter --thread=deep main
599 '
600
601 cat >expect.deep-cl-irt <<EOF
602 ---
603 Message-Id: <0>
604 In-Reply-To: <1>
605 References: <1>
606 ---
607 Message-Id: <2>
608 In-Reply-To: <0>
609 References: <1>
610 <0>
611 ---
612 Message-Id: <3>
613 In-Reply-To: <2>
614 References: <1>
615 <0>
616 <2>
617 ---
618 Message-Id: <4>
619 In-Reply-To: <3>
620 References: <1>
621 <0>
622 <2>
623 <3>
624 EOF
625
626 test_expect_success 'thread deep cover-letter in-reply-to' '
627 check_threading expect.deep-cl-irt --cover-letter \
628 --in-reply-to="<test.message>" --thread=deep main
629 '
630
631 test_expect_success 'thread via config' '
632 test_config format.thread true &&
633 check_threading expect.thread main
634 '
635
636 test_expect_success 'thread deep via config' '
637 test_config format.thread deep &&
638 check_threading expect.deep main
639 '
640
641 test_expect_success 'thread config + override' '
642 test_config format.thread deep &&
643 check_threading expect.thread --thread main
644 '
645
646 test_expect_success 'thread config + --no-thread' '
647 test_config format.thread deep &&
648 check_threading expect.no-threading --no-thread main
649 '
650
651 test_expect_success 'excessive subject' '
652 rm -rf patches/ &&
653 git checkout side &&
654 before=$(git hash-object file) &&
655 before=$(git rev-parse --short $before) &&
656 test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >>file &&
657 after=$(git hash-object file) &&
658 after=$(git rev-parse --short $after) &&
659 git update-index file &&
660 git commit -m "This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole paragraph right at the start as the only thing in the commit message. It had better not become the filename for the patch." &&
661 git format-patch -o patches/ main..side &&
662 ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
663 '
664
665 test_expect_success 'failure to write cover-letter aborts gracefully' '
666 test_when_finished "rmdir 0000-cover-letter.patch" &&
667 mkdir 0000-cover-letter.patch &&
668 test_must_fail git format-patch --no-renames --cover-letter -1
669 '
670
671 test_expect_success 'cover-letter inherits diff options' '
672 git mv file foo &&
673 git commit -m foo &&
674 git format-patch --no-renames --cover-letter -1 &&
675 check_patch 0000-cover-letter.patch &&
676 ! grep "file => foo .* 0 *\$" 0000-cover-letter.patch &&
677 git format-patch --cover-letter -1 -M &&
678 grep "file => foo .* 0 *\$" 0000-cover-letter.patch
679 '
680
681 cat >expect <<EOF
682 This is an excessively long subject line for a message due to the
683 habit some projects have of not having a short, one-line subject at
684 the start of the commit message, but rather sticking a whole
685 paragraph right at the start as the only thing in the commit
686 message. It had better not become the filename for the patch.
687 foo
688
689 EOF
690
691 test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
692 git format-patch --cover-letter -2 &&
693 sed -e "1,/A U Thor/d" -e "/^\$/q" 0000-cover-letter.patch >output &&
694 test_cmp expect output
695 '
696
697 cat >expect <<EOF
698 index $before..$after 100644
699 --- a/file
700 +++ b/file
701 @@ -13,4 +13,20 @@ C
702 10
703 D
704 E
705 F
706 +5
707 EOF
708
709 test_expect_success 'format-patch respects -U' '
710 git format-patch -U4 -2 &&
711 sed -e "1,/^diff/d" -e "/^+5/q" \
712 <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch \
713 >output &&
714 test_cmp expect output
715 '
716
717 cat >expect <<EOF
718
719 diff --git a/file b/file
720 index $before..$after 100644
721 --- a/file
722 +++ b/file
723 @@ -14,3 +14,19 @@ C
724 D
725 E
726 F
727 +5
728 EOF
729
730 test_expect_success 'format-patch -p suppresses stat' '
731 git format-patch -p -2 &&
732 sed -e "1,/^\$/d" -e "/^+5/q" 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch >output &&
733 test_cmp expect output
734 '
735
736 test_expect_success 'format-patch from a subdirectory (1)' '
737 filename=$(
738 rm -rf sub &&
739 mkdir -p sub/dir &&
740 cd sub/dir &&
741 git format-patch -1
742 ) &&
743 case "$filename" in
744 0*)
745 ;; # ok
746 *)
747 echo "Oops? $filename"
748 false
749 ;;
750 esac &&
751 test -f "$filename"
752 '
753
754 test_expect_success 'format-patch from a subdirectory (2)' '
755 filename=$(
756 rm -rf sub &&
757 mkdir -p sub/dir &&
758 cd sub/dir &&
759 git format-patch -1 -o ..
760 ) &&
761 case "$filename" in
762 ../0*)
763 ;; # ok
764 *)
765 echo "Oops? $filename"
766 false
767 ;;
768 esac &&
769 basename=$(expr "$filename" : ".*/\(.*\)") &&
770 test -f "sub/$basename"
771 '
772
773 test_expect_success 'format-patch from a subdirectory (3)' '
774 rm -f 0* &&
775 filename=$(
776 rm -rf sub &&
777 mkdir -p sub/dir &&
778 cd sub/dir &&
779 git format-patch -1 -o "$TRASH_DIRECTORY"
780 ) &&
781 basename=$(expr "$filename" : ".*/\(.*\)") &&
782 test -f "$basename"
783 '
784
785 test_expect_success 'format-patch --in-reply-to' '
786 git format-patch -1 --stdout --in-reply-to "baz@foo.bar" >patch8 &&
787 grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
788 grep "^References: <baz@foo.bar>" patch8
789 '
790
791 test_expect_success 'format-patch --signoff' '
792 git format-patch -1 --signoff --stdout >out &&
793 grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out
794 '
795
796 test_expect_success 'format-patch --notes --signoff' '
797 git notes --ref test add -m "test message" HEAD &&
798 git format-patch -1 --signoff --stdout --notes=test >out &&
799 # Three dashes must come after S-o-b
800 ! sed "/^Signed-off-by: /q" out | grep "test message" &&
801 sed "1,/^Signed-off-by: /d" out | grep "test message" &&
802 # Notes message must come after three dashes
803 ! sed "/^---$/q" out | grep "test message" &&
804 sed "1,/^---$/d" out | grep "test message"
805 '
806
807 test_expect_success 'format-patch notes output control' '
808 git notes add -m "notes config message" HEAD &&
809 test_when_finished git notes remove HEAD &&
810
811 git format-patch -1 --stdout >out &&
812 ! grep "notes config message" out &&
813 git format-patch -1 --stdout --notes >out &&
814 grep "notes config message" out &&
815 git format-patch -1 --stdout --no-notes >out &&
816 ! grep "notes config message" out &&
817 git format-patch -1 --stdout --notes --no-notes >out &&
818 ! grep "notes config message" out &&
819 git format-patch -1 --stdout --no-notes --notes >out &&
820 grep "notes config message" out &&
821
822 test_config format.notes true &&
823 git format-patch -1 --stdout >out &&
824 grep "notes config message" out &&
825 git format-patch -1 --stdout --notes >out &&
826 grep "notes config message" out &&
827 git format-patch -1 --stdout --no-notes >out &&
828 ! grep "notes config message" out &&
829 git format-patch -1 --stdout --notes --no-notes >out &&
830 ! grep "notes config message" out &&
831 git format-patch -1 --stdout --no-notes --notes >out &&
832 grep "notes config message" out
833 '
834
835 test_expect_success 'format-patch with multiple notes refs' '
836 git notes --ref note1 add -m "this is note 1" HEAD &&
837 test_when_finished git notes --ref note1 remove HEAD &&
838 git notes --ref note2 add -m "this is note 2" HEAD &&
839 test_when_finished git notes --ref note2 remove HEAD &&
840
841 git format-patch -1 --stdout >out &&
842 ! grep "this is note 1" out &&
843 ! grep "this is note 2" out &&
844 git format-patch -1 --stdout --notes=note1 >out &&
845 grep "this is note 1" out &&
846 ! grep "this is note 2" out &&
847 git format-patch -1 --stdout --notes=note2 >out &&
848 ! grep "this is note 1" out &&
849 grep "this is note 2" out &&
850 git format-patch -1 --stdout --notes=note1 --notes=note2 >out &&
851 grep "this is note 1" out &&
852 grep "this is note 2" out &&
853
854 test_config format.notes note1 &&
855 git format-patch -1 --stdout >out &&
856 grep "this is note 1" out &&
857 ! grep "this is note 2" out &&
858 git format-patch -1 --stdout --no-notes >out &&
859 ! grep "this is note 1" out &&
860 ! grep "this is note 2" out &&
861 git format-patch -1 --stdout --notes=note2 >out &&
862 grep "this is note 1" out &&
863 grep "this is note 2" out &&
864 git format-patch -1 --stdout --no-notes --notes=note2 >out &&
865 ! grep "this is note 1" out &&
866 grep "this is note 2" out &&
867
868 git config --add format.notes note2 &&
869 git format-patch -1 --stdout >out &&
870 grep "this is note 1" out &&
871 grep "this is note 2" out &&
872 git format-patch -1 --stdout --no-notes >out &&
873 ! grep "this is note 1" out &&
874 ! grep "this is note 2" out
875 '
876
877 test_expect_success 'format-patch with multiple notes refs in config' '
878 test_when_finished "test_unconfig format.notes" &&
879
880 git notes --ref note1 add -m "this is note 1" HEAD &&
881 test_when_finished git notes --ref note1 remove HEAD &&
882 git notes --ref note2 add -m "this is note 2" HEAD &&
883 test_when_finished git notes --ref note2 remove HEAD &&
884
885 git config format.notes note1 &&
886 git format-patch -1 --stdout >out &&
887 grep "this is note 1" out &&
888 ! grep "this is note 2" out &&
889 git config format.notes note2 &&
890 git format-patch -1 --stdout >out &&
891 ! grep "this is note 1" out &&
892 grep "this is note 2" out &&
893 git config --add format.notes note1 &&
894 git format-patch -1 --stdout >out &&
895 grep "this is note 1" out &&
896 grep "this is note 2" out &&
897
898 git config --replace-all format.notes note1 &&
899 git config --add format.notes false &&
900 git format-patch -1 --stdout >out &&
901 ! grep "this is note 1" out &&
902 ! grep "this is note 2" out &&
903 git config --add format.notes note2 &&
904 git format-patch -1 --stdout >out &&
905 ! grep "this is note 1" out &&
906 grep "this is note 2" out
907 '
908
909 echo "fatal: --name-only does not make sense" >expect.name-only
910 echo "fatal: --name-status does not make sense" >expect.name-status
911 echo "fatal: --check does not make sense" >expect.check
912
913 test_expect_success 'options no longer allowed for format-patch' '
914 test_must_fail git format-patch --name-only 2>output &&
915 test_cmp expect.name-only output &&
916 test_must_fail git format-patch --name-status 2>output &&
917 test_cmp expect.name-status output &&
918 test_must_fail git format-patch --check 2>output &&
919 test_cmp expect.check output
920 '
921
922 test_expect_success 'format-patch --numstat should produce a patch' '
923 git format-patch --numstat --stdout main..side >output &&
924 grep "^diff --git a/" output >diff &&
925 test_line_count = 5 diff
926 '
927
928 test_expect_success 'format-patch -- <path>' '
929 rm -f *.patch &&
930 git checkout -b pathspec main &&
931
932 echo file_a 1 >file_a &&
933 echo file_b 1 >file_b &&
934 git add file_a file_b &&
935 git commit -m pathspec_initial &&
936
937 echo file_a 2 >>file_a &&
938 git add file_a &&
939 git commit -m pathspec_a &&
940
941 echo file_b 2 >>file_b &&
942 git add file_b &&
943 git commit -m pathspec_b &&
944
945 echo file_a 3 >>file_a &&
946 echo file_b 3 >>file_b &&
947 git add file_a file_b &&
948 git commit -m pathspec_ab &&
949
950 cat >expect <<-\EOF &&
951 0001-pathspec_initial.patch
952 0002-pathspec_a.patch
953 0003-pathspec_ab.patch
954 EOF
955
956 git format-patch main..pathspec -- file_a >output &&
957 test_cmp expect output &&
958 ! grep file_b *.patch
959 '
960
961 test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
962 git checkout side &&
963 git format-patch --ignore-if-in-upstream HEAD
964 '
965
966 test_expect_success 'get git version' '
967 git_version=$(git --version) &&
968 git_version=${git_version##* }
969 '
970
971 signature() {
972 printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
973 }
974
975 test_expect_success 'format-patch default signature' '
976 git format-patch --stdout -1 >patch &&
977 tail -n 3 patch >output &&
978 signature >expect &&
979 test_cmp expect output
980 '
981
982 test_expect_success 'format-patch --signature' '
983 git format-patch --stdout --signature="my sig" -1 >patch &&
984 tail -n 3 patch >output &&
985 signature "my sig" >expect &&
986 test_cmp expect output
987 '
988
989 test_expect_success 'format-patch with format.signature config' '
990 git config format.signature "config sig" &&
991 git format-patch --stdout -1 >output &&
992 grep "config sig" output
993 '
994
995 test_expect_success 'format-patch --signature overrides format.signature' '
996 git config format.signature "config sig" &&
997 git format-patch --stdout --signature="overrides" -1 >output &&
998 ! grep "config sig" output &&
999 grep "overrides" output
1000 '
1001
1002 test_expect_success 'format-patch --no-signature ignores format.signature' '
1003 git config format.signature "config sig" &&
1004 git format-patch --stdout --signature="my sig" --no-signature \
1005 -1 >output &&
1006 check_patch output &&
1007 ! grep "config sig" output &&
1008 ! grep "my sig" output &&
1009 ! grep "^-- \$" output
1010 '
1011
1012 test_expect_success 'format-patch --signature --cover-letter' '
1013 git config --unset-all format.signature &&
1014 git format-patch --stdout --signature="my sig" --cover-letter \
1015 -1 >output &&
1016 grep "my sig" output >sig &&
1017 test_line_count = 2 sig
1018 '
1019
1020 test_expect_success 'format.signature="" suppresses signatures' '
1021 git config format.signature "" &&
1022 git format-patch --stdout -1 >output &&
1023 check_patch output &&
1024 ! grep "^-- \$" output
1025 '
1026
1027 test_expect_success 'format-patch --no-signature suppresses signatures' '
1028 git config --unset-all format.signature &&
1029 git format-patch --stdout --no-signature -1 >output &&
1030 check_patch output &&
1031 ! grep "^-- \$" output
1032 '
1033
1034 test_expect_success 'format-patch --signature="" suppresses signatures' '
1035 git format-patch --stdout --signature="" -1 >output &&
1036 check_patch output &&
1037 ! grep "^-- \$" output
1038 '
1039
1040 test_expect_success 'prepare mail-signature input' '
1041 cat >mail-signature <<-\EOF
1042
1043 Test User <test.email@kernel.org>
1044 http://git.kernel.org/cgit/git/git.git
1045
1046 git.kernel.org/?p=git/git.git;a=summary
1047
1048 EOF
1049 '
1050
1051 test_expect_success '--signature-file=file works' '
1052 git format-patch --stdout --signature-file=mail-signature -1 >output &&
1053 check_patch output &&
1054 sed -e "1,/^-- \$/d" output >actual &&
1055 {
1056 cat mail-signature && echo
1057 } >expect &&
1058 test_cmp expect actual
1059 '
1060
1061 test_expect_success 'format.signaturefile works' '
1062 test_config format.signaturefile mail-signature &&
1063 git format-patch --stdout -1 >output &&
1064 check_patch output &&
1065 sed -e "1,/^-- \$/d" output >actual &&
1066 {
1067 cat mail-signature && echo
1068 } >expect &&
1069 test_cmp expect actual
1070 '
1071
1072 test_expect_success '--no-signature suppresses format.signaturefile ' '
1073 test_config format.signaturefile mail-signature &&
1074 git format-patch --stdout --no-signature -1 >output &&
1075 check_patch output &&
1076 ! grep "^-- \$" output
1077 '
1078
1079 test_expect_success '--signature-file overrides format.signaturefile' '
1080 cat >other-mail-signature <<-\EOF &&
1081 Use this other signature instead of mail-signature.
1082 EOF
1083 test_config format.signaturefile mail-signature &&
1084 git format-patch --stdout \
1085 --signature-file=other-mail-signature -1 >output &&
1086 check_patch output &&
1087 sed -e "1,/^-- \$/d" output >actual &&
1088 {
1089 cat other-mail-signature && echo
1090 } >expect &&
1091 test_cmp expect actual
1092 '
1093
1094 test_expect_success '--signature overrides format.signaturefile' '
1095 test_config format.signaturefile mail-signature &&
1096 git format-patch --stdout --signature="my sig" -1 >output &&
1097 check_patch output &&
1098 grep "my sig" output
1099 '
1100
1101 test_expect_success TTY 'format-patch --stdout paginates' '
1102 rm -f pager_used &&
1103 test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
1104 test_path_is_file pager_used
1105 '
1106
1107 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
1108 rm -f pager_used &&
1109 test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
1110 test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
1111 test_path_is_missing pager_used &&
1112 test_path_is_missing .git/pager_used
1113 '
1114
1115 test_expect_success 'format-patch handles multi-line subjects' '
1116 rm -rf patches/ &&
1117 echo content >>file &&
1118 test_write_lines one two three >msg &&
1119 git add file &&
1120 git commit -F msg &&
1121 git format-patch -o patches -1 &&
1122 grep ^Subject: patches/0001-one.patch >actual &&
1123 echo "Subject: [PATCH] one two three" >expect &&
1124 test_cmp expect actual
1125 '
1126
1127 test_expect_success 'format-patch handles multi-line encoded subjects' '
1128 rm -rf patches/ &&
1129 echo content >>file &&
1130 test_write_lines en två tre >msg &&
1131 git add file &&
1132 git commit -F msg &&
1133 git format-patch -o patches -1 &&
1134 grep ^Subject: patches/0001-en.patch >actual &&
1135 echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
1136 test_cmp expect actual
1137 '
1138
1139 M8="foo bar "
1140 M64=$M8$M8$M8$M8$M8$M8$M8$M8
1141 M512=$M64$M64$M64$M64$M64$M64$M64$M64
1142 cat >expect <<'EOF'
1143 Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1144 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1145 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1146 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1147 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1148 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1149 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1150 EOF
1151 test_expect_success 'format-patch wraps extremely long subject (ascii)' '
1152 echo content >>file &&
1153 git add file &&
1154 git commit -m "$M512" &&
1155 git format-patch --stdout -1 >patch &&
1156 sed -n "/^Subject/p; /^ /p; /^$/q" patch >subject &&
1157 test_cmp expect subject
1158 '
1159
1160 M8="föö bar "
1161 M64=$M8$M8$M8$M8$M8$M8$M8$M8
1162 M512=$M64$M64$M64$M64$M64$M64$M64$M64
1163 cat >expect <<'EOF'
1164 Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1165 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1166 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1167 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1168 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1169 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1170 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1171 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1172 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1173 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1174 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1175 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1176 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1177 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1178 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1179 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1180 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1181 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1182 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1183 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1184 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1185 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1186 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1187 =?UTF-8?q?bar?=
1188 EOF
1189 test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1190 rm -rf patches/ &&
1191 echo content >>file &&
1192 git add file &&
1193 git commit -m "$M512" &&
1194 git format-patch --stdout -1 >patch &&
1195 sed -n "/^Subject/p; /^ /p; /^$/q" patch >subject &&
1196 test_cmp expect subject
1197 '
1198
1199 check_author() {
1200 echo content >>file &&
1201 git add file &&
1202 GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1203 git format-patch --stdout -1 >patch &&
1204 sed -n "/^From: /p; /^ /p; /^$/q" patch >actual &&
1205 test_cmp expect actual
1206 }
1207
1208 cat >expect <<'EOF'
1209 From: "Foo B. Bar" <author@example.com>
1210 EOF
1211 test_expect_success 'format-patch quotes dot in from-headers' '
1212 check_author "Foo B. Bar"
1213 '
1214
1215 cat >expect <<'EOF'
1216 From: "Foo \"The Baz\" Bar" <author@example.com>
1217 EOF
1218 test_expect_success 'format-patch quotes double-quote in from-headers' '
1219 check_author "Foo \"The Baz\" Bar"
1220 '
1221
1222 cat >expect <<'EOF'
1223 From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1224 EOF
1225 test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1226 check_author "Föo Bar"
1227 '
1228
1229 cat >expect <<'EOF'
1230 From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1231 EOF
1232 test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1233 check_author "Föo B. Bar"
1234 '
1235
1236 cat >expect <<EOF
1237 From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1238 <author@example.com>
1239 EOF
1240 test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1241 check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1242 '
1243
1244 cat >expect <<'EOF'
1245 From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1246 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1247 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1248 EOF
1249 test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1250 check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1251 '
1252
1253 cat >expect <<'EOF'
1254 From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1255 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1256 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1257 EOF
1258 test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1259 check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1260 '
1261
1262 cat >expect <<'EOF'
1263 From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1264 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1265 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1266 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1267 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1268 EOF
1269 test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1270 check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1271 '
1272
1273 cat >expect <<'EOF'
1274 From: Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1275 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1276 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1277 EOF
1278 test_expect_success 'format-patch wraps extremely long from-header (non-ASCII without Q-encoding)' '
1279 echo content >>file &&
1280 git add file &&
1281 GIT_AUTHOR_NAME="Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar" \
1282 git commit -m author-check &&
1283 git format-patch --no-encode-email-headers --stdout -1 >patch &&
1284 sed -n "/^From: /p; /^ /p; /^$/q" patch >actual &&
1285 test_cmp expect actual
1286 '
1287
1288 cat >expect <<'EOF'
1289 Subject: [PATCH] Foö
1290 EOF
1291 test_expect_success 'subject lines are unencoded with --no-encode-email-headers' '
1292 echo content >>file &&
1293 git add file &&
1294 git commit -m "Foö" &&
1295 git format-patch --no-encode-email-headers -1 --stdout >patch &&
1296 grep ^Subject: patch >actual &&
1297 test_cmp expect actual
1298 '
1299
1300 cat >expect <<'EOF'
1301 Subject: [PATCH] Foö
1302 EOF
1303 test_expect_success 'subject lines are unencoded with format.encodeEmailHeaders=false' '
1304 echo content >>file &&
1305 git add file &&
1306 git commit -m "Foö" &&
1307 git config format.encodeEmailHeaders false &&
1308 git format-patch -1 --stdout >patch &&
1309 grep ^Subject: patch >actual &&
1310 test_cmp expect actual
1311 '
1312
1313 cat >expect <<'EOF'
1314 Subject: [PATCH] =?UTF-8?q?Fo=C3=B6?=
1315 EOF
1316 test_expect_success '--encode-email-headers overrides format.encodeEmailHeaders' '
1317 echo content >>file &&
1318 git add file &&
1319 git commit -m "Foö" &&
1320 git config format.encodeEmailHeaders false &&
1321 git format-patch --encode-email-headers -1 --stdout >patch &&
1322 grep ^Subject: patch >actual &&
1323 test_cmp expect actual
1324 '
1325
1326 cat >expect <<'EOF'
1327 Subject: header with . in it
1328 EOF
1329 test_expect_success 'subject lines do not have 822 atom-quoting' '
1330 echo content >>file &&
1331 git add file &&
1332 git commit -m "header with . in it" &&
1333 git format-patch -k -1 --stdout >patch &&
1334 grep ^Subject: patch >actual &&
1335 test_cmp expect actual
1336 '
1337
1338 cat >expect <<'EOF'
1339 Subject: [PREFIX 1/1] header with . in it
1340 EOF
1341 test_expect_success 'subject prefixes have space prepended' '
1342 git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1343 grep ^Subject: patch >actual &&
1344 test_cmp expect actual
1345 '
1346
1347 cat >expect <<'EOF'
1348 Subject: [1/1] header with . in it
1349 EOF
1350 test_expect_success 'empty subject prefix does not have extra space' '
1351 git format-patch -n -1 --stdout --subject-prefix= >patch &&
1352 grep ^Subject: patch >actual &&
1353 test_cmp expect actual
1354 '
1355
1356 test_expect_success '--rfc' '
1357 cat >expect <<-\EOF &&
1358 Subject: [RFC PATCH 1/1] header with . in it
1359 EOF
1360 git format-patch -n -1 --stdout --rfc >patch &&
1361 grep ^Subject: patch >actual &&
1362 test_cmp expect actual
1363 '
1364
1365 test_expect_success '--from=ident notices bogus ident' '
1366 test_must_fail git format-patch -1 --stdout --from=foo >patch
1367 '
1368
1369 test_expect_success '--from=ident replaces author' '
1370 git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1371 cat >expect <<-\EOF &&
1372 From: Me <me@example.com>
1373
1374 From: A U Thor <author@example.com>
1375
1376 EOF
1377 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1378 test_cmp expect patch.head
1379 '
1380
1381 test_expect_success '--from uses committer ident' '
1382 git format-patch -1 --stdout --from >patch &&
1383 cat >expect <<-\EOF &&
1384 From: C O Mitter <committer@example.com>
1385
1386 From: A U Thor <author@example.com>
1387
1388 EOF
1389 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1390 test_cmp expect patch.head
1391 '
1392
1393 test_expect_success '--from omits redundant in-body header' '
1394 git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1395 cat >expect <<-\EOF &&
1396 From: A U Thor <author@example.com>
1397
1398 EOF
1399 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1400 test_cmp expect patch.head
1401 '
1402
1403 test_expect_success 'with --force-in-body-from, redundant in-body from is kept' '
1404 git format-patch --force-in-body-from \
1405 -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1406 cat >expect <<-\EOF &&
1407 From: A U Thor <author@example.com>
1408
1409 From: A U Thor <author@example.com>
1410
1411 EOF
1412 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1413 test_cmp expect patch.head
1414 '
1415
1416 test_expect_success 'format.forceInBodyFrom, equivalent to --force-in-body-from' '
1417 git -c format.forceInBodyFrom=yes format-patch \
1418 -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1419 cat >expect <<-\EOF &&
1420 From: A U Thor <author@example.com>
1421
1422 From: A U Thor <author@example.com>
1423
1424 EOF
1425 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1426 test_cmp expect patch.head
1427 '
1428
1429 test_expect_success 'format.forceInBodyFrom, equivalent to --force-in-body-from' '
1430 git -c format.forceInBodyFrom=yes format-patch --no-force-in-body-from \
1431 -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1432 cat >expect <<-\EOF &&
1433 From: A U Thor <author@example.com>
1434
1435 EOF
1436 sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
1437 test_cmp expect patch.head
1438 '
1439
1440 test_expect_success 'in-body headers trigger content encoding' '
1441 test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1442 test_when_finished "git reset --hard HEAD^" &&
1443 git format-patch -1 --stdout --from >patch &&
1444 cat >expect <<-\EOF &&
1445 From: C O Mitter <committer@example.com>
1446 Content-Type: text/plain; charset=UTF-8
1447
1448 From: éxötìc <author@example.com>
1449
1450 EOF
1451 sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" patch >patch.head &&
1452 test_cmp expect patch.head
1453 '
1454
1455 append_signoff()
1456 {
1457 C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1458 git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1459 sed -n -e "1,/^---$/p" append_signoff.patch |
1460 grep -E -n "^Subject|Sign|^$"
1461 }
1462
1463 test_expect_success 'signoff: commit with no body' '
1464 append_signoff </dev/null >actual &&
1465 cat <<-\EOF | sed "s/EOL$//" >expect &&
1466 4:Subject: [PATCH] EOL
1467 8:
1468 9:Signed-off-by: C O Mitter <committer@example.com>
1469 EOF
1470 test_cmp expect actual
1471 '
1472
1473 test_expect_success 'signoff: commit with only subject' '
1474 echo subject | append_signoff >actual &&
1475 cat >expect <<-\EOF &&
1476 4:Subject: [PATCH] subject
1477 8:
1478 9:Signed-off-by: C O Mitter <committer@example.com>
1479 EOF
1480 test_cmp expect actual
1481 '
1482
1483 test_expect_success 'signoff: commit with only subject that does not end with NL' '
1484 printf subject | append_signoff >actual &&
1485 cat >expect <<-\EOF &&
1486 4:Subject: [PATCH] subject
1487 8:
1488 9:Signed-off-by: C O Mitter <committer@example.com>
1489 EOF
1490 test_cmp expect actual
1491 '
1492
1493 test_expect_success 'signoff: no existing signoffs' '
1494 append_signoff <<-\EOF >actual &&
1495 subject
1496
1497 body
1498 EOF
1499 cat >expect <<-\EOF &&
1500 4:Subject: [PATCH] subject
1501 8:
1502 10:
1503 11:Signed-off-by: C O Mitter <committer@example.com>
1504 EOF
1505 test_cmp expect actual
1506 '
1507
1508 test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1509 printf "subject\n\nbody" | append_signoff >actual &&
1510 cat >expect <<-\EOF &&
1511 4:Subject: [PATCH] subject
1512 8:
1513 10:
1514 11:Signed-off-by: C O Mitter <committer@example.com>
1515 EOF
1516 test_cmp expect actual
1517 '
1518
1519 test_expect_success 'signoff: some random signoff' '
1520 append_signoff <<-\EOF >actual &&
1521 subject
1522
1523 body
1524
1525 Signed-off-by: my@house
1526 EOF
1527 cat >expect <<-\EOF &&
1528 4:Subject: [PATCH] subject
1529 8:
1530 10:
1531 11:Signed-off-by: my@house
1532 12:Signed-off-by: C O Mitter <committer@example.com>
1533 EOF
1534 test_cmp expect actual
1535 '
1536
1537 test_expect_success 'signoff: misc conforming footer elements' '
1538 append_signoff <<-\EOF >actual &&
1539 subject
1540
1541 body
1542
1543 Signed-off-by: my@house
1544 (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1545 Tested-by: Some One <someone@example.com>
1546 Bug: 1234
1547 EOF
1548 cat >expect <<-\EOF &&
1549 4:Subject: [PATCH] subject
1550 8:
1551 10:
1552 11:Signed-off-by: my@house
1553 15:Signed-off-by: C O Mitter <committer@example.com>
1554 EOF
1555 test_cmp expect actual
1556 '
1557
1558 test_expect_success 'signoff: some random signoff-alike' '
1559 append_signoff <<-\EOF >actual &&
1560 subject
1561
1562 body
1563 Fooled-by-me: my@house
1564 EOF
1565 cat >expect <<-\EOF &&
1566 4:Subject: [PATCH] subject
1567 8:
1568 11:
1569 12:Signed-off-by: C O Mitter <committer@example.com>
1570 EOF
1571 test_cmp expect actual
1572 '
1573
1574 test_expect_success 'signoff: not really a signoff' '
1575 append_signoff <<-\EOF >actual &&
1576 subject
1577
1578 I want to mention about Signed-off-by: here.
1579 EOF
1580 cat >expect <<-\EOF &&
1581 4:Subject: [PATCH] subject
1582 8:
1583 9:I want to mention about Signed-off-by: here.
1584 10:
1585 11:Signed-off-by: C O Mitter <committer@example.com>
1586 EOF
1587 test_cmp expect actual
1588 '
1589
1590 test_expect_success 'signoff: not really a signoff (2)' '
1591 append_signoff <<-\EOF >actual &&
1592 subject
1593
1594 My unfortunate
1595 Signed-off-by: example happens to be wrapped here.
1596 EOF
1597 cat >expect <<-\EOF &&
1598 4:Subject: [PATCH] subject
1599 8:
1600 10:Signed-off-by: example happens to be wrapped here.
1601 11:Signed-off-by: C O Mitter <committer@example.com>
1602 EOF
1603 test_cmp expect actual
1604 '
1605
1606 test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1607 append_signoff <<-\EOF >actual &&
1608 subject
1609
1610 Signed-off-by: my@house
1611 Signed-off-by: your@house
1612
1613 A lot of houses.
1614 EOF
1615 cat >expect <<-\EOF &&
1616 4:Subject: [PATCH] subject
1617 8:
1618 9:Signed-off-by: my@house
1619 10:Signed-off-by: your@house
1620 11:
1621 13:
1622 14:Signed-off-by: C O Mitter <committer@example.com>
1623 EOF
1624 test_cmp expect actual
1625 '
1626
1627 test_expect_success 'signoff: the same signoff at the end' '
1628 append_signoff <<-\EOF >actual &&
1629 subject
1630
1631 body
1632
1633 Signed-off-by: C O Mitter <committer@example.com>
1634 EOF
1635 cat >expect <<-\EOF &&
1636 4:Subject: [PATCH] subject
1637 8:
1638 10:
1639 11:Signed-off-by: C O Mitter <committer@example.com>
1640 EOF
1641 test_cmp expect actual
1642 '
1643
1644 test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1645 printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1646 append_signoff >actual &&
1647 cat >expect <<-\EOF &&
1648 4:Subject: [PATCH] subject
1649 8:
1650 9:Signed-off-by: C O Mitter <committer@example.com>
1651 EOF
1652 test_cmp expect actual
1653 '
1654
1655 test_expect_success 'signoff: the same signoff NOT at the end' '
1656 append_signoff <<-\EOF >actual &&
1657 subject
1658
1659 body
1660
1661 Signed-off-by: C O Mitter <committer@example.com>
1662 Signed-off-by: my@house
1663 EOF
1664 cat >expect <<-\EOF &&
1665 4:Subject: [PATCH] subject
1666 8:
1667 10:
1668 11:Signed-off-by: C O Mitter <committer@example.com>
1669 12:Signed-off-by: my@house
1670 EOF
1671 test_cmp expect actual
1672 '
1673
1674 test_expect_success 'signoff: tolerate garbage in conforming footer' '
1675 append_signoff <<-\EOF >actual &&
1676 subject
1677
1678 body
1679
1680 Tested-by: my@house
1681 Some Trash
1682 Signed-off-by: C O Mitter <committer@example.com>
1683 EOF
1684 cat >expect <<-\EOF &&
1685 4:Subject: [PATCH] subject
1686 8:
1687 10:
1688 13:Signed-off-by: C O Mitter <committer@example.com>
1689 EOF
1690 test_cmp expect actual
1691 '
1692
1693 test_expect_success 'signoff: respect trailer config' '
1694 append_signoff <<-\EOF >actual &&
1695 subject
1696
1697 Myfooter: x
1698 Some Trash
1699 EOF
1700 cat >expect <<-\EOF &&
1701 4:Subject: [PATCH] subject
1702 8:
1703 11:
1704 12:Signed-off-by: C O Mitter <committer@example.com>
1705 EOF
1706 test_cmp expect actual &&
1707
1708 test_config trailer.Myfooter.ifexists add &&
1709 append_signoff <<-\EOF >actual &&
1710 subject
1711
1712 Myfooter: x
1713 Some Trash
1714 EOF
1715 cat >expect <<-\EOF &&
1716 4:Subject: [PATCH] subject
1717 8:
1718 11:Signed-off-by: C O Mitter <committer@example.com>
1719 EOF
1720 test_cmp expect actual
1721 '
1722
1723 test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1724 append_signoff <<-\EOF >actual &&
1725 subject
1726
1727 body
1728
1729 Reviewed-id: Noone
1730 Tested-by: my@house
1731 Change-id: Ideadbeef
1732 Signed-off-by: C O Mitter <committer@example.com>
1733 Bug: 1234
1734 EOF
1735 cat >expect <<-\EOF &&
1736 4:Subject: [PATCH] subject
1737 8:
1738 10:
1739 14:Signed-off-by: C O Mitter <committer@example.com>
1740 EOF
1741 test_cmp expect actual
1742 '
1743
1744 test_expect_success 'format patch ignores color.ui' '
1745 test_unconfig color.ui &&
1746 git format-patch --stdout -1 >expect &&
1747 test_config color.ui always &&
1748 git format-patch --stdout -1 >actual &&
1749 test_cmp expect actual
1750 '
1751
1752 test_expect_success 'format patch respects diff.relative' '
1753 rm -rf subdir &&
1754 mkdir subdir &&
1755 echo other content >subdir/file2 &&
1756 git add subdir/file2 &&
1757 git commit -F msg &&
1758 test_unconfig diff.relative &&
1759 git format-patch --relative=subdir --stdout -1 >expect &&
1760 test_config diff.relative true &&
1761 git -C subdir format-patch --stdout -1 >actual &&
1762 test_cmp expect actual
1763 '
1764
1765 test_expect_success 'cover letter with invalid --cover-from-description and config' '
1766 test_config branch.rebuild-1.description "config subject
1767
1768 body" &&
1769 test_must_fail git format-patch --cover-letter --cover-from-description garbage main &&
1770 test_config format.coverFromDescription garbage &&
1771 test_must_fail git format-patch --cover-letter main
1772 '
1773
1774 test_expect_success 'cover letter with format.coverFromDescription = default' '
1775 test_config branch.rebuild-1.description "config subject
1776
1777 body" &&
1778 test_config format.coverFromDescription default &&
1779 git checkout rebuild-1 &&
1780 git format-patch --stdout --cover-letter main >actual &&
1781 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1782 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1783 grep "^config subject$" actual &&
1784 grep "^body$" actual
1785 '
1786
1787 test_expect_success 'cover letter with --cover-from-description default' '
1788 test_config branch.rebuild-1.description "config subject
1789
1790 body" &&
1791 git checkout rebuild-1 &&
1792 git format-patch --stdout --cover-letter --cover-from-description default main >actual &&
1793 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1794 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1795 grep "^config subject$" actual &&
1796 grep "^body$" actual
1797 '
1798
1799 test_expect_success 'cover letter with format.coverFromDescription = none' '
1800 test_config branch.rebuild-1.description "config subject
1801
1802 body" &&
1803 test_config format.coverFromDescription none &&
1804 git checkout rebuild-1 &&
1805 git format-patch --stdout --cover-letter main >actual &&
1806 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1807 grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1808 ! grep "^config subject$" actual &&
1809 ! grep "^body$" actual
1810 '
1811
1812 test_expect_success 'cover letter with --cover-from-description none' '
1813 test_config branch.rebuild-1.description "config subject
1814
1815 body" &&
1816 git checkout rebuild-1 &&
1817 git format-patch --stdout --cover-letter --cover-from-description none main >actual &&
1818 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1819 grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1820 ! grep "^config subject$" actual &&
1821 ! grep "^body$" actual
1822 '
1823
1824 test_expect_success 'cover letter with format.coverFromDescription = message' '
1825 test_config branch.rebuild-1.description "config subject
1826
1827 body" &&
1828 test_config format.coverFromDescription message &&
1829 git checkout rebuild-1 &&
1830 git format-patch --stdout --cover-letter main >actual &&
1831 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1832 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1833 grep "^config subject$" actual &&
1834 grep "^body$" actual
1835 '
1836
1837 test_expect_success 'cover letter with --cover-from-description message' '
1838 test_config branch.rebuild-1.description "config subject
1839
1840 body" &&
1841 git checkout rebuild-1 &&
1842 git format-patch --stdout --cover-letter --cover-from-description message main >actual &&
1843 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1844 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1845 grep "^config subject$" actual &&
1846 grep "^body$" actual
1847 '
1848
1849 test_expect_success 'cover letter with format.coverFromDescription = subject' '
1850 test_config branch.rebuild-1.description "config subject
1851
1852 body" &&
1853 test_config format.coverFromDescription subject &&
1854 git checkout rebuild-1 &&
1855 git format-patch --stdout --cover-letter main >actual &&
1856 grep "^Subject: \[PATCH 0/2\] config subject$" actual &&
1857 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1858 ! grep "^config subject$" actual &&
1859 grep "^body$" actual
1860 '
1861
1862 test_expect_success 'cover letter with --cover-from-description subject' '
1863 test_config branch.rebuild-1.description "config subject
1864
1865 body" &&
1866 git checkout rebuild-1 &&
1867 git format-patch --stdout --cover-letter --cover-from-description subject main >actual &&
1868 grep "^Subject: \[PATCH 0/2\] config subject$" actual &&
1869 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1870 ! grep "^config subject$" actual &&
1871 grep "^body$" actual
1872 '
1873
1874 test_expect_success 'cover letter with format.coverFromDescription = auto (short subject line)' '
1875 test_config branch.rebuild-1.description "config subject
1876
1877 body" &&
1878 test_config format.coverFromDescription auto &&
1879 git checkout rebuild-1 &&
1880 git format-patch --stdout --cover-letter main >actual &&
1881 grep "^Subject: \[PATCH 0/2\] config subject$" actual &&
1882 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1883 ! grep "^config subject$" actual &&
1884 grep "^body$" actual
1885 '
1886
1887 test_expect_success 'cover letter with --cover-from-description auto (short subject line)' '
1888 test_config branch.rebuild-1.description "config subject
1889
1890 body" &&
1891 git checkout rebuild-1 &&
1892 git format-patch --stdout --cover-letter --cover-from-description auto main >actual &&
1893 grep "^Subject: \[PATCH 0/2\] config subject$" actual &&
1894 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1895 ! grep "^config subject$" actual &&
1896 grep "^body$" actual
1897 '
1898
1899 test_expect_success 'cover letter with format.coverFromDescription = auto (long subject line)' '
1900 test_config branch.rebuild-1.description "this is a really long first line and it is over 100 characters long which is the threshold for long subjects
1901
1902 body" &&
1903 test_config format.coverFromDescription auto &&
1904 git checkout rebuild-1 &&
1905 git format-patch --stdout --cover-letter main >actual &&
1906 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1907 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1908 grep "^this is a really long first line and it is over 100 characters long which is the threshold for long subjects$" actual &&
1909 grep "^body$" actual
1910 '
1911
1912 test_expect_success 'cover letter with --cover-from-description auto (long subject line)' '
1913 test_config branch.rebuild-1.description "this is a really long first line and it is over 100 characters long which is the threshold for long subjects
1914
1915 body" &&
1916 git checkout rebuild-1 &&
1917 git format-patch --stdout --cover-letter --cover-from-description auto main >actual &&
1918 grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual &&
1919 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1920 grep "^this is a really long first line and it is over 100 characters long which is the threshold for long subjects$" actual &&
1921 grep "^body$" actual
1922 '
1923
1924 test_expect_success 'cover letter with command-line --cover-from-description overrides config' '
1925 test_config branch.rebuild-1.description "config subject
1926
1927 body" &&
1928 test_config format.coverFromDescription none &&
1929 git checkout rebuild-1 &&
1930 git format-patch --stdout --cover-letter --cover-from-description subject main >actual &&
1931 grep "^Subject: \[PATCH 0/2\] config subject$" actual &&
1932 ! grep "^\*\*\* BLURB HERE \*\*\*$" actual &&
1933 ! grep "^config subject$" actual &&
1934 grep "^body$" actual
1935 '
1936
1937 test_expect_success 'cover letter using branch description (1)' '
1938 git checkout rebuild-1 &&
1939 test_config branch.rebuild-1.description hello &&
1940 git format-patch --stdout --cover-letter main >actual &&
1941 grep hello actual
1942 '
1943
1944 test_expect_success 'cover letter using branch description (2)' '
1945 git checkout rebuild-1 &&
1946 test_config branch.rebuild-1.description hello &&
1947 git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1948 grep hello actual
1949 '
1950
1951 test_expect_success 'cover letter using branch description (3)' '
1952 git checkout rebuild-1 &&
1953 test_config branch.rebuild-1.description hello &&
1954 git format-patch --stdout --cover-letter ^main rebuild-1 >actual &&
1955 grep hello actual
1956 '
1957
1958 test_expect_success 'cover letter using branch description (4)' '
1959 git checkout rebuild-1 &&
1960 test_config branch.rebuild-1.description hello &&
1961 git format-patch --stdout --cover-letter main.. >actual &&
1962 grep hello actual
1963 '
1964
1965 test_expect_success 'cover letter using branch description (5)' '
1966 git checkout rebuild-1 &&
1967 test_config branch.rebuild-1.description hello &&
1968 git format-patch --stdout --cover-letter -2 HEAD >actual &&
1969 grep hello actual
1970 '
1971
1972 test_expect_success 'cover letter using branch description (6)' '
1973 git checkout rebuild-1 &&
1974 test_config branch.rebuild-1.description hello &&
1975 git format-patch --stdout --cover-letter -2 >actual &&
1976 grep hello actual
1977 '
1978
1979 test_expect_success 'cover letter with nothing' '
1980 git format-patch --stdout --cover-letter >actual &&
1981 test_line_count = 0 actual
1982 '
1983
1984 test_expect_success 'cover letter auto' '
1985 mkdir -p tmp &&
1986 test_when_finished "rm -rf tmp;
1987 git config --unset format.coverletter" &&
1988
1989 git config format.coverletter auto &&
1990 git format-patch -o tmp -1 >list &&
1991 test_line_count = 1 list &&
1992 git format-patch -o tmp -2 >list &&
1993 test_line_count = 3 list
1994 '
1995
1996 test_expect_success 'cover letter auto user override' '
1997 mkdir -p tmp &&
1998 test_when_finished "rm -rf tmp;
1999 git config --unset format.coverletter" &&
2000
2001 git config format.coverletter auto &&
2002 git format-patch -o tmp --cover-letter -1 >list &&
2003 test_line_count = 2 list &&
2004 git format-patch -o tmp --cover-letter -2 >list &&
2005 test_line_count = 3 list &&
2006 git format-patch -o tmp --no-cover-letter -1 >list &&
2007 test_line_count = 1 list &&
2008 git format-patch -o tmp --no-cover-letter -2 >list &&
2009 test_line_count = 2 list
2010 '
2011
2012 test_expect_success 'format-patch --zero-commit' '
2013 git format-patch --zero-commit --stdout v2..v1 >patch2 &&
2014 grep "^From " patch2 | sort | uniq >actual &&
2015 echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
2016 test_cmp expect actual
2017 '
2018
2019 test_expect_success 'From line has expected format' '
2020 git format-patch --stdout v2..v1 >patch2 &&
2021 grep "^From " patch2 >from &&
2022 grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
2023 test_cmp from filtered
2024 '
2025
2026 test_expect_success 'format-patch -o with no leading directories' '
2027 rm -fr patches &&
2028 git format-patch -o patches main..side &&
2029 count=$(git rev-list --count main..side) &&
2030 ls patches >list &&
2031 test_line_count = $count list
2032 '
2033
2034 test_expect_success 'format-patch -o with leading existing directories' '
2035 rm -rf existing-dir &&
2036 mkdir existing-dir &&
2037 git format-patch -o existing-dir/patches main..side &&
2038 count=$(git rev-list --count main..side) &&
2039 ls existing-dir/patches >list &&
2040 test_line_count = $count list
2041 '
2042
2043 test_expect_success 'format-patch -o with leading non-existing directories' '
2044 rm -rf non-existing-dir &&
2045 git format-patch -o non-existing-dir/patches main..side &&
2046 count=$(git rev-list --count main..side) &&
2047 test_path_is_dir non-existing-dir &&
2048 ls non-existing-dir/patches >list &&
2049 test_line_count = $count list
2050 '
2051
2052 test_expect_success 'format-patch format.outputDirectory option' '
2053 test_config format.outputDirectory patches &&
2054 rm -fr patches &&
2055 git format-patch main..side &&
2056 count=$(git rev-list --count main..side) &&
2057 ls patches >list &&
2058 test_line_count = $count list
2059 '
2060
2061 test_expect_success 'format-patch -o overrides format.outputDirectory' '
2062 test_config format.outputDirectory patches &&
2063 rm -fr patches patchset &&
2064 git format-patch main..side -o patchset &&
2065 test_path_is_missing patches &&
2066 test_path_is_dir patchset
2067 '
2068
2069 test_expect_success 'format-patch forbids multiple outputs' '
2070 rm -fr outfile outdir &&
2071 test_must_fail \
2072 git format-patch --stdout --output-directory=outdir &&
2073 test_must_fail \
2074 git format-patch --stdout --output=outfile &&
2075 test_must_fail \
2076 git format-patch --output=outfile --output-directory=outdir
2077 '
2078
2079 test_expect_success 'configured outdir does not conflict with output options' '
2080 rm -fr outfile outdir &&
2081 test_config format.outputDirectory outdir &&
2082 git format-patch --stdout &&
2083 test_path_is_missing outdir &&
2084 git format-patch --output=outfile &&
2085 test_path_is_missing outdir
2086 '
2087
2088 test_expect_success 'format-patch --output' '
2089 rm -fr outfile &&
2090 git format-patch -3 --stdout HEAD >expect &&
2091 git format-patch -3 --output=outfile HEAD &&
2092 test_cmp expect outfile
2093 '
2094
2095 test_expect_success 'format-patch --cover-letter --output' '
2096 rm -fr outfile &&
2097 git format-patch --cover-letter -3 --stdout HEAD >expect &&
2098 git format-patch --cover-letter -3 --output=outfile HEAD &&
2099 test_cmp expect outfile
2100 '
2101
2102 test_expect_success 'format-patch --base' '
2103 git checkout patchid &&
2104
2105 git format-patch --stdout --base=HEAD~3 -1 >patch &&
2106 tail -n 7 patch >actual1 &&
2107
2108 git format-patch --stdout --base=HEAD~3 HEAD~.. >patch &&
2109 tail -n 7 patch >actual2 &&
2110
2111 echo >expect &&
2112 git rev-parse HEAD~3 >commit-id-base &&
2113 echo "base-commit: $(cat commit-id-base)" >>expect &&
2114
2115 git show --patch HEAD~2 >patch &&
2116 git patch-id --stable <patch >patch.id.raw &&
2117 awk "{print \"prerequisite-patch-id:\", \$1}" <patch.id.raw >>expect &&
2118
2119 git show --patch HEAD~1 >patch &&
2120 git patch-id --stable <patch >patch.id.raw &&
2121 awk "{print \"prerequisite-patch-id:\", \$1}" <patch.id.raw >>expect &&
2122
2123 signature >>expect &&
2124 test_cmp expect actual1 &&
2125 test_cmp expect actual2 &&
2126
2127 echo >fail &&
2128 echo "base-commit: $(cat commit-id-base)" >>fail &&
2129
2130 git show --patch HEAD~2 >patch &&
2131 git patch-id --unstable <patch >patch.id.raw &&
2132 awk "{print \"prerequisite-patch-id:\", \$1}" <patch.id.raw >>fail &&
2133
2134 git show --patch HEAD~1 >patch &&
2135 git patch-id --unstable <patch >patch.id.raw &&
2136 awk "{print \"prerequisite-patch-id:\", \$1}" <patch.id.raw >>fail &&
2137
2138 signature >>fail &&
2139 ! test_cmp fail actual1 &&
2140 ! test_cmp fail actual2
2141 '
2142
2143 test_expect_success 'format-patch --base errors out when base commit is in revision list' '
2144 test_must_fail git format-patch --base=HEAD -2 &&
2145 test_must_fail git format-patch --base=HEAD~1 -2 &&
2146 git format-patch --stdout --base=HEAD~2 -2 >patch &&
2147 grep "^base-commit:" patch >actual &&
2148 git rev-parse HEAD~2 >commit-id-base &&
2149 echo "base-commit: $(cat commit-id-base)" >expect &&
2150 test_cmp expect actual
2151 '
2152
2153 test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
2154 # For history as below:
2155 #
2156 # ---Q---P---Z---Y---*---X
2157 # \ /
2158 # ------------W
2159 #
2160 # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
2161 git checkout -b topic1 main &&
2162 git rev-parse HEAD >commit-id-base &&
2163 test_commit P &&
2164 git rev-parse HEAD >commit-id-P &&
2165 test_commit Z &&
2166 git rev-parse HEAD >commit-id-Z &&
2167 test_commit Y &&
2168 git checkout -b topic2 main &&
2169 test_commit W &&
2170 git merge topic1 &&
2171 test_commit X &&
2172 test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
2173 test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
2174 git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
2175 grep "^base-commit:" patch >actual &&
2176 echo "base-commit: $(cat commit-id-base)" >expect &&
2177 test_cmp expect actual
2178 '
2179
2180 test_expect_success 'format-patch --base=auto' '
2181 git checkout -b upstream main &&
2182 git checkout -b local upstream &&
2183 git branch --set-upstream-to=upstream &&
2184 test_commit N1 &&
2185 test_commit N2 &&
2186 git format-patch --stdout --base=auto -2 >patch &&
2187 grep "^base-commit:" patch >actual &&
2188 git rev-parse upstream >commit-id-base &&
2189 echo "base-commit: $(cat commit-id-base)" >expect &&
2190 test_cmp expect actual
2191 '
2192
2193 test_expect_success 'format-patch errors out when history involves criss-cross' '
2194 # setup criss-cross history
2195 #
2196 # B---M1---D
2197 # / \ /
2198 # A X
2199 # \ / \
2200 # C---M2---E
2201 #
2202 git checkout main &&
2203 test_commit A &&
2204 git checkout -b xb main &&
2205 test_commit B &&
2206 git checkout -b xc main &&
2207 test_commit C &&
2208 git checkout -b xbc xb -- &&
2209 git merge xc &&
2210 git checkout -b xcb xc -- &&
2211 git branch --set-upstream-to=xbc &&
2212 git merge xb &&
2213 git checkout xbc &&
2214 test_commit D &&
2215 git checkout xcb &&
2216 test_commit E &&
2217 test_must_fail git format-patch --base=auto -1
2218 '
2219
2220 test_expect_success 'format-patch format.useAutoBase whenAble history involves criss-cross' '
2221 test_config format.useAutoBase whenAble &&
2222 git format-patch -1 >patch &&
2223 ! grep "^base-commit:" patch
2224 '
2225
2226 test_expect_success 'format-patch format.useAutoBase option' '
2227 git checkout local &&
2228 test_config format.useAutoBase true &&
2229 git format-patch --stdout -1 >patch &&
2230 grep "^base-commit:" patch >actual &&
2231 git rev-parse upstream >commit-id-base &&
2232 echo "base-commit: $(cat commit-id-base)" >expect &&
2233 test_cmp expect actual
2234 '
2235
2236 test_expect_success 'format-patch format.useAutoBase option with whenAble' '
2237 git checkout local &&
2238 test_config format.useAutoBase whenAble &&
2239 git format-patch --stdout -1 >patch &&
2240 grep "^base-commit:" patch >actual &&
2241 git rev-parse upstream >commit-id-base &&
2242 echo "base-commit: $(cat commit-id-base)" >expect &&
2243 test_cmp expect actual
2244 '
2245
2246 test_expect_success 'format-patch --base overrides format.useAutoBase' '
2247 test_config format.useAutoBase true &&
2248 git format-patch --stdout --base=HEAD~1 -1 >patch &&
2249 grep "^base-commit:" patch >actual &&
2250 git rev-parse HEAD~1 >commit-id-base &&
2251 echo "base-commit: $(cat commit-id-base)" >expect &&
2252 test_cmp expect actual
2253 '
2254
2255 test_expect_success 'format-patch --no-base overrides format.useAutoBase' '
2256 test_config format.useAutoBase true &&
2257 git format-patch --stdout --no-base -1 >patch &&
2258 ! grep "^base-commit:" patch
2259 '
2260
2261 test_expect_success 'format-patch --no-base overrides format.useAutoBase whenAble' '
2262 test_config format.useAutoBase whenAble &&
2263 git format-patch --stdout --no-base -1 >patch &&
2264 ! grep "^base-commit:" patch
2265 '
2266
2267 test_expect_success 'format-patch --base with --attach' '
2268 git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
2269 sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
2270 patch >actual &&
2271 test_write_lines 1 2 >expect &&
2272 test_cmp expect actual
2273 '
2274 test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
2275 test_when_finished "rm -fr patches" &&
2276 git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
2277 ! grep -E "^--+mimemime" patches/0000*.patch &&
2278 grep -E "^--+mimemime$" patches/0001*.patch >output &&
2279 test_line_count = 2 output &&
2280 grep -E "^--+mimemime--$" patches/0001*.patch >output &&
2281 test_line_count = 1 output
2282 '
2283
2284 test_expect_success 'format-patch with format.attach' '
2285 test_when_finished "rm -fr patches" &&
2286 separator=attachment-separator &&
2287 test_config format.attach "$separator" &&
2288 filename=$(git format-patch -o patches -1) &&
2289 grep "^Content-Type: multipart/.*$separator" "$filename"
2290 '
2291
2292 test_expect_success 'format-patch with format.attach=disabled' '
2293 test_when_finished "rm -fr patches" &&
2294 separator=attachment-separator &&
2295 test_config_global format.attach "$separator" &&
2296 test_config format.attach "" &&
2297 filename=$(git format-patch -o patches -1) &&
2298 # The output should not even declare content type for text/plain.
2299 ! grep "^Content-Type: multipart/" "$filename"
2300 '
2301
2302 test_expect_success '-c format.mboxrd format-patch' '
2303 sp=" " &&
2304 cat >msg <<-INPUT_END &&
2305 mboxrd should escape the body
2306
2307 From could trip up a loose mbox parser
2308 >From extra escape for reversibility
2309 >>From extra escape for reversibility 2
2310 from lower case not escaped
2311 Fromm bad speling not escaped
2312 From with leading space not escaped
2313
2314 F
2315 From
2316 From$sp
2317 From $sp
2318 From $sp
2319 INPUT_END
2320
2321 cat >expect <<-INPUT_END &&
2322 >From could trip up a loose mbox parser
2323 >>From extra escape for reversibility
2324 >>>From extra escape for reversibility 2
2325 from lower case not escaped
2326 Fromm bad speling not escaped
2327 From with leading space not escaped
2328
2329 F
2330 From
2331 From
2332 From
2333 From
2334 INPUT_END
2335
2336 C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
2337 git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch &&
2338 git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat &&
2339 test_cmp patch compat &&
2340 git grep -h --no-index -A11 \
2341 "^>From could trip up a loose mbox parser" patch >actual &&
2342 test_cmp expect actual
2343 '
2344
2345 test_expect_success 'interdiff: setup' '
2346 git checkout -b boop main &&
2347 test_commit fnorp blorp &&
2348 test_commit fleep blorp
2349 '
2350
2351 test_expect_success 'interdiff: cover-letter' '
2352 sed "y/q/ /" >expect <<-\EOF &&
2353 +fleep
2354 --q
2355 EOF
2356 git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
2357 test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
2358 test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
2359 sed "1,/^@@ /d; /^-- $/q" 0000-cover-letter.patch >actual &&
2360 test_cmp expect actual
2361 '
2362
2363 test_expect_success 'interdiff: reroll-count' '
2364 git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
2365 test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
2366 '
2367
2368 test_expect_success 'interdiff: reroll-count with a non-integer' '
2369 git format-patch --cover-letter --interdiff=boop~2 -v2.2 -1 boop &&
2370 test_i18ngrep "^Interdiff:$" v2.2-0000-cover-letter.patch
2371 '
2372
2373 test_expect_success 'interdiff: reroll-count with a integer' '
2374 git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
2375 test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
2376 '
2377
2378 test_expect_success 'interdiff: solo-patch' '
2379 cat >expect <<-\EOF &&
2380 +fleep
2381
2382 EOF
2383 git format-patch --interdiff=boop~2 -1 boop &&
2384 test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
2385 sed "1,/^ @@ /d; /^$/q" 0001-fleep.patch >actual &&
2386 test_cmp expect actual
2387 '
2388
2389 test_done