c07d868491bbbd2887931d8afd19d662a4ac5272
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 cnt=$(grep "^From " patch0 | wc -l) &&
64 test $cnt = 3
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 cnt=$(grep "^From " patch1 | wc -l) &&
71 test $cnt = 2
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 cnt=$(grep "^From " patch1 | wc -l) &&
79 test $cnt = 2
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 cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) &&
94 test $cnt = 3
95'
96
97test_expect_success 'format-patch result applies' '
98 git checkout -b rebuild-0 master &&
99 git am -3 patch0 &&
100 cnt=$(git rev-list master.. | wc -l) &&
101 test $cnt = 2
102'
103
104test_expect_success 'format-patch --ignore-if-in-upstream result applies' '
105 git checkout -b rebuild-1 master &&
106 git am -3 patch1 &&
107 cnt=$(git rev-list master.. | wc -l) &&
108 test $cnt = 2
109'
110
111test_expect_success 'commit did not screw up the log message' '
112 git cat-file commit side | grep "^Side .* with .* backslash-n"
113'
114
115test_expect_success 'format-patch did not screw up the log message' '
116 grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
117 grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
118'
119
120test_expect_success 'replay did not screw up the log message' '
121 git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
122'
123
124test_expect_success 'extra headers' '
125 git config format.headers "To: R E Cipient <rcipient@example.com>
126" &&
127 git config --add format.headers "Cc: S E Cipient <scipient@example.com>
128" &&
129 git format-patch --stdout master..side >patch2 &&
130 sed -e "/^\$/q" patch2 >hdrs2 &&
131 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
132 grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
133'
134
135test_expect_success 'extra headers without newlines' '
136 git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
137 git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
138 git format-patch --stdout master..side >patch3 &&
139 sed -e "/^\$/q" patch3 >hdrs3 &&
140 grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
141 grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
142'
143
144test_expect_success 'extra headers with multiple To:s' '
145 git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
146 git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
147 git format-patch --stdout master..side >patch4 &&
148 sed -e "/^\$/q" patch4 >hdrs4 &&
149 grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
150 grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
151'
152
153test_expect_success 'additional command line cc (ascii)' '
154 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
155 git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
156 grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
157 grep "^ *S E Cipient <scipient@example.com>\$" patch5
158'
159
160test_expect_failure 'additional command line cc (rfc822)' '
161 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
162 git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
163 grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
164 grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
165'
166
167test_expect_success 'command line headers' '
168 git config --unset-all format.headers &&
169 git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
170 grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
171'
172
173test_expect_success 'configuration headers and command line headers' '
174 git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
175 git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
176 grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
177 grep "^ *S E Cipient <scipient@example.com>\$" patch7
178'
179
180test_expect_success 'command line To: header (ascii)' '
181 git config --unset-all format.headers &&
182 git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
183 grep "^To: R E Cipient <rcipient@example.com>\$" patch8
184'
185
186test_expect_failure 'command line To: header (rfc822)' '
187 git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
188 grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8
189'
190
191test_expect_failure 'command line To: header (rfc2047)' '
192 git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
193 grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
194'
195
196test_expect_success 'configuration To: header (ascii)' '
197 git config format.to "R E Cipient <rcipient@example.com>" &&
198 git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
199 grep "^To: R E Cipient <rcipient@example.com>\$" patch9
200'
201
202test_expect_failure 'configuration To: header (rfc822)' '
203 git config format.to "R. E. Cipient <rcipient@example.com>" &&
204 git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
205 grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9
206'
207
208test_expect_failure 'configuration To: header (rfc2047)' '
209 git config format.to "R Ä Cipient <rcipient@example.com>" &&
210 git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
211 grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
212'
213
214# check_patch <patch>: Verify that <patch> looks like a half-sane
215# patch email to avoid a false positive with !grep
216check_patch () {
217 grep -e "^From:" "$1" &&
218 grep -e "^Date:" "$1" &&
219 grep -e "^Subject:" "$1"
220}
221
222test_expect_success 'format.from=false' '
223 git -c format.from=false format-patch --stdout master..side |
224 sed -e "/^\$/q" >patch &&
225 check_patch patch &&
226 ! grep "^From: C O Mitter <committer@example.com>\$" patch
227'
228
229test_expect_success 'format.from=true' '
230 git -c format.from=true format-patch --stdout master..side |
231 sed -e "/^\$/q" >patch &&
232 check_patch patch &&
233 grep "^From: C O Mitter <committer@example.com>\$" patch
234'
235
236test_expect_success 'format.from with address' '
237 git -c format.from="F R Om <from@example.com>" format-patch --stdout master..side |
238 sed -e "/^\$/q" >patch &&
239 check_patch patch &&
240 grep "^From: F R Om <from@example.com>\$" patch
241'
242
243test_expect_success '--no-from overrides format.from' '
244 git -c format.from="F R Om <from@example.com>" format-patch --no-from --stdout master..side |
245 sed -e "/^\$/q" >patch &&
246 check_patch patch &&
247 ! grep "^From: F R Om <from@example.com>\$" patch
248'
249
250test_expect_success '--from overrides format.from' '
251 git -c format.from="F R Om <from@example.com>" format-patch --from --stdout master..side |
252 sed -e "/^\$/q" >patch &&
253 check_patch patch &&
254 ! grep "^From: F R Om <from@example.com>\$" patch
255'
256
257test_expect_success '--no-to overrides config.to' '
258 git config --replace-all format.to \
259 "R E Cipient <rcipient@example.com>" &&
260 git format-patch --no-to --stdout master..side |
261 sed -e "/^\$/q" >patch10 &&
262 check_patch patch10 &&
263 ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
264'
265
266test_expect_success '--no-to and --to replaces config.to' '
267 git config --replace-all format.to \
268 "Someone <someone@out.there>" &&
269 git format-patch --no-to --to="Someone Else <else@out.there>" \
270 --stdout master..side |
271 sed -e "/^\$/q" >patch11 &&
272 check_patch patch11 &&
273 ! grep "^To: Someone <someone@out.there>\$" patch11 &&
274 grep "^To: Someone Else <else@out.there>\$" patch11
275'
276
277test_expect_success '--no-cc overrides config.cc' '
278 git config --replace-all format.cc \
279 "C E Cipient <rcipient@example.com>" &&
280 git format-patch --no-cc --stdout master..side |
281 sed -e "/^\$/q" >patch12 &&
282 check_patch patch12 &&
283 ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
284'
285
286test_expect_success '--no-add-header overrides config.headers' '
287 git config --replace-all format.headers \
288 "Header1: B E Cipient <rcipient@example.com>" &&
289 git format-patch --no-add-header --stdout master..side |
290 sed -e "/^\$/q" >patch13 &&
291 check_patch patch13 &&
292 ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
293'
294
295test_expect_success 'multiple files' '
296 rm -rf patches/ &&
297 git checkout side &&
298 git format-patch -o patches/ master &&
299 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
300'
301
302test_expect_success 'reroll count' '
303 rm -fr patches &&
304 git format-patch -o patches --cover-letter --reroll-count 4 master..side >list &&
305 ! grep -v "^patches/v4-000[0-3]-" list &&
306 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
307 ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
308'
309
310test_expect_success 'reroll count (-v)' '
311 rm -fr patches &&
312 git format-patch -o patches --cover-letter -v4 master..side >list &&
313 ! grep -v "^patches/v4-000[0-3]-" list &&
314 sed -n -e "/^Subject: /p" $(cat list) >subjects &&
315 ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
316'
317
318check_threading () {
319 expect="$1" &&
320 shift &&
321 (git format-patch --stdout "$@"; echo $? >status.out) |
322 # Prints everything between the Message-ID and In-Reply-To,
323 # and replaces all Message-ID-lookalikes by a sequence number
324 perl -ne '
325 if (/^(message-id|references|in-reply-to)/i) {
326 $printing = 1;
327 } elsif (/^\S/) {
328 $printing = 0;
329 }
330 if ($printing) {
331 $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
332 for $k (keys %h) {s/$k/$h{$k}/};
333 print;
334 }
335 print "---\n" if /^From /i;
336 ' >actual &&
337 test 0 = "$(cat status.out)" &&
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 test 5 = $(grep "^diff --git a/" output | wc -l)
799'
800
801test_expect_success 'format-patch -- <path>' '
802 git format-patch master..side -- file 2>error &&
803 ! grep "Use .--" error
804'
805
806test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
807 git format-patch --ignore-if-in-upstream HEAD
808'
809
810git_version="$(git --version | sed "s/.* //")"
811
812signature() {
813 printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
814}
815
816test_expect_success 'format-patch default signature' '
817 git format-patch --stdout -1 | tail -n 3 >output &&
818 signature >expect &&
819 test_cmp expect output
820'
821
822test_expect_success 'format-patch --signature' '
823 git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output &&
824 signature "my sig" >expect &&
825 test_cmp expect output
826'
827
828test_expect_success 'format-patch with format.signature config' '
829 git config format.signature "config sig" &&
830 git format-patch --stdout -1 >output &&
831 grep "config sig" output
832'
833
834test_expect_success 'format-patch --signature overrides format.signature' '
835 git config format.signature "config sig" &&
836 git format-patch --stdout --signature="overrides" -1 >output &&
837 ! grep "config sig" output &&
838 grep "overrides" output
839'
840
841test_expect_success 'format-patch --no-signature ignores format.signature' '
842 git config format.signature "config sig" &&
843 git format-patch --stdout --signature="my sig" --no-signature \
844 -1 >output &&
845 check_patch output &&
846 ! grep "config sig" output &&
847 ! grep "my sig" output &&
848 ! grep "^-- \$" output
849'
850
851test_expect_success 'format-patch --signature --cover-letter' '
852 git config --unset-all format.signature &&
853 git format-patch --stdout --signature="my sig" --cover-letter \
854 -1 >output &&
855 grep "my sig" output &&
856 test 2 = $(grep "my sig" output | wc -l)
857'
858
859test_expect_success 'format.signature="" suppresses signatures' '
860 git config format.signature "" &&
861 git format-patch --stdout -1 >output &&
862 check_patch output &&
863 ! grep "^-- \$" output
864'
865
866test_expect_success 'format-patch --no-signature suppresses signatures' '
867 git config --unset-all format.signature &&
868 git format-patch --stdout --no-signature -1 >output &&
869 check_patch output &&
870 ! grep "^-- \$" output
871'
872
873test_expect_success 'format-patch --signature="" suppresses signatures' '
874 git format-patch --stdout --signature="" -1 >output &&
875 check_patch output &&
876 ! grep "^-- \$" output
877'
878
879test_expect_success 'prepare mail-signature input' '
880 cat >mail-signature <<-\EOF
881
882 Test User <test.email@kernel.org>
883 http://git.kernel.org/cgit/git/git.git
884
885 git.kernel.org/?p=git/git.git;a=summary
886
887 EOF
888'
889
890test_expect_success '--signature-file=file works' '
891 git format-patch --stdout --signature-file=mail-signature -1 >output &&
892 check_patch output &&
893 sed -e "1,/^-- \$/d" <output >actual &&
894 {
895 cat mail-signature && echo
896 } >expect &&
897 test_cmp expect actual
898'
899
900test_expect_success 'format.signaturefile works' '
901 test_config format.signaturefile mail-signature &&
902 git format-patch --stdout -1 >output &&
903 check_patch output &&
904 sed -e "1,/^-- \$/d" <output >actual &&
905 {
906 cat mail-signature && echo
907 } >expect &&
908 test_cmp expect actual
909'
910
911test_expect_success '--no-signature suppresses format.signaturefile ' '
912 test_config format.signaturefile mail-signature &&
913 git format-patch --stdout --no-signature -1 >output &&
914 check_patch output &&
915 ! grep "^-- \$" output
916'
917
918test_expect_success '--signature-file overrides format.signaturefile' '
919 cat >other-mail-signature <<-\EOF &&
920 Use this other signature instead of mail-signature.
921 EOF
922 test_config format.signaturefile mail-signature &&
923 git format-patch --stdout \
924 --signature-file=other-mail-signature -1 >output &&
925 check_patch output &&
926 sed -e "1,/^-- \$/d" <output >actual &&
927 {
928 cat other-mail-signature && echo
929 } >expect &&
930 test_cmp expect actual
931'
932
933test_expect_success '--signature overrides format.signaturefile' '
934 test_config format.signaturefile mail-signature &&
935 git format-patch --stdout --signature="my sig" -1 >output &&
936 check_patch output &&
937 grep "my sig" output
938'
939
940test_expect_success TTY 'format-patch --stdout paginates' '
941 rm -f pager_used &&
942 test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
943 test_path_is_file pager_used
944'
945
946 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
947 rm -f pager_used &&
948 test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
949 test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
950 test_path_is_missing pager_used &&
951 test_path_is_missing .git/pager_used
952'
953
954test_expect_success 'format-patch handles multi-line subjects' '
955 rm -rf patches/ &&
956 echo content >>file &&
957 for i in one two three; do echo $i; done >msg &&
958 git add file &&
959 git commit -F msg &&
960 git format-patch -o patches -1 &&
961 grep ^Subject: patches/0001-one.patch >actual &&
962 echo "Subject: [PATCH] one two three" >expect &&
963 test_cmp expect actual
964'
965
966test_expect_success 'format-patch handles multi-line encoded subjects' '
967 rm -rf patches/ &&
968 echo content >>file &&
969 for i in en två tre; do echo $i; done >msg &&
970 git add file &&
971 git commit -F msg &&
972 git format-patch -o patches -1 &&
973 grep ^Subject: patches/0001-en.patch >actual &&
974 echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
975 test_cmp expect actual
976'
977
978M8="foo bar "
979M64=$M8$M8$M8$M8$M8$M8$M8$M8
980M512=$M64$M64$M64$M64$M64$M64$M64$M64
981cat >expect <<'EOF'
982Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
983 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
984 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
985 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
986 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
987 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
988 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
989EOF
990test_expect_success 'format-patch wraps extremely long subject (ascii)' '
991 echo content >>file &&
992 git add file &&
993 git commit -m "$M512" &&
994 git format-patch --stdout -1 >patch &&
995 sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
996 test_cmp expect subject
997'
998
999M8="föö bar "
1000M64=$M8$M8$M8$M8$M8$M8$M8$M8
1001M512=$M64$M64$M64$M64$M64$M64$M64$M64
1002cat >expect <<'EOF'
1003Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1004 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1005 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1006 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1007 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1008 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1009 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1010 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1011 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1012 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1013 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1014 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1015 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1016 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1017 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1018 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1019 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1020 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1021 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1022 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1023 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1024 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1025 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1026 =?UTF-8?q?bar?=
1027EOF
1028test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1029 rm -rf patches/ &&
1030 echo content >>file &&
1031 git add file &&
1032 git commit -m "$M512" &&
1033 git format-patch --stdout -1 >patch &&
1034 sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1035 test_cmp expect subject
1036'
1037
1038check_author() {
1039 echo content >>file &&
1040 git add file &&
1041 GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1042 git format-patch --stdout -1 >patch &&
1043 sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
1044 test_cmp expect actual
1045}
1046
1047cat >expect <<'EOF'
1048From: "Foo B. Bar" <author@example.com>
1049EOF
1050test_expect_success 'format-patch quotes dot in from-headers' '
1051 check_author "Foo B. Bar"
1052'
1053
1054cat >expect <<'EOF'
1055From: "Foo \"The Baz\" Bar" <author@example.com>
1056EOF
1057test_expect_success 'format-patch quotes double-quote in from-headers' '
1058 check_author "Foo \"The Baz\" Bar"
1059'
1060
1061cat >expect <<'EOF'
1062From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1063EOF
1064test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1065 check_author "Föo Bar"
1066'
1067
1068cat >expect <<'EOF'
1069From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1070EOF
1071test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1072 check_author "Föo B. Bar"
1073'
1074
1075cat >expect <<EOF
1076From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1077 <author@example.com>
1078EOF
1079test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1080 check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1081'
1082
1083cat >expect <<'EOF'
1084From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1085 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1086 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1087EOF
1088test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1089 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"
1090'
1091
1092cat >expect <<'EOF'
1093From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1094 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1095 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1096EOF
1097test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1098 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"
1099'
1100
1101cat >expect <<'EOF'
1102From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1103 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1104 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1105 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1106 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1107EOF
1108test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1109 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"
1110'
1111
1112cat >expect <<'EOF'
1113Subject: header with . in it
1114EOF
1115test_expect_success 'subject lines do not have 822 atom-quoting' '
1116 echo content >>file &&
1117 git add file &&
1118 git commit -m "header with . in it" &&
1119 git format-patch -k -1 --stdout >patch &&
1120 grep ^Subject: patch >actual &&
1121 test_cmp expect actual
1122'
1123
1124cat >expect <<'EOF'
1125Subject: [PREFIX 1/1] header with . in it
1126EOF
1127test_expect_success 'subject prefixes have space prepended' '
1128 git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1129 grep ^Subject: patch >actual &&
1130 test_cmp expect actual
1131'
1132
1133cat >expect <<'EOF'
1134Subject: [1/1] header with . in it
1135EOF
1136test_expect_success 'empty subject prefix does not have extra space' '
1137 git format-patch -n -1 --stdout --subject-prefix= >patch &&
1138 grep ^Subject: patch >actual &&
1139 test_cmp expect actual
1140'
1141
1142test_expect_success '--rfc' '
1143 cat >expect <<-\EOF &&
1144 Subject: [RFC PATCH 1/1] header with . in it
1145 EOF
1146 git format-patch -n -1 --stdout --rfc >patch &&
1147 grep ^Subject: patch >actual &&
1148 test_cmp expect actual
1149'
1150
1151test_expect_success '--from=ident notices bogus ident' '
1152 test_must_fail git format-patch -1 --stdout --from=foo >patch
1153'
1154
1155test_expect_success '--from=ident replaces author' '
1156 git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1157 cat >expect <<-\EOF &&
1158 From: Me <me@example.com>
1159
1160 From: A U Thor <author@example.com>
1161
1162 EOF
1163 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1164 test_cmp expect patch.head
1165'
1166
1167test_expect_success '--from uses committer ident' '
1168 git format-patch -1 --stdout --from >patch &&
1169 cat >expect <<-\EOF &&
1170 From: C O Mitter <committer@example.com>
1171
1172 From: A U Thor <author@example.com>
1173
1174 EOF
1175 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1176 test_cmp expect patch.head
1177'
1178
1179test_expect_success '--from omits redundant in-body header' '
1180 git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1181 cat >expect <<-\EOF &&
1182 From: A U Thor <author@example.com>
1183
1184 EOF
1185 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1186 test_cmp expect patch.head
1187'
1188
1189test_expect_success 'in-body headers trigger content encoding' '
1190 test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1191 test_when_finished "git reset --hard HEAD^" &&
1192 git format-patch -1 --stdout --from >patch &&
1193 cat >expect <<-\EOF &&
1194 From: C O Mitter <committer@example.com>
1195 Content-Type: text/plain; charset=UTF-8
1196
1197 From: éxötìc <author@example.com>
1198
1199 EOF
1200 sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
1201 test_cmp expect patch.head
1202'
1203
1204append_signoff()
1205{
1206 C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1207 git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1208 sed -n -e "1,/^---$/p" append_signoff.patch |
1209 egrep -n "^Subject|Sign|^$"
1210}
1211
1212test_expect_success 'signoff: commit with no body' '
1213 append_signoff </dev/null >actual &&
1214 cat <<-\EOF | sed "s/EOL$//" >expect &&
1215 4:Subject: [PATCH] EOL
1216 8:
1217 9:Signed-off-by: C O Mitter <committer@example.com>
1218 EOF
1219 test_cmp expect actual
1220'
1221
1222test_expect_success 'signoff: commit with only subject' '
1223 echo subject | append_signoff >actual &&
1224 cat >expect <<-\EOF &&
1225 4:Subject: [PATCH] subject
1226 8:
1227 9:Signed-off-by: C O Mitter <committer@example.com>
1228 EOF
1229 test_cmp expect actual
1230'
1231
1232test_expect_success 'signoff: commit with only subject that does not end with NL' '
1233 printf subject | append_signoff >actual &&
1234 cat >expect <<-\EOF &&
1235 4:Subject: [PATCH] subject
1236 8:
1237 9:Signed-off-by: C O Mitter <committer@example.com>
1238 EOF
1239 test_cmp expect actual
1240'
1241
1242test_expect_success 'signoff: no existing signoffs' '
1243 append_signoff <<-\EOF >actual &&
1244 subject
1245
1246 body
1247 EOF
1248 cat >expect <<-\EOF &&
1249 4:Subject: [PATCH] subject
1250 8:
1251 10:
1252 11:Signed-off-by: C O Mitter <committer@example.com>
1253 EOF
1254 test_cmp expect actual
1255'
1256
1257test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1258 printf "subject\n\nbody" | append_signoff >actual &&
1259 cat >expect <<-\EOF &&
1260 4:Subject: [PATCH] subject
1261 8:
1262 10:
1263 11:Signed-off-by: C O Mitter <committer@example.com>
1264 EOF
1265 test_cmp expect actual
1266'
1267
1268test_expect_success 'signoff: some random signoff' '
1269 append_signoff <<-\EOF >actual &&
1270 subject
1271
1272 body
1273
1274 Signed-off-by: my@house
1275 EOF
1276 cat >expect <<-\EOF &&
1277 4:Subject: [PATCH] subject
1278 8:
1279 10:
1280 11:Signed-off-by: my@house
1281 12:Signed-off-by: C O Mitter <committer@example.com>
1282 EOF
1283 test_cmp expect actual
1284'
1285
1286test_expect_success 'signoff: misc conforming footer elements' '
1287 append_signoff <<-\EOF >actual &&
1288 subject
1289
1290 body
1291
1292 Signed-off-by: my@house
1293 (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1294 Tested-by: Some One <someone@example.com>
1295 Bug: 1234
1296 EOF
1297 cat >expect <<-\EOF &&
1298 4:Subject: [PATCH] subject
1299 8:
1300 10:
1301 11:Signed-off-by: my@house
1302 15:Signed-off-by: C O Mitter <committer@example.com>
1303 EOF
1304 test_cmp expect actual
1305'
1306
1307test_expect_success 'signoff: some random signoff-alike' '
1308 append_signoff <<-\EOF >actual &&
1309 subject
1310
1311 body
1312 Fooled-by-me: my@house
1313 EOF
1314 cat >expect <<-\EOF &&
1315 4:Subject: [PATCH] subject
1316 8:
1317 11:
1318 12:Signed-off-by: C O Mitter <committer@example.com>
1319 EOF
1320 test_cmp expect actual
1321'
1322
1323test_expect_success 'signoff: not really a signoff' '
1324 append_signoff <<-\EOF >actual &&
1325 subject
1326
1327 I want to mention about Signed-off-by: here.
1328 EOF
1329 cat >expect <<-\EOF &&
1330 4:Subject: [PATCH] subject
1331 8:
1332 9:I want to mention about Signed-off-by: here.
1333 10:
1334 11:Signed-off-by: C O Mitter <committer@example.com>
1335 EOF
1336 test_cmp expect actual
1337'
1338
1339test_expect_success 'signoff: not really a signoff (2)' '
1340 append_signoff <<-\EOF >actual &&
1341 subject
1342
1343 My unfortunate
1344 Signed-off-by: example happens to be wrapped here.
1345 EOF
1346 cat >expect <<-\EOF &&
1347 4:Subject: [PATCH] subject
1348 8:
1349 10:Signed-off-by: example happens to be wrapped here.
1350 11:Signed-off-by: C O Mitter <committer@example.com>
1351 EOF
1352 test_cmp expect actual
1353'
1354
1355test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1356 append_signoff <<-\EOF >actual &&
1357 subject
1358
1359 Signed-off-by: my@house
1360 Signed-off-by: your@house
1361
1362 A lot of houses.
1363 EOF
1364 cat >expect <<-\EOF &&
1365 4:Subject: [PATCH] subject
1366 8:
1367 9:Signed-off-by: my@house
1368 10:Signed-off-by: your@house
1369 11:
1370 13:
1371 14:Signed-off-by: C O Mitter <committer@example.com>
1372 EOF
1373 test_cmp expect actual
1374'
1375
1376test_expect_success 'signoff: the same signoff at the end' '
1377 append_signoff <<-\EOF >actual &&
1378 subject
1379
1380 body
1381
1382 Signed-off-by: C O Mitter <committer@example.com>
1383 EOF
1384 cat >expect <<-\EOF &&
1385 4:Subject: [PATCH] subject
1386 8:
1387 10:
1388 11:Signed-off-by: C O Mitter <committer@example.com>
1389 EOF
1390 test_cmp expect actual
1391'
1392
1393test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1394 printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1395 append_signoff >actual &&
1396 cat >expect <<-\EOF &&
1397 4:Subject: [PATCH] subject
1398 8:
1399 9:Signed-off-by: C O Mitter <committer@example.com>
1400 EOF
1401 test_cmp expect actual
1402'
1403
1404test_expect_success 'signoff: the same signoff NOT at the end' '
1405 append_signoff <<-\EOF >actual &&
1406 subject
1407
1408 body
1409
1410 Signed-off-by: C O Mitter <committer@example.com>
1411 Signed-off-by: my@house
1412 EOF
1413 cat >expect <<-\EOF &&
1414 4:Subject: [PATCH] subject
1415 8:
1416 10:
1417 11:Signed-off-by: C O Mitter <committer@example.com>
1418 12:Signed-off-by: my@house
1419 EOF
1420 test_cmp expect actual
1421'
1422
1423test_expect_success 'signoff: tolerate garbage in conforming footer' '
1424 append_signoff <<-\EOF >actual &&
1425 subject
1426
1427 body
1428
1429 Tested-by: my@house
1430 Some Trash
1431 Signed-off-by: C O Mitter <committer@example.com>
1432 EOF
1433 cat >expect <<-\EOF &&
1434 4:Subject: [PATCH] subject
1435 8:
1436 10:
1437 13:Signed-off-by: C O Mitter <committer@example.com>
1438 EOF
1439 test_cmp expect actual
1440'
1441
1442test_expect_success 'signoff: respect trailer config' '
1443 append_signoff <<-\EOF >actual &&
1444 subject
1445
1446 Myfooter: x
1447 Some Trash
1448 EOF
1449 cat >expect <<-\EOF &&
1450 4:Subject: [PATCH] subject
1451 8:
1452 11:
1453 12:Signed-off-by: C O Mitter <committer@example.com>
1454 EOF
1455 test_cmp expect actual &&
1456
1457 test_config trailer.Myfooter.ifexists add &&
1458 append_signoff <<-\EOF >actual &&
1459 subject
1460
1461 Myfooter: x
1462 Some Trash
1463 EOF
1464 cat >expect <<-\EOF &&
1465 4:Subject: [PATCH] subject
1466 8:
1467 11:Signed-off-by: C O Mitter <committer@example.com>
1468 EOF
1469 test_cmp expect actual
1470'
1471
1472test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1473 append_signoff <<-\EOF >actual &&
1474 subject
1475
1476 body
1477
1478 Reviewed-id: Noone
1479 Tested-by: my@house
1480 Change-id: Ideadbeef
1481 Signed-off-by: C O Mitter <committer@example.com>
1482 Bug: 1234
1483 EOF
1484 cat >expect <<-\EOF &&
1485 4:Subject: [PATCH] subject
1486 8:
1487 10:
1488 14:Signed-off-by: C O Mitter <committer@example.com>
1489 EOF
1490 test_cmp expect actual
1491'
1492
1493test_expect_success 'format patch ignores color.ui' '
1494 test_unconfig color.ui &&
1495 git format-patch --stdout -1 >expect &&
1496 test_config color.ui always &&
1497 git format-patch --stdout -1 >actual &&
1498 test_cmp expect actual
1499'
1500
1501test_expect_success 'cover letter using branch description (1)' '
1502 git checkout rebuild-1 &&
1503 test_config branch.rebuild-1.description hello &&
1504 git format-patch --stdout --cover-letter master >actual &&
1505 grep hello actual >/dev/null
1506'
1507
1508test_expect_success 'cover letter using branch description (2)' '
1509 git checkout rebuild-1 &&
1510 test_config branch.rebuild-1.description hello &&
1511 git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1512 grep hello actual >/dev/null
1513'
1514
1515test_expect_success 'cover letter using branch description (3)' '
1516 git checkout rebuild-1 &&
1517 test_config branch.rebuild-1.description hello &&
1518 git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
1519 grep hello actual >/dev/null
1520'
1521
1522test_expect_success 'cover letter using branch description (4)' '
1523 git checkout rebuild-1 &&
1524 test_config branch.rebuild-1.description hello &&
1525 git format-patch --stdout --cover-letter master.. >actual &&
1526 grep hello actual >/dev/null
1527'
1528
1529test_expect_success 'cover letter using branch description (5)' '
1530 git checkout rebuild-1 &&
1531 test_config branch.rebuild-1.description hello &&
1532 git format-patch --stdout --cover-letter -2 HEAD >actual &&
1533 grep hello actual >/dev/null
1534'
1535
1536test_expect_success 'cover letter using branch description (6)' '
1537 git checkout rebuild-1 &&
1538 test_config branch.rebuild-1.description hello &&
1539 git format-patch --stdout --cover-letter -2 >actual &&
1540 grep hello actual >/dev/null
1541'
1542
1543test_expect_success 'cover letter with nothing' '
1544 git format-patch --stdout --cover-letter >actual &&
1545 test_line_count = 0 actual
1546'
1547
1548test_expect_success 'cover letter auto' '
1549 mkdir -p tmp &&
1550 test_when_finished "rm -rf tmp;
1551 git config --unset format.coverletter" &&
1552
1553 git config format.coverletter auto &&
1554 git format-patch -o tmp -1 >list &&
1555 test_line_count = 1 list &&
1556 git format-patch -o tmp -2 >list &&
1557 test_line_count = 3 list
1558'
1559
1560test_expect_success 'cover letter auto user override' '
1561 mkdir -p tmp &&
1562 test_when_finished "rm -rf tmp;
1563 git config --unset format.coverletter" &&
1564
1565 git config format.coverletter auto &&
1566 git format-patch -o tmp --cover-letter -1 >list &&
1567 test_line_count = 2 list &&
1568 git format-patch -o tmp --cover-letter -2 >list &&
1569 test_line_count = 3 list &&
1570 git format-patch -o tmp --no-cover-letter -1 >list &&
1571 test_line_count = 1 list &&
1572 git format-patch -o tmp --no-cover-letter -2 >list &&
1573 test_line_count = 2 list
1574'
1575
1576test_expect_success 'format-patch --zero-commit' '
1577 git format-patch --zero-commit --stdout v2..v1 >patch2 &&
1578 grep "^From " patch2 | sort | uniq >actual &&
1579 echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
1580 test_cmp expect actual
1581'
1582
1583test_expect_success 'From line has expected format' '
1584 git format-patch --stdout v2..v1 >patch2 &&
1585 grep "^From " patch2 >from &&
1586 grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
1587 test_cmp from filtered
1588'
1589
1590test_expect_success 'format-patch format.outputDirectory option' '
1591 test_config format.outputDirectory patches &&
1592 rm -fr patches &&
1593 git format-patch master..side &&
1594 test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l)
1595'
1596
1597test_expect_success 'format-patch -o overrides format.outputDirectory' '
1598 test_config format.outputDirectory patches &&
1599 rm -fr patches patchset &&
1600 git format-patch master..side -o patchset &&
1601 test_path_is_missing patches &&
1602 test_path_is_dir patchset
1603'
1604
1605test_expect_success 'format-patch --base' '
1606 git checkout patchid &&
1607 git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
1608 git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
1609 echo >expect &&
1610 echo "base-commit: $(git rev-parse HEAD~3)" >>expect &&
1611 echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1612 echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1613 signature >>expect &&
1614 test_cmp expect actual1 &&
1615 test_cmp expect actual2 &&
1616 echo >fail &&
1617 echo "base-commit: $(git rev-parse HEAD~3)" >>fail &&
1618 echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1619 echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1620 signature >>fail &&
1621 ! test_cmp fail actual1 &&
1622 ! test_cmp fail actual2
1623'
1624
1625test_expect_success 'format-patch --base errors out when base commit is in revision list' '
1626 test_must_fail git format-patch --base=HEAD -2 &&
1627 test_must_fail git format-patch --base=HEAD~1 -2 &&
1628 git format-patch --stdout --base=HEAD~2 -2 >patch &&
1629 grep "^base-commit:" patch >actual &&
1630 echo "base-commit: $(git rev-parse HEAD~2)" >expect &&
1631 test_cmp expect actual
1632'
1633
1634test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
1635 # For history as below:
1636 #
1637 # ---Q---P---Z---Y---*---X
1638 # \ /
1639 # ------------W
1640 #
1641 # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
1642 git checkout -b topic1 master &&
1643 git rev-parse HEAD >commit-id-base &&
1644 test_commit P &&
1645 git rev-parse HEAD >commit-id-P &&
1646 test_commit Z &&
1647 git rev-parse HEAD >commit-id-Z &&
1648 test_commit Y &&
1649 git checkout -b topic2 master &&
1650 test_commit W &&
1651 git merge topic1 &&
1652 test_commit X &&
1653 test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
1654 test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
1655 git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
1656 grep "^base-commit:" patch >actual &&
1657 echo "base-commit: $(cat commit-id-base)" >expect &&
1658 test_cmp expect actual
1659'
1660
1661test_expect_success 'format-patch --base=auto' '
1662 git checkout -b upstream master &&
1663 git checkout -b local upstream &&
1664 git branch --set-upstream-to=upstream &&
1665 test_commit N1 &&
1666 test_commit N2 &&
1667 git format-patch --stdout --base=auto -2 >patch &&
1668 grep "^base-commit:" patch >actual &&
1669 echo "base-commit: $(git rev-parse upstream)" >expect &&
1670 test_cmp expect actual
1671'
1672
1673test_expect_success 'format-patch errors out when history involves criss-cross' '
1674 # setup criss-cross history
1675 #
1676 # B---M1---D
1677 # / \ /
1678 # A X
1679 # \ / \
1680 # C---M2---E
1681 #
1682 git checkout master &&
1683 test_commit A &&
1684 git checkout -b xb master &&
1685 test_commit B &&
1686 git checkout -b xc master &&
1687 test_commit C &&
1688 git checkout -b xbc xb -- &&
1689 git merge xc &&
1690 git checkout -b xcb xc -- &&
1691 git branch --set-upstream-to=xbc &&
1692 git merge xb &&
1693 git checkout xbc &&
1694 test_commit D &&
1695 git checkout xcb &&
1696 test_commit E &&
1697 test_must_fail git format-patch --base=auto -1
1698'
1699
1700test_expect_success 'format-patch format.useAutoBaseoption' '
1701 test_when_finished "git config --unset format.useAutoBase" &&
1702 git checkout local &&
1703 git config format.useAutoBase true &&
1704 git format-patch --stdout -1 >patch &&
1705 grep "^base-commit:" patch >actual &&
1706 echo "base-commit: $(git rev-parse upstream)" >expect &&
1707 test_cmp expect actual
1708'
1709
1710test_expect_success 'format-patch --base overrides format.useAutoBase' '
1711 test_when_finished "git config --unset format.useAutoBase" &&
1712 git config format.useAutoBase true &&
1713 git format-patch --stdout --base=HEAD~1 -1 >patch &&
1714 grep "^base-commit:" patch >actual &&
1715 echo "base-commit: $(git rev-parse HEAD~1)" >expect &&
1716 test_cmp expect actual
1717'
1718
1719test_expect_success 'format-patch --base with --attach' '
1720 git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
1721 sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
1722 patch >actual &&
1723 test_write_lines 1 2 >expect &&
1724 test_cmp expect actual
1725'
1726test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
1727 test_when_finished "rm -fr patches" &&
1728 git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
1729 ! egrep "^--+mimemime" patches/0000*.patch &&
1730 egrep "^--+mimemime$" patches/0001*.patch >output &&
1731 test_line_count = 2 output &&
1732 egrep "^--+mimemime--$" patches/0001*.patch >output &&
1733 test_line_count = 1 output
1734'
1735
1736test_expect_success 'format-patch --pretty=mboxrd' '
1737 sp=" " &&
1738 cat >msg <<-INPUT_END &&
1739 mboxrd should escape the body
1740
1741 From could trip up a loose mbox parser
1742 >From extra escape for reversibility
1743 >>From extra escape for reversibility 2
1744 from lower case not escaped
1745 Fromm bad speling not escaped
1746 From with leading space not escaped
1747
1748 F
1749 From
1750 From$sp
1751 From $sp
1752 From $sp
1753 INPUT_END
1754
1755 cat >expect <<-INPUT_END &&
1756 >From could trip up a loose mbox parser
1757 >>From extra escape for reversibility
1758 >>>From extra escape for reversibility 2
1759 from lower case not escaped
1760 Fromm bad speling not escaped
1761 From with leading space not escaped
1762
1763 F
1764 From
1765 From
1766 From
1767 From
1768 INPUT_END
1769
1770 C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
1771 git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
1772 git grep -h --no-index -A11 \
1773 "^>From could trip up a loose mbox parser" patch >actual &&
1774 test_cmp expect actual
1775'
1776
1777test_expect_success 'interdiff: setup' '
1778 git checkout -b boop master &&
1779 test_commit fnorp blorp &&
1780 test_commit fleep blorp
1781'
1782
1783test_expect_success 'interdiff: cover-letter' '
1784 sed "y/q/ /" >expect <<-\EOF &&
1785 +fleep
1786 --q
1787 EOF
1788 git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1789 test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1790 test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
1791 sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1792 test_cmp expect actual
1793'
1794
1795test_expect_success 'interdiff: reroll-count' '
1796 git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
1797 test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
1798'
1799
1800test_expect_success 'interdiff: solo-patch' '
1801 cat >expect <<-\EOF &&
1802 +fleep
1803
1804 EOF
1805 git format-patch --interdiff=boop~2 -1 boop &&
1806 test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
1807 sed "1,/^ @@ /d; /^$/q" <0001-fleep.patch >actual &&
1808 test_cmp expect actual
1809'
1810
1811test_done