Add 'git format-patch --to=' option and 'format.to' configuration variable.
[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
10 test_expect_success setup '
11
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         git commit -m Initial &&
16         git checkout -b side &&
17
18         for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
19         test_chmod +x elif &&
20         git commit -m "Side changes #1" &&
21
22         for i in D E F; do echo "$i"; done >>file &&
23         git update-index file &&
24         git commit -m "Side changes #2" &&
25         git tag C2 &&
26
27         for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
28         git update-index file &&
29         git commit -m "Side changes #3 with \\n backslash-n in it." &&
30
31         git checkout master &&
32         git diff-tree -p C2 | git apply --index &&
33         git commit -m "Master accepts moral equivalent of #2"
34
35 '
36
37 test_expect_success "format-patch --ignore-if-in-upstream" '
38
39         git format-patch --stdout master..side >patch0 &&
40         cnt=`grep "^From " patch0 | wc -l` &&
41         test $cnt = 3
42
43 '
44
45 test_expect_success "format-patch --ignore-if-in-upstream" '
46
47         git format-patch --stdout \
48                 --ignore-if-in-upstream master..side >patch1 &&
49         cnt=`grep "^From " patch1 | wc -l` &&
50         test $cnt = 2
51
52 '
53
54 test_expect_success "format-patch result applies" '
55
56         git checkout -b rebuild-0 master &&
57         git am -3 patch0 &&
58         cnt=`git rev-list master.. | wc -l` &&
59         test $cnt = 2
60 '
61
62 test_expect_success "format-patch --ignore-if-in-upstream result applies" '
63
64         git checkout -b rebuild-1 master &&
65         git am -3 patch1 &&
66         cnt=`git rev-list master.. | wc -l` &&
67         test $cnt = 2
68 '
69
70 test_expect_success 'commit did not screw up the log message' '
71
72         git cat-file commit side | grep "^Side .* with .* backslash-n"
73
74 '
75
76 test_expect_success 'format-patch did not screw up the log message' '
77
78         grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
79         grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
80
81 '
82
83 test_expect_success 'replay did not screw up the log message' '
84
85         git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
86
87 '
88
89 test_expect_success 'extra headers' '
90
91         git config format.headers "To: R. E. Cipient <rcipient@example.com>
92 " &&
93         git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
94 " &&
95         git format-patch --stdout master..side > patch2 &&
96         sed -e "/^\$/q" patch2 > hdrs2 &&
97         grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
98         grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
99
100 '
101
102 test_expect_success 'extra headers without newlines' '
103
104         git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
105         git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
106         git format-patch --stdout master..side >patch3 &&
107         sed -e "/^\$/q" patch3 > hdrs3 &&
108         grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
109         grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
110
111 '
112
113 test_expect_success 'extra headers with multiple To:s' '
114
115         git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
116         git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
117         git format-patch --stdout master..side > patch4 &&
118         sed -e "/^\$/q" patch4 > hdrs4 &&
119         grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
120         grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
121 '
122
123 test_expect_success 'additional command line cc' '
124
125         git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
126         git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
127         grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 &&
128         grep "^ *S. E. Cipient <scipient@example.com>\$" patch5
129 '
130
131 test_expect_success 'command line headers' '
132
133         git config --unset-all format.headers &&
134         git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
135         grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
136 '
137
138 test_expect_success 'configuration headers and command line headers' '
139
140         git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
141         git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
142         grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
143         grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
144 '
145
146 test_expect_success 'command line To: header' '
147
148         git config --unset-all format.headers &&
149         git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
150         grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8
151 '
152
153 test_expect_success 'configuration To: header' '
154
155         git config format.to "R. E. Cipient <rcipient@example.com>" &&
156         git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
157         grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
158 '
159
160 test_expect_success 'multiple files' '
161
162         rm -rf patches/ &&
163         git checkout side &&
164         git format-patch -o patches/ master &&
165         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
166 '
167
168 check_threading () {
169         expect="$1" &&
170         shift &&
171         (git format-patch --stdout "$@"; echo $? > status.out) |
172         # Prints everything between the Message-ID and In-Reply-To,
173         # and replaces all Message-ID-lookalikes by a sequence number
174         perl -ne '
175                 if (/^(message-id|references|in-reply-to)/i) {
176                         $printing = 1;
177                 } elsif (/^\S/) {
178                         $printing = 0;
179                 }
180                 if ($printing) {
181                         $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
182                         for $k (keys %h) {s/$k/$h{$k}/};
183                         print;
184                 }
185                 print "---\n" if /^From /i;
186         ' > actual &&
187         test 0 = "$(cat status.out)" &&
188         test_cmp "$expect" actual
189 }
190
191 cat >> expect.no-threading <<EOF
192 ---
193 ---
194 ---
195 EOF
196
197 test_expect_success 'no threading' '
198         git checkout side &&
199         check_threading expect.no-threading master
200 '
201
202 cat > expect.thread <<EOF
203 ---
204 Message-Id: <0>
205 ---
206 Message-Id: <1>
207 In-Reply-To: <0>
208 References: <0>
209 ---
210 Message-Id: <2>
211 In-Reply-To: <0>
212 References: <0>
213 EOF
214
215 test_expect_success 'thread' '
216         check_threading expect.thread --thread master
217 '
218
219 cat > expect.in-reply-to <<EOF
220 ---
221 Message-Id: <0>
222 In-Reply-To: <1>
223 References: <1>
224 ---
225 Message-Id: <2>
226 In-Reply-To: <1>
227 References: <1>
228 ---
229 Message-Id: <3>
230 In-Reply-To: <1>
231 References: <1>
232 EOF
233
234 test_expect_success 'thread in-reply-to' '
235         check_threading expect.in-reply-to --in-reply-to="<test.message>" \
236                 --thread master
237 '
238
239 cat > expect.cover-letter <<EOF
240 ---
241 Message-Id: <0>
242 ---
243 Message-Id: <1>
244 In-Reply-To: <0>
245 References: <0>
246 ---
247 Message-Id: <2>
248 In-Reply-To: <0>
249 References: <0>
250 ---
251 Message-Id: <3>
252 In-Reply-To: <0>
253 References: <0>
254 EOF
255
256 test_expect_success 'thread cover-letter' '
257         check_threading expect.cover-letter --cover-letter --thread master
258 '
259
260 cat > expect.cl-irt <<EOF
261 ---
262 Message-Id: <0>
263 In-Reply-To: <1>
264 References: <1>
265 ---
266 Message-Id: <2>
267 In-Reply-To: <0>
268 References: <1>
269         <0>
270 ---
271 Message-Id: <3>
272 In-Reply-To: <0>
273 References: <1>
274         <0>
275 ---
276 Message-Id: <4>
277 In-Reply-To: <0>
278 References: <1>
279         <0>
280 EOF
281
282 test_expect_success 'thread cover-letter in-reply-to' '
283         check_threading expect.cl-irt --cover-letter \
284                 --in-reply-to="<test.message>" --thread master
285 '
286
287 test_expect_success 'thread explicit shallow' '
288         check_threading expect.cl-irt --cover-letter \
289                 --in-reply-to="<test.message>" --thread=shallow master
290 '
291
292 cat > expect.deep <<EOF
293 ---
294 Message-Id: <0>
295 ---
296 Message-Id: <1>
297 In-Reply-To: <0>
298 References: <0>
299 ---
300 Message-Id: <2>
301 In-Reply-To: <1>
302 References: <0>
303         <1>
304 EOF
305
306 test_expect_success 'thread deep' '
307         check_threading expect.deep --thread=deep master
308 '
309
310 cat > expect.deep-irt <<EOF
311 ---
312 Message-Id: <0>
313 In-Reply-To: <1>
314 References: <1>
315 ---
316 Message-Id: <2>
317 In-Reply-To: <0>
318 References: <1>
319         <0>
320 ---
321 Message-Id: <3>
322 In-Reply-To: <2>
323 References: <1>
324         <0>
325         <2>
326 EOF
327
328 test_expect_success 'thread deep in-reply-to' '
329         check_threading expect.deep-irt  --thread=deep \
330                 --in-reply-to="<test.message>" master
331 '
332
333 cat > expect.deep-cl <<EOF
334 ---
335 Message-Id: <0>
336 ---
337 Message-Id: <1>
338 In-Reply-To: <0>
339 References: <0>
340 ---
341 Message-Id: <2>
342 In-Reply-To: <1>
343 References: <0>
344         <1>
345 ---
346 Message-Id: <3>
347 In-Reply-To: <2>
348 References: <0>
349         <1>
350         <2>
351 EOF
352
353 test_expect_success 'thread deep cover-letter' '
354         check_threading expect.deep-cl --cover-letter --thread=deep master
355 '
356
357 cat > expect.deep-cl-irt <<EOF
358 ---
359 Message-Id: <0>
360 In-Reply-To: <1>
361 References: <1>
362 ---
363 Message-Id: <2>
364 In-Reply-To: <0>
365 References: <1>
366         <0>
367 ---
368 Message-Id: <3>
369 In-Reply-To: <2>
370 References: <1>
371         <0>
372         <2>
373 ---
374 Message-Id: <4>
375 In-Reply-To: <3>
376 References: <1>
377         <0>
378         <2>
379         <3>
380 EOF
381
382 test_expect_success 'thread deep cover-letter in-reply-to' '
383         check_threading expect.deep-cl-irt --cover-letter \
384                 --in-reply-to="<test.message>" --thread=deep master
385 '
386
387 test_expect_success 'thread via config' '
388         git config format.thread true &&
389         check_threading expect.thread master
390 '
391
392 test_expect_success 'thread deep via config' '
393         git config format.thread deep &&
394         check_threading expect.deep master
395 '
396
397 test_expect_success 'thread config + override' '
398         git config format.thread deep &&
399         check_threading expect.thread --thread master
400 '
401
402 test_expect_success 'thread config + --no-thread' '
403         git config format.thread deep &&
404         check_threading expect.no-threading --no-thread master
405 '
406
407 test_expect_success 'excessive subject' '
408
409         rm -rf patches/ &&
410         git checkout side &&
411         for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
412         git update-index file &&
413         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." &&
414         git format-patch -o patches/ master..side &&
415         ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
416 '
417
418 test_expect_success 'cover-letter inherits diff options' '
419
420         git mv file foo &&
421         git commit -m foo &&
422         git format-patch --cover-letter -1 &&
423         ! grep "file => foo .* 0 *\$" 0000-cover-letter.patch &&
424         git format-patch --cover-letter -1 -M &&
425         grep "file => foo .* 0 *\$" 0000-cover-letter.patch
426
427 '
428
429 cat > expect << EOF
430   This is an excessively long subject line for a message due to the
431     habit some projects have of not having a short, one-line subject at
432     the start of the commit message, but rather sticking a whole
433     paragraph right at the start as the only thing in the commit
434     message. It had better not become the filename for the patch.
435   foo
436
437 EOF
438
439 test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
440
441         git format-patch --cover-letter -2 &&
442         sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output &&
443         test_cmp expect output
444
445 '
446
447 cat > expect << EOF
448 ---
449  file |   16 ++++++++++++++++
450  1 files changed, 16 insertions(+), 0 deletions(-)
451
452 diff --git a/file b/file
453 index 40f36c6..2dc5c23 100644
454 --- a/file
455 +++ b/file
456 @@ -13,4 +13,20 @@ C
457  10
458  D
459  E
460  F
461 +5
462 EOF
463
464 test_expect_success 'format-patch respects -U' '
465
466         git format-patch -U4 -2 &&
467         sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
468         test_cmp expect output
469
470 '
471
472 cat > expect << EOF
473
474 diff --git a/file b/file
475 index 40f36c6..2dc5c23 100644
476 --- a/file
477 +++ b/file
478 @@ -14,3 +14,19 @@ C
479  D
480  E
481  F
482 +5
483 EOF
484
485 test_expect_success 'format-patch -p suppresses stat' '
486
487         git format-patch -p -2 &&
488         sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
489         test_cmp expect output
490
491 '
492
493 test_expect_success 'format-patch from a subdirectory (1)' '
494         filename=$(
495                 rm -rf sub &&
496                 mkdir -p sub/dir &&
497                 cd sub/dir &&
498                 git format-patch -1
499         ) &&
500         case "$filename" in
501         0*)
502                 ;; # ok
503         *)
504                 echo "Oops? $filename"
505                 false
506                 ;;
507         esac &&
508         test -f "$filename"
509 '
510
511 test_expect_success 'format-patch from a subdirectory (2)' '
512         filename=$(
513                 rm -rf sub &&
514                 mkdir -p sub/dir &&
515                 cd sub/dir &&
516                 git format-patch -1 -o ..
517         ) &&
518         case "$filename" in
519         ../0*)
520                 ;; # ok
521         *)
522                 echo "Oops? $filename"
523                 false
524                 ;;
525         esac &&
526         basename=$(expr "$filename" : ".*/\(.*\)") &&
527         test -f "sub/$basename"
528 '
529
530 test_expect_success 'format-patch from a subdirectory (3)' '
531         rm -f 0* &&
532         filename=$(
533                 rm -rf sub &&
534                 mkdir -p sub/dir &&
535                 cd sub/dir &&
536                 git format-patch -1 -o "$TRASH_DIRECTORY"
537         ) &&
538         basename=$(expr "$filename" : ".*/\(.*\)") &&
539         test -f "$basename"
540 '
541
542 test_expect_success 'format-patch --in-reply-to' '
543         git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
544         grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
545         grep "^References: <baz@foo.bar>" patch8
546 '
547
548 test_expect_success 'format-patch --signoff' '
549         git format-patch -1 --signoff --stdout |
550         grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
551 '
552
553 echo "fatal: --name-only does not make sense" > expect.name-only
554 echo "fatal: --name-status does not make sense" > expect.name-status
555 echo "fatal: --check does not make sense" > expect.check
556
557 test_expect_success 'options no longer allowed for format-patch' '
558         test_must_fail git format-patch --name-only 2> output &&
559         test_cmp expect.name-only output &&
560         test_must_fail git format-patch --name-status 2> output &&
561         test_cmp expect.name-status output &&
562         test_must_fail git format-patch --check 2> output &&
563         test_cmp expect.check output'
564
565 test_expect_success 'format-patch --numstat should produce a patch' '
566         git format-patch --numstat --stdout master..side > output &&
567         test 6 = $(grep "^diff --git a/" output | wc -l)'
568
569 test_expect_success 'format-patch -- <path>' '
570         git format-patch master..side -- file 2>error &&
571         ! grep "Use .--" error
572 '
573
574 test_done