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