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