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