3ed3feabfec1aad6547713f0f5928f0462b280b2
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
795test_expect_success 'format-patch --numstat should produce a patch' '
796 git format-patch --numstat --stdout master..side > output &&
797 test 5 = $(grep "^diff --git a/" output | wc -l)'
798
799test_expect_success 'format-patch -- <path>' '
800 git format-patch master..side -- file 2>error &&
801 ! grep "Use .--" error
802'
803
804test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
805 git format-patch --ignore-if-in-upstream HEAD
806'
807
808git_version="$(git --version | sed "s/.* //")"
809
810signature() {
811 printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
812}
813
814test_expect_success 'format-patch default signature' '
815 git format-patch --stdout -1 | tail -n 3 >output &&
816 signature >expect &&
817 test_cmp expect output
818'
819
820test_expect_success 'format-patch --signature' '
821 git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output &&
822 signature "my sig" >expect &&
823 test_cmp expect output
824'
825
826test_expect_success 'format-patch with format.signature config' '
827 git config format.signature "config sig" &&
828 git format-patch --stdout -1 >output &&
829 grep "config sig" output
830'
831
832test_expect_success 'format-patch --signature overrides format.signature' '
833 git config format.signature "config sig" &&
834 git format-patch --stdout --signature="overrides" -1 >output &&
835 ! grep "config sig" output &&
836 grep "overrides" output
837'
838
839test_expect_success 'format-patch --no-signature ignores format.signature' '
840 git config format.signature "config sig" &&
841 git format-patch --stdout --signature="my sig" --no-signature \
842 -1 >output &&
843 check_patch output &&
844 ! grep "config sig" output &&
845 ! grep "my sig" output &&
846 ! grep "^-- \$" output
847'
848
849test_expect_success 'format-patch --signature --cover-letter' '
850 git config --unset-all format.signature &&
851 git format-patch --stdout --signature="my sig" --cover-letter \
852 -1 >output &&
853 grep "my sig" output &&
854 test 2 = $(grep "my sig" output | wc -l)
855'
856
857test_expect_success 'format.signature="" suppresses signatures' '
858 git config format.signature "" &&
859 git format-patch --stdout -1 >output &&
860 check_patch output &&
861 ! grep "^-- \$" output
862'
863
864test_expect_success 'format-patch --no-signature suppresses signatures' '
865 git config --unset-all format.signature &&
866 git format-patch --stdout --no-signature -1 >output &&
867 check_patch output &&
868 ! grep "^-- \$" output
869'
870
871test_expect_success 'format-patch --signature="" suppresses signatures' '
872 git format-patch --stdout --signature="" -1 >output &&
873 check_patch output &&
874 ! grep "^-- \$" output
875'
876
877test_expect_success 'prepare mail-signature input' '
878 cat >mail-signature <<-\EOF
879
880 Test User <test.email@kernel.org>
881 http://git.kernel.org/cgit/git/git.git
882
883 git.kernel.org/?p=git/git.git;a=summary
884
885 EOF
886'
887
888test_expect_success '--signature-file=file works' '
889 git format-patch --stdout --signature-file=mail-signature -1 >output &&
890 check_patch output &&
891 sed -e "1,/^-- \$/d" <output >actual &&
892 {
893 cat mail-signature && echo
894 } >expect &&
895 test_cmp expect actual
896'
897
898test_expect_success 'format.signaturefile works' '
899 test_config format.signaturefile mail-signature &&
900 git format-patch --stdout -1 >output &&
901 check_patch output &&
902 sed -e "1,/^-- \$/d" <output >actual &&
903 {
904 cat mail-signature && echo
905 } >expect &&
906 test_cmp expect actual
907'
908
909test_expect_success '--no-signature suppresses format.signaturefile ' '
910 test_config format.signaturefile mail-signature &&
911 git format-patch --stdout --no-signature -1 >output &&
912 check_patch output &&
913 ! grep "^-- \$" output
914'
915
916test_expect_success '--signature-file overrides format.signaturefile' '
917 cat >other-mail-signature <<-\EOF &&
918 Use this other signature instead of mail-signature.
919 EOF
920 test_config format.signaturefile mail-signature &&
921 git format-patch --stdout \
922 --signature-file=other-mail-signature -1 >output &&
923 check_patch output &&
924 sed -e "1,/^-- \$/d" <output >actual &&
925 {
926 cat other-mail-signature && echo
927 } >expect &&
928 test_cmp expect actual
929'
930
931test_expect_success '--signature overrides format.signaturefile' '
932 test_config format.signaturefile mail-signature &&
933 git format-patch --stdout --signature="my sig" -1 >output &&
934 check_patch output &&
935 grep "my sig" output
936'
937
938test_expect_success TTY 'format-patch --stdout paginates' '
939 rm -f pager_used &&
940 test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
941 test_path_is_file pager_used
942'
943
944 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
945 rm -f pager_used &&
946 test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
947 test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
948 test_path_is_missing pager_used &&
949 test_path_is_missing .git/pager_used
950'
951
952test_expect_success 'format-patch handles multi-line subjects' '
953 rm -rf patches/ &&
954 echo content >>file &&
955 for i in one two three; do echo $i; done >msg &&
956 git add file &&
957 git commit -F msg &&
958 git format-patch -o patches -1 &&
959 grep ^Subject: patches/0001-one.patch >actual &&
960 echo "Subject: [PATCH] one two three" >expect &&
961 test_cmp expect actual
962'
963
964test_expect_success 'format-patch handles multi-line encoded subjects' '
965 rm -rf patches/ &&
966 echo content >>file &&
967 for i in en två tre; do echo $i; done >msg &&
968 git add file &&
969 git commit -F msg &&
970 git format-patch -o patches -1 &&
971 grep ^Subject: patches/0001-en.patch >actual &&
972 echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
973 test_cmp expect actual
974'
975
976M8="foo bar "
977M64=$M8$M8$M8$M8$M8$M8$M8$M8
978M512=$M64$M64$M64$M64$M64$M64$M64$M64
979cat >expect <<'EOF'
980Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
981 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
982 foo bar foo bar 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
987EOF
988test_expect_success 'format-patch wraps extremely long subject (ascii)' '
989 echo content >>file &&
990 git add file &&
991 git commit -m "$M512" &&
992 git format-patch --stdout -1 >patch &&
993 sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
994 test_cmp expect subject
995'
996
997M8="föö bar "
998M64=$M8$M8$M8$M8$M8$M8$M8$M8
999M512=$M64$M64$M64$M64$M64$M64$M64$M64
1000cat >expect <<'EOF'
1001Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1002 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1003 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1004 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1005 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1006 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1007 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1008 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1009 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1010 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1011 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1012 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1013 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1014 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1015 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1016 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1017 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1018 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1019 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1020 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1021 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1022 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1023 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1024 =?UTF-8?q?bar?=
1025EOF
1026test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1027 rm -rf patches/ &&
1028 echo content >>file &&
1029 git add file &&
1030 git commit -m "$M512" &&
1031 git format-patch --stdout -1 >patch &&
1032 sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1033 test_cmp expect subject
1034'
1035
1036check_author() {
1037 echo content >>file &&
1038 git add file &&
1039 GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1040 git format-patch --stdout -1 >patch &&
1041 sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
1042 test_cmp expect actual
1043}
1044
1045cat >expect <<'EOF'
1046From: "Foo B. Bar" <author@example.com>
1047EOF
1048test_expect_success 'format-patch quotes dot in from-headers' '
1049 check_author "Foo B. Bar"
1050'
1051
1052cat >expect <<'EOF'
1053From: "Foo \"The Baz\" Bar" <author@example.com>
1054EOF
1055test_expect_success 'format-patch quotes double-quote in from-headers' '
1056 check_author "Foo \"The Baz\" Bar"
1057'
1058
1059cat >expect <<'EOF'
1060From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1061EOF
1062test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1063 check_author "Föo Bar"
1064'
1065
1066cat >expect <<'EOF'
1067From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1068EOF
1069test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1070 check_author "Föo B. Bar"
1071'
1072
1073cat >expect <<EOF
1074From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1075 <author@example.com>
1076EOF
1077test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1078 check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1079'
1080
1081cat >expect <<'EOF'
1082From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1083 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1084 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1085EOF
1086test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1087 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"
1088'
1089
1090cat >expect <<'EOF'
1091From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1092 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1093 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1094EOF
1095test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1096 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"
1097'
1098
1099cat >expect <<'EOF'
1100From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1101 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1102 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1103 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1104 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1105EOF
1106test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1107 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"
1108'
1109
1110cat >expect <<'EOF'
1111Subject: header with . in it
1112EOF
1113test_expect_success 'subject lines do not have 822 atom-quoting' '
1114 echo content >>file &&
1115 git add file &&
1116 git commit -m "header with . in it" &&
1117 git format-patch -k -1 --stdout >patch &&
1118 grep ^Subject: patch >actual &&
1119 test_cmp expect actual
1120'
1121
1122cat >expect <<'EOF'
1123Subject: [PREFIX 1/1] header with . in it
1124EOF
1125test_expect_success 'subject prefixes have space prepended' '
1126 git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1127 grep ^Subject: patch >actual &&
1128 test_cmp expect actual
1129'
1130
1131cat >expect <<'EOF'
1132Subject: [1/1] header with . in it
1133EOF
1134test_expect_success 'empty subject prefix does not have extra space' '
1135 git format-patch -n -1 --stdout --subject-prefix= >patch &&
1136 grep ^Subject: patch >actual &&
1137 test_cmp expect actual
1138'
1139
1140test_expect_success '--rfc' '
1141 cat >expect <<-\EOF &&
1142 Subject: [RFC PATCH 1/1] header with . in it
1143 EOF
1144 git format-patch -n -1 --stdout --rfc >patch &&
1145 grep ^Subject: patch >actual &&
1146 test_cmp expect actual
1147'
1148
1149test_expect_success '--from=ident notices bogus ident' '
1150 test_must_fail git format-patch -1 --stdout --from=foo >patch
1151'
1152
1153test_expect_success '--from=ident replaces author' '
1154 git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1155 cat >expect <<-\EOF &&
1156 From: Me <me@example.com>
1157
1158 From: A U Thor <author@example.com>
1159
1160 EOF
1161 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1162 test_cmp expect patch.head
1163'
1164
1165test_expect_success '--from uses committer ident' '
1166 git format-patch -1 --stdout --from >patch &&
1167 cat >expect <<-\EOF &&
1168 From: C O Mitter <committer@example.com>
1169
1170 From: A U Thor <author@example.com>
1171
1172 EOF
1173 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1174 test_cmp expect patch.head
1175'
1176
1177test_expect_success '--from omits redundant in-body header' '
1178 git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1179 cat >expect <<-\EOF &&
1180 From: A U Thor <author@example.com>
1181
1182 EOF
1183 sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1184 test_cmp expect patch.head
1185'
1186
1187test_expect_success 'in-body headers trigger content encoding' '
1188 test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1189 test_when_finished "git reset --hard HEAD^" &&
1190 git format-patch -1 --stdout --from >patch &&
1191 cat >expect <<-\EOF &&
1192 From: C O Mitter <committer@example.com>
1193 Content-Type: text/plain; charset=UTF-8
1194
1195 From: éxötìc <author@example.com>
1196
1197 EOF
1198 sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
1199 test_cmp expect patch.head
1200'
1201
1202append_signoff()
1203{
1204 C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1205 git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1206 sed -n -e "1,/^---$/p" append_signoff.patch |
1207 egrep -n "^Subject|Sign|^$"
1208}
1209
1210test_expect_success 'signoff: commit with no body' '
1211 append_signoff </dev/null >actual &&
1212 cat <<\EOF | sed "s/EOL$//" >expected &&
12134:Subject: [PATCH] EOL
12148:
12159:Signed-off-by: C O Mitter <committer@example.com>
1216EOF
1217 test_cmp expected actual
1218'
1219
1220test_expect_success 'signoff: commit with only subject' '
1221 echo subject | append_signoff >actual &&
1222 cat >expected <<\EOF &&
12234:Subject: [PATCH] subject
12248:
12259:Signed-off-by: C O Mitter <committer@example.com>
1226EOF
1227 test_cmp expected actual
1228'
1229
1230test_expect_success 'signoff: commit with only subject that does not end with NL' '
1231 printf subject | append_signoff >actual &&
1232 cat >expected <<\EOF &&
12334:Subject: [PATCH] subject
12348:
12359:Signed-off-by: C O Mitter <committer@example.com>
1236EOF
1237 test_cmp expected actual
1238'
1239
1240test_expect_success 'signoff: no existing signoffs' '
1241 append_signoff <<\EOF >actual &&
1242subject
1243
1244body
1245EOF
1246 cat >expected <<\EOF &&
12474:Subject: [PATCH] subject
12488:
124910:
125011:Signed-off-by: C O Mitter <committer@example.com>
1251EOF
1252 test_cmp expected actual
1253'
1254
1255test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1256 printf "subject\n\nbody" | append_signoff >actual &&
1257 cat >expected <<\EOF &&
12584:Subject: [PATCH] subject
12598:
126010:
126111:Signed-off-by: C O Mitter <committer@example.com>
1262EOF
1263 test_cmp expected actual
1264'
1265
1266test_expect_success 'signoff: some random signoff' '
1267 append_signoff <<\EOF >actual &&
1268subject
1269
1270body
1271
1272Signed-off-by: my@house
1273EOF
1274 cat >expected <<\EOF &&
12754:Subject: [PATCH] subject
12768:
127710:
127811:Signed-off-by: my@house
127912:Signed-off-by: C O Mitter <committer@example.com>
1280EOF
1281 test_cmp expected actual
1282'
1283
1284test_expect_success 'signoff: misc conforming footer elements' '
1285 append_signoff <<\EOF >actual &&
1286subject
1287
1288body
1289
1290Signed-off-by: my@house
1291(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1292Tested-by: Some One <someone@example.com>
1293Bug: 1234
1294EOF
1295 cat >expected <<\EOF &&
12964:Subject: [PATCH] subject
12978:
129810:
129911:Signed-off-by: my@house
130015:Signed-off-by: C O Mitter <committer@example.com>
1301EOF
1302 test_cmp expected actual
1303'
1304
1305test_expect_success 'signoff: some random signoff-alike' '
1306 append_signoff <<\EOF >actual &&
1307subject
1308
1309body
1310Fooled-by-me: my@house
1311EOF
1312 cat >expected <<\EOF &&
13134:Subject: [PATCH] subject
13148:
131511:
131612:Signed-off-by: C O Mitter <committer@example.com>
1317EOF
1318 test_cmp expected actual
1319'
1320
1321test_expect_success 'signoff: not really a signoff' '
1322 append_signoff <<\EOF >actual &&
1323subject
1324
1325I want to mention about Signed-off-by: here.
1326EOF
1327 cat >expected <<\EOF &&
13284:Subject: [PATCH] subject
13298:
13309:I want to mention about Signed-off-by: here.
133110:
133211:Signed-off-by: C O Mitter <committer@example.com>
1333EOF
1334 test_cmp expected actual
1335'
1336
1337test_expect_success 'signoff: not really a signoff (2)' '
1338 append_signoff <<\EOF >actual &&
1339subject
1340
1341My unfortunate
1342Signed-off-by: example happens to be wrapped here.
1343EOF
1344 cat >expected <<\EOF &&
13454:Subject: [PATCH] subject
13468:
134710:Signed-off-by: example happens to be wrapped here.
134811:Signed-off-by: C O Mitter <committer@example.com>
1349EOF
1350 test_cmp expected actual
1351'
1352
1353test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1354 append_signoff <<\EOF >actual &&
1355subject
1356
1357Signed-off-by: my@house
1358Signed-off-by: your@house
1359
1360A lot of houses.
1361EOF
1362 cat >expected <<\EOF &&
13634:Subject: [PATCH] subject
13648:
13659:Signed-off-by: my@house
136610:Signed-off-by: your@house
136711:
136813:
136914:Signed-off-by: C O Mitter <committer@example.com>
1370EOF
1371 test_cmp expected actual
1372'
1373
1374test_expect_success 'signoff: the same signoff at the end' '
1375 append_signoff <<\EOF >actual &&
1376subject
1377
1378body
1379
1380Signed-off-by: C O Mitter <committer@example.com>
1381EOF
1382 cat >expected <<\EOF &&
13834:Subject: [PATCH] subject
13848:
138510:
138611:Signed-off-by: C O Mitter <committer@example.com>
1387EOF
1388 test_cmp expected actual
1389'
1390
1391test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1392 printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1393 append_signoff >actual &&
1394 cat >expected <<\EOF &&
13954:Subject: [PATCH] subject
13968:
13979:Signed-off-by: C O Mitter <committer@example.com>
1398EOF
1399 test_cmp expected actual
1400'
1401
1402test_expect_success 'signoff: the same signoff NOT at the end' '
1403 append_signoff <<\EOF >actual &&
1404subject
1405
1406body
1407
1408Signed-off-by: C O Mitter <committer@example.com>
1409Signed-off-by: my@house
1410EOF
1411 cat >expected <<\EOF &&
14124:Subject: [PATCH] subject
14138:
141410:
141511:Signed-off-by: C O Mitter <committer@example.com>
141612:Signed-off-by: my@house
1417EOF
1418 test_cmp expected actual
1419'
1420
1421test_expect_success 'signoff: tolerate garbage in conforming footer' '
1422 append_signoff <<\EOF >actual &&
1423subject
1424
1425body
1426
1427Tested-by: my@house
1428Some Trash
1429Signed-off-by: C O Mitter <committer@example.com>
1430EOF
1431 cat >expected <<\EOF &&
14324:Subject: [PATCH] subject
14338:
143410:
143513:Signed-off-by: C O Mitter <committer@example.com>
1436EOF
1437 test_cmp expected actual
1438'
1439
1440test_expect_success 'signoff: respect trailer config' '
1441 append_signoff <<\EOF >actual &&
1442subject
1443
1444Myfooter: x
1445Some Trash
1446EOF
1447 cat >expected <<\EOF &&
14484:Subject: [PATCH] subject
14498:
145011:
145112:Signed-off-by: C O Mitter <committer@example.com>
1452EOF
1453 test_cmp expected actual &&
1454
1455 test_config trailer.Myfooter.ifexists add &&
1456 append_signoff <<\EOF >actual &&
1457subject
1458
1459Myfooter: x
1460Some Trash
1461EOF
1462 cat >expected <<\EOF &&
14634:Subject: [PATCH] subject
14648:
146511:Signed-off-by: C O Mitter <committer@example.com>
1466EOF
1467 test_cmp expected actual
1468'
1469
1470test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1471 append_signoff <<\EOF >actual &&
1472subject
1473
1474body
1475
1476Reviewed-id: Noone
1477Tested-by: my@house
1478Change-id: Ideadbeef
1479Signed-off-by: C O Mitter <committer@example.com>
1480Bug: 1234
1481EOF
1482 cat >expected <<\EOF &&
14834:Subject: [PATCH] subject
14848:
148510:
148614:Signed-off-by: C O Mitter <committer@example.com>
1487EOF
1488 test_cmp expected actual
1489'
1490
1491test_expect_success 'format patch ignores color.ui' '
1492 test_unconfig color.ui &&
1493 git format-patch --stdout -1 >expect &&
1494 test_config color.ui always &&
1495 git format-patch --stdout -1 >actual &&
1496 test_cmp expect actual
1497'
1498
1499test_expect_success 'cover letter using branch description (1)' '
1500 git checkout rebuild-1 &&
1501 test_config branch.rebuild-1.description hello &&
1502 git format-patch --stdout --cover-letter master >actual &&
1503 grep hello actual >/dev/null
1504'
1505
1506test_expect_success 'cover letter using branch description (2)' '
1507 git checkout rebuild-1 &&
1508 test_config branch.rebuild-1.description hello &&
1509 git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1510 grep hello actual >/dev/null
1511'
1512
1513test_expect_success 'cover letter using branch description (3)' '
1514 git checkout rebuild-1 &&
1515 test_config branch.rebuild-1.description hello &&
1516 git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
1517 grep hello actual >/dev/null
1518'
1519
1520test_expect_success 'cover letter using branch description (4)' '
1521 git checkout rebuild-1 &&
1522 test_config branch.rebuild-1.description hello &&
1523 git format-patch --stdout --cover-letter master.. >actual &&
1524 grep hello actual >/dev/null
1525'
1526
1527test_expect_success 'cover letter using branch description (5)' '
1528 git checkout rebuild-1 &&
1529 test_config branch.rebuild-1.description hello &&
1530 git format-patch --stdout --cover-letter -2 HEAD >actual &&
1531 grep hello actual >/dev/null
1532'
1533
1534test_expect_success 'cover letter using branch description (6)' '
1535 git checkout rebuild-1 &&
1536 test_config branch.rebuild-1.description hello &&
1537 git format-patch --stdout --cover-letter -2 >actual &&
1538 grep hello actual >/dev/null
1539'
1540
1541test_expect_success 'cover letter with nothing' '
1542 git format-patch --stdout --cover-letter >actual &&
1543 test_line_count = 0 actual
1544'
1545
1546test_expect_success 'cover letter auto' '
1547 mkdir -p tmp &&
1548 test_when_finished "rm -rf tmp;
1549 git config --unset format.coverletter" &&
1550
1551 git config format.coverletter auto &&
1552 git format-patch -o tmp -1 >list &&
1553 test_line_count = 1 list &&
1554 git format-patch -o tmp -2 >list &&
1555 test_line_count = 3 list
1556'
1557
1558test_expect_success 'cover letter auto user override' '
1559 mkdir -p tmp &&
1560 test_when_finished "rm -rf tmp;
1561 git config --unset format.coverletter" &&
1562
1563 git config format.coverletter auto &&
1564 git format-patch -o tmp --cover-letter -1 >list &&
1565 test_line_count = 2 list &&
1566 git format-patch -o tmp --cover-letter -2 >list &&
1567 test_line_count = 3 list &&
1568 git format-patch -o tmp --no-cover-letter -1 >list &&
1569 test_line_count = 1 list &&
1570 git format-patch -o tmp --no-cover-letter -2 >list &&
1571 test_line_count = 2 list
1572'
1573
1574test_expect_success 'format-patch --zero-commit' '
1575 git format-patch --zero-commit --stdout v2..v1 >patch2 &&
1576 grep "^From " patch2 | sort | uniq >actual &&
1577 echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
1578 test_cmp expect actual
1579'
1580
1581test_expect_success 'From line has expected format' '
1582 git format-patch --stdout v2..v1 >patch2 &&
1583 grep "^From " patch2 >from &&
1584 grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
1585 test_cmp from filtered
1586'
1587
1588test_expect_success 'format-patch format.outputDirectory option' '
1589 test_config format.outputDirectory patches &&
1590 rm -fr patches &&
1591 git format-patch master..side &&
1592 test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l)
1593'
1594
1595test_expect_success 'format-patch -o overrides format.outputDirectory' '
1596 test_config format.outputDirectory patches &&
1597 rm -fr patches patchset &&
1598 git format-patch master..side -o patchset &&
1599 test_path_is_missing patches &&
1600 test_path_is_dir patchset
1601'
1602
1603test_expect_success 'format-patch --base' '
1604 git checkout patchid &&
1605 git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
1606 git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
1607 echo >expected &&
1608 echo "base-commit: $(git rev-parse HEAD~3)" >>expected &&
1609 echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected &&
1610 echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected &&
1611 signature >> expected &&
1612 test_cmp expected actual1 &&
1613 test_cmp expected actual2 &&
1614 echo >fail &&
1615 echo "base-commit: $(git rev-parse HEAD~3)" >>fail &&
1616 echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1617 echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1618 signature >> fail &&
1619 ! test_cmp fail actual1 &&
1620 ! test_cmp fail actual2
1621'
1622
1623test_expect_success 'format-patch --base errors out when base commit is in revision list' '
1624 test_must_fail git format-patch --base=HEAD -2 &&
1625 test_must_fail git format-patch --base=HEAD~1 -2 &&
1626 git format-patch --stdout --base=HEAD~2 -2 >patch &&
1627 grep "^base-commit:" patch >actual &&
1628 echo "base-commit: $(git rev-parse HEAD~2)" >expected &&
1629 test_cmp expected actual
1630'
1631
1632test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
1633 # For history as below:
1634 #
1635 # ---Q---P---Z---Y---*---X
1636 # \ /
1637 # ------------W
1638 #
1639 # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
1640 git checkout -b topic1 master &&
1641 git rev-parse HEAD >commit-id-base &&
1642 test_commit P &&
1643 git rev-parse HEAD >commit-id-P &&
1644 test_commit Z &&
1645 git rev-parse HEAD >commit-id-Z &&
1646 test_commit Y &&
1647 git checkout -b topic2 master &&
1648 test_commit W &&
1649 git merge topic1 &&
1650 test_commit X &&
1651 test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
1652 test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
1653 git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
1654 grep "^base-commit:" patch >actual &&
1655 echo "base-commit: $(cat commit-id-base)" >expected &&
1656 test_cmp expected actual
1657'
1658
1659test_expect_success 'format-patch --base=auto' '
1660 git checkout -b upstream master &&
1661 git checkout -b local upstream &&
1662 git branch --set-upstream-to=upstream &&
1663 test_commit N1 &&
1664 test_commit N2 &&
1665 git format-patch --stdout --base=auto -2 >patch &&
1666 grep "^base-commit:" patch >actual &&
1667 echo "base-commit: $(git rev-parse upstream)" >expected &&
1668 test_cmp expected actual
1669'
1670
1671test_expect_success 'format-patch errors out when history involves criss-cross' '
1672 # setup criss-cross history
1673 #
1674 # B---M1---D
1675 # / \ /
1676 # A X
1677 # \ / \
1678 # C---M2---E
1679 #
1680 git checkout master &&
1681 test_commit A &&
1682 git checkout -b xb master &&
1683 test_commit B &&
1684 git checkout -b xc master &&
1685 test_commit C &&
1686 git checkout -b xbc xb -- &&
1687 git merge xc &&
1688 git checkout -b xcb xc -- &&
1689 git branch --set-upstream-to=xbc &&
1690 git merge xb &&
1691 git checkout xbc &&
1692 test_commit D &&
1693 git checkout xcb &&
1694 test_commit E &&
1695 test_must_fail git format-patch --base=auto -1
1696'
1697
1698test_expect_success 'format-patch format.useAutoBaseoption' '
1699 test_when_finished "git config --unset format.useAutoBase" &&
1700 git checkout local &&
1701 git config format.useAutoBase true &&
1702 git format-patch --stdout -1 >patch &&
1703 grep "^base-commit:" patch >actual &&
1704 echo "base-commit: $(git rev-parse upstream)" >expected &&
1705 test_cmp expected actual
1706'
1707
1708test_expect_success 'format-patch --base overrides format.useAutoBase' '
1709 test_when_finished "git config --unset format.useAutoBase" &&
1710 git config format.useAutoBase true &&
1711 git format-patch --stdout --base=HEAD~1 -1 >patch &&
1712 grep "^base-commit:" patch >actual &&
1713 echo "base-commit: $(git rev-parse HEAD~1)" >expected &&
1714 test_cmp expected actual
1715'
1716
1717test_expect_success 'format-patch --base with --attach' '
1718 git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
1719 sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
1720 patch >actual &&
1721 test_write_lines 1 2 >expect &&
1722 test_cmp expect actual
1723'
1724test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
1725 test_when_finished "rm -fr patches" &&
1726 git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
1727 ! egrep "^--+mimemime" patches/0000*.patch &&
1728 egrep "^--+mimemime$" patches/0001*.patch >output &&
1729 test_line_count = 2 output &&
1730 egrep "^--+mimemime--$" patches/0001*.patch >output &&
1731 test_line_count = 1 output
1732'
1733
1734test_expect_success 'format-patch --pretty=mboxrd' '
1735 sp=" " &&
1736 cat >msg <<-INPUT_END &&
1737 mboxrd should escape the body
1738
1739 From could trip up a loose mbox parser
1740 >From extra escape for reversibility
1741 >>From extra escape for reversibility 2
1742 from lower case not escaped
1743 Fromm bad speling not escaped
1744 From with leading space not escaped
1745
1746 F
1747 From
1748 From$sp
1749 From $sp
1750 From $sp
1751 INPUT_END
1752
1753 cat >expect <<-INPUT_END &&
1754 >From could trip up a loose mbox parser
1755 >>From extra escape for reversibility
1756 >>>From extra escape for reversibility 2
1757 from lower case not escaped
1758 Fromm bad speling not escaped
1759 From with leading space not escaped
1760
1761 F
1762 From
1763 From
1764 From
1765 From
1766 INPUT_END
1767
1768 C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
1769 git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
1770 git grep -h --no-index -A11 \
1771 "^>From could trip up a loose mbox parser" patch >actual &&
1772 test_cmp expect actual
1773'
1774
1775test_expect_success 'interdiff: setup' '
1776 git checkout -b boop master &&
1777 test_commit fnorp blorp &&
1778 test_commit fleep blorp
1779'
1780
1781test_expect_success 'interdiff: cover-letter' '
1782 sed "y/q/ /" >expect <<-\EOF &&
1783 +fleep
1784 --q
1785 EOF
1786 git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1787 test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1788 test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
1789 sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1790 test_cmp expect actual
1791'
1792
1793test_expect_success 'interdiff: reroll-count' '
1794 git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
1795 test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
1796'
1797
1798test_expect_success 'interdiff: solo-patch' '
1799 cat >expect <<-\EOF &&
1800 +fleep
1801
1802 EOF
1803 git format-patch --interdiff=boop~2 -1 boop &&
1804 test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
1805 sed "1,/^ @@ /d; /^$/q" <0001-fleep.patch >actual &&
1806 test_cmp expect actual
1807'
1808
1809test_done