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
10test_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
37test_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
45test_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
54test_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
62test_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
70test_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
76test_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
83test_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
89test_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
102test_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
113test_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
123test_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
131test_expect_success 'multiple files' '
132
133 rm -rf patches/ &&
134 git checkout side &&
135 git format-patch -o patches/ master &&
136 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
137'
138
139check_threading () {
140 expect="$1" &&
141 shift &&
142 (git format-patch --stdout "$@"; echo $? > status.out) |
143 # Prints everything between the Message-ID and In-Reply-To,
144 # and replaces all Message-ID-lookalikes by a sequence number
145 perl -ne '
146 if (/^(message-id|references|in-reply-to)/i) {
147 $printing = 1;
148 } elsif (/^\S/) {
149 $printing = 0;
150 }
151 if ($printing) {
152 $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
153 for $k (keys %h) {s/$k/$h{$k}/};
154 print;
155 }
156 print "---\n" if /^From /i;
157 ' > actual &&
158 test 0 = "$(cat status.out)" &&
159 test_cmp "$expect" actual
160}
161
162cat >> expect.no-threading <<EOF
163---
164---
165---
166EOF
167
168test_expect_success 'no threading' '
169 git checkout side &&
170 check_threading expect.no-threading master
171'
172
173cat > expect.thread <<EOF
174---
175Message-Id: <0>
176---
177Message-Id: <1>
178In-Reply-To: <0>
179References: <0>
180---
181Message-Id: <2>
182In-Reply-To: <0>
183References: <0>
184EOF
185
186test_expect_success 'thread' '
187 check_threading expect.thread --thread master
188'
189
190cat > expect.in-reply-to <<EOF
191---
192Message-Id: <0>
193In-Reply-To: <1>
194References: <1>
195---
196Message-Id: <2>
197In-Reply-To: <1>
198References: <1>
199---
200Message-Id: <3>
201In-Reply-To: <1>
202References: <1>
203EOF
204
205test_expect_success 'thread in-reply-to' '
206 check_threading expect.in-reply-to --in-reply-to="<test.message>" \
207 --thread master
208'
209
210cat > expect.cover-letter <<EOF
211---
212Message-Id: <0>
213---
214Message-Id: <1>
215In-Reply-To: <0>
216References: <0>
217---
218Message-Id: <2>
219In-Reply-To: <0>
220References: <0>
221---
222Message-Id: <3>
223In-Reply-To: <0>
224References: <0>
225EOF
226
227test_expect_success 'thread cover-letter' '
228 check_threading expect.cover-letter --cover-letter --thread master
229'
230
231cat > expect.cl-irt <<EOF
232---
233Message-Id: <0>
234In-Reply-To: <1>
235References: <1>
236---
237Message-Id: <2>
238In-Reply-To: <0>
239References: <1>
240 <0>
241---
242Message-Id: <3>
243In-Reply-To: <0>
244References: <1>
245 <0>
246---
247Message-Id: <4>
248In-Reply-To: <0>
249References: <1>
250 <0>
251EOF
252
253test_expect_success 'thread cover-letter in-reply-to' '
254 check_threading expect.cl-irt --cover-letter \
255 --in-reply-to="<test.message>" --thread master
256'
257
258test_expect_success 'thread explicit shallow' '
259 check_threading expect.cl-irt --cover-letter \
260 --in-reply-to="<test.message>" --thread=shallow master
261'
262
263cat > expect.deep <<EOF
264---
265Message-Id: <0>
266---
267Message-Id: <1>
268In-Reply-To: <0>
269References: <0>
270---
271Message-Id: <2>
272In-Reply-To: <1>
273References: <0>
274 <1>
275EOF
276
277test_expect_success 'thread deep' '
278 check_threading expect.deep --thread=deep master
279'
280
281cat > expect.deep-irt <<EOF
282---
283Message-Id: <0>
284In-Reply-To: <1>
285References: <1>
286---
287Message-Id: <2>
288In-Reply-To: <0>
289References: <1>
290 <0>
291---
292Message-Id: <3>
293In-Reply-To: <2>
294References: <1>
295 <0>
296 <2>
297EOF
298
299test_expect_success 'thread deep in-reply-to' '
300 check_threading expect.deep-irt --thread=deep \
301 --in-reply-to="<test.message>" master
302'
303
304cat > expect.deep-cl <<EOF
305---
306Message-Id: <0>
307---
308Message-Id: <1>
309In-Reply-To: <0>
310References: <0>
311---
312Message-Id: <2>
313In-Reply-To: <1>
314References: <0>
315 <1>
316---
317Message-Id: <3>
318In-Reply-To: <2>
319References: <0>
320 <1>
321 <2>
322EOF
323
324test_expect_success 'thread deep cover-letter' '
325 check_threading expect.deep-cl --cover-letter --thread=deep master
326'
327
328cat > expect.deep-cl-irt <<EOF
329---
330Message-Id: <0>
331In-Reply-To: <1>
332References: <1>
333---
334Message-Id: <2>
335In-Reply-To: <0>
336References: <1>
337 <0>
338---
339Message-Id: <3>
340In-Reply-To: <2>
341References: <1>
342 <0>
343 <2>
344---
345Message-Id: <4>
346In-Reply-To: <3>
347References: <1>
348 <0>
349 <2>
350 <3>
351EOF
352
353test_expect_success 'thread deep cover-letter in-reply-to' '
354 check_threading expect.deep-cl-irt --cover-letter \
355 --in-reply-to="<test.message>" --thread=deep master
356'
357
358test_expect_success 'thread via config' '
359 git config format.thread true &&
360 check_threading expect.thread master
361'
362
363test_expect_success 'thread deep via config' '
364 git config format.thread deep &&
365 check_threading expect.deep master
366'
367
368test_expect_success 'thread config + override' '
369 git config format.thread deep &&
370 check_threading expect.thread --thread master
371'
372
373test_expect_success 'thread config + --no-thread' '
374 git config format.thread deep &&
375 check_threading expect.no-threading --no-thread master
376'
377
378test_expect_success 'excessive subject' '
379
380 rm -rf patches/ &&
381 git checkout side &&
382 for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
383 git update-index file &&
384 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." &&
385 git format-patch -o patches/ master..side &&
386 ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
387'
388
389test_expect_success 'cover-letter inherits diff options' '
390
391 git mv file foo &&
392 git commit -m foo &&
393 git format-patch --cover-letter -1 &&
394 ! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
395 git format-patch --cover-letter -1 -M &&
396 grep "file => foo .* 0 *$" 0000-cover-letter.patch
397
398'
399
400cat > expect << EOF
401 This is an excessively long subject line for a message due to the
402 habit some projects have of not having a short, one-line subject at
403 the start of the commit message, but rather sticking a whole
404 paragraph right at the start as the only thing in the commit
405 message. It had better not become the filename for the patch.
406 foo
407
408EOF
409
410test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
411
412 git format-patch --cover-letter -2 &&
413 sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
414 test_cmp expect output
415
416'
417
418cat > expect << EOF
419---
420 file | 16 ++++++++++++++++
421 1 files changed, 16 insertions(+), 0 deletions(-)
422
423diff --git a/file b/file
424index 40f36c6..2dc5c23 100644
425--- a/file
426+++ b/file
427@@ -13,4 +13,20 @@ C
428 10
429 D
430 E
431 F
432+5
433EOF
434
435test_expect_success 'format-patch respects -U' '
436
437 git format-patch -U4 -2 &&
438 sed -e "1,/^$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
439 test_cmp expect output
440
441'
442
443test_expect_success 'format-patch from a subdirectory (1)' '
444 filename=$(
445 rm -rf sub &&
446 mkdir -p sub/dir &&
447 cd sub/dir &&
448 git format-patch -1
449 ) &&
450 case "$filename" in
451 0*)
452 ;; # ok
453 *)
454 echo "Oops? $filename"
455 false
456 ;;
457 esac &&
458 test -f "$filename"
459'
460
461test_expect_success 'format-patch from a subdirectory (2)' '
462 filename=$(
463 rm -rf sub &&
464 mkdir -p sub/dir &&
465 cd sub/dir &&
466 git format-patch -1 -o ..
467 ) &&
468 case "$filename" in
469 ../0*)
470 ;; # ok
471 *)
472 echo "Oops? $filename"
473 false
474 ;;
475 esac &&
476 basename=$(expr "$filename" : ".*/\(.*\)") &&
477 test -f "sub/$basename"
478'
479
480test_expect_success 'format-patch from a subdirectory (3)' '
481 here="$TEST_DIRECTORY/$test" &&
482 rm -f 0* &&
483 filename=$(
484 rm -rf sub &&
485 mkdir -p sub/dir &&
486 cd sub/dir &&
487 git format-patch -1 -o "$here"
488 ) &&
489 basename=$(expr "$filename" : ".*/\(.*\)") &&
490 test -f "$basename"
491'
492
493test_done