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