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