1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Junio C Hamano
4 #
6 test_description='various format-patch tests'
8 . ./test-lib.sh
10 test_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 git commit -m Initial &&
16 git checkout -b side &&
18 for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
19 chmod +x elif &&
20 git update-index file elif &&
21 git update-index --chmod=+x elif &&
22 git commit -m "Side changes #1" &&
24 for i in D E F; do echo "$i"; done >>file &&
25 git update-index file &&
26 git commit -m "Side changes #2" &&
27 git tag C2 &&
29 for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
30 git update-index file &&
31 git commit -m "Side changes #3 with \\n backslash-n in it." &&
33 git checkout master &&
34 git diff-tree -p C2 | git apply --index &&
35 git commit -m "Master accepts moral equivalent of #2"
37 '
39 test_expect_success "format-patch --ignore-if-in-upstream" '
41 git format-patch --stdout master..side >patch0 &&
42 cnt=`grep "^From " patch0 | wc -l` &&
43 test $cnt = 3
45 '
47 test_expect_success "format-patch --ignore-if-in-upstream" '
49 git format-patch --stdout \
50 --ignore-if-in-upstream master..side >patch1 &&
51 cnt=`grep "^From " patch1 | wc -l` &&
52 test $cnt = 2
54 '
56 test_expect_success "format-patch result applies" '
58 git checkout -b rebuild-0 master &&
59 git am -3 patch0 &&
60 cnt=`git rev-list master.. | wc -l` &&
61 test $cnt = 2
62 '
64 test_expect_success "format-patch --ignore-if-in-upstream result applies" '
66 git checkout -b rebuild-1 master &&
67 git am -3 patch1 &&
68 cnt=`git rev-list master.. | wc -l` &&
69 test $cnt = 2
70 '
72 test_expect_success 'commit did not screw up the log message' '
74 git cat-file commit side | grep "^Side .* with .* backslash-n"
76 '
78 test_expect_success 'format-patch did not screw up the log message' '
80 grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
81 grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
83 '
85 test_expect_success 'replay did not screw up the log message' '
87 git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
89 '
91 test_expect_success 'extra headers' '
93 git config format.headers "To: R. E. Cipient <rcipient@example.com>
94 " &&
95 git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
96 " &&
97 git format-patch --stdout master..side > patch2 &&
98 sed -e "/^$/q" patch2 > hdrs2 &&
99 grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs2 &&
100 grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs2
102 '
104 test_expect_success 'extra headers without newlines' '
106 git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
107 git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
108 git format-patch --stdout master..side >patch3 &&
109 sed -e "/^$/q" patch3 > hdrs3 &&
110 grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs3 &&
111 grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs3
113 '
115 test_expect_success 'extra headers with multiple To:s' '
117 git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
118 git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
119 git format-patch --stdout master..side > patch4 &&
120 sed -e "/^$/q" patch4 > hdrs4 &&
121 grep "^To: R. E. Cipient <rcipient@example.com>,$" hdrs4 &&
122 grep "^ *S. E. Cipient <scipient@example.com>$" hdrs4
123 '
125 test_expect_success 'additional command line cc' '
127 git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
128 git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch5 &&
129 grep "^Cc: R. E. Cipient <rcipient@example.com>,$" patch5 &&
130 grep "^ *S. E. Cipient <scipient@example.com>$" patch5
131 '
133 test_expect_success 'multiple files' '
135 rm -rf patches/ &&
136 git checkout side &&
137 git format-patch -o patches/ master &&
138 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
139 '
141 check_threading () {
142 expect="$1" &&
143 shift &&
144 (git format-patch --stdout "$@"; echo $? > status.out) |
145 # Prints everything between the Message-ID and In-Reply-To,
146 # and replaces all Message-ID-lookalikes by a sequence number
147 perl -ne '
148 if (/^(message-id|references|in-reply-to)/i) {
149 $printing = 1;
150 } elsif (/^\S/) {
151 $printing = 0;
152 }
153 if ($printing) {
154 $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
155 for $k (keys %h) {s/$k/$h{$k}/};
156 print;
157 }
158 print "---\n" if /^From /i;
159 ' > actual &&
160 test 0 = "$(cat status.out)" &&
161 test_cmp "$expect" actual
162 }
164 cat >> expect.no-threading <<EOF
165 ---
166 ---
167 ---
168 EOF
170 test_expect_success 'no threading' '
171 git checkout side &&
172 check_threading expect.no-threading master
173 '
175 cat > expect.thread <<EOF
176 ---
177 Message-Id: <0>
178 ---
179 Message-Id: <1>
180 In-Reply-To: <0>
181 References: <0>
182 ---
183 Message-Id: <2>
184 In-Reply-To: <0>
185 References: <0>
186 EOF
188 test_expect_success 'thread' '
189 check_threading expect.thread --thread master
190 '
192 cat > expect.in-reply-to <<EOF
193 ---
194 Message-Id: <0>
195 In-Reply-To: <1>
196 References: <1>
197 ---
198 Message-Id: <2>
199 In-Reply-To: <1>
200 References: <1>
201 ---
202 Message-Id: <3>
203 In-Reply-To: <1>
204 References: <1>
205 EOF
207 test_expect_success 'thread in-reply-to' '
208 check_threading expect.in-reply-to --in-reply-to="<test.message>" \
209 --thread master
210 '
212 cat > expect.cover-letter <<EOF
213 ---
214 Message-Id: <0>
215 ---
216 Message-Id: <1>
217 In-Reply-To: <0>
218 References: <0>
219 ---
220 Message-Id: <2>
221 In-Reply-To: <0>
222 References: <0>
223 ---
224 Message-Id: <3>
225 In-Reply-To: <0>
226 References: <0>
227 EOF
229 test_expect_success 'thread cover-letter' '
230 check_threading expect.cover-letter --cover-letter --thread master
231 '
233 cat > expect.cl-irt <<EOF
234 ---
235 Message-Id: <0>
236 In-Reply-To: <1>
237 References: <1>
238 ---
239 Message-Id: <2>
240 In-Reply-To: <0>
241 References: <1>
242 <0>
243 ---
244 Message-Id: <3>
245 In-Reply-To: <0>
246 References: <1>
247 <0>
248 ---
249 Message-Id: <4>
250 In-Reply-To: <0>
251 References: <1>
252 <0>
253 EOF
255 test_expect_success 'thread cover-letter in-reply-to' '
256 check_threading expect.cl-irt --cover-letter \
257 --in-reply-to="<test.message>" --thread master
258 '
260 test_expect_success 'thread explicit shallow' '
261 check_threading expect.cl-irt --cover-letter \
262 --in-reply-to="<test.message>" --thread=shallow master
263 '
265 cat > expect.deep <<EOF
266 ---
267 Message-Id: <0>
268 ---
269 Message-Id: <1>
270 In-Reply-To: <0>
271 References: <0>
272 ---
273 Message-Id: <2>
274 In-Reply-To: <1>
275 References: <0>
276 <1>
277 EOF
279 test_expect_success 'thread deep' '
280 check_threading expect.deep --thread=deep master
281 '
283 cat > expect.deep-irt <<EOF
284 ---
285 Message-Id: <0>
286 In-Reply-To: <1>
287 References: <1>
288 ---
289 Message-Id: <2>
290 In-Reply-To: <0>
291 References: <1>
292 <0>
293 ---
294 Message-Id: <3>
295 In-Reply-To: <2>
296 References: <1>
297 <0>
298 <2>
299 EOF
301 test_expect_success 'thread deep in-reply-to' '
302 check_threading expect.deep-irt --thread=deep \
303 --in-reply-to="<test.message>" master
304 '
306 cat > expect.deep-cl <<EOF
307 ---
308 Message-Id: <0>
309 ---
310 Message-Id: <1>
311 In-Reply-To: <0>
312 References: <0>
313 ---
314 Message-Id: <2>
315 In-Reply-To: <1>
316 References: <0>
317 <1>
318 ---
319 Message-Id: <3>
320 In-Reply-To: <2>
321 References: <0>
322 <1>
323 <2>
324 EOF
326 test_expect_success 'thread deep cover-letter' '
327 check_threading expect.deep-cl --cover-letter --thread=deep master
328 '
330 cat > expect.deep-cl-irt <<EOF
331 ---
332 Message-Id: <0>
333 In-Reply-To: <1>
334 References: <1>
335 ---
336 Message-Id: <2>
337 In-Reply-To: <0>
338 References: <1>
339 <0>
340 ---
341 Message-Id: <3>
342 In-Reply-To: <2>
343 References: <1>
344 <0>
345 <2>
346 ---
347 Message-Id: <4>
348 In-Reply-To: <3>
349 References: <1>
350 <0>
351 <2>
352 <3>
353 EOF
355 test_expect_success 'thread deep cover-letter in-reply-to' '
356 check_threading expect.deep-cl-irt --cover-letter \
357 --in-reply-to="<test.message>" --thread=deep master
358 '
360 test_expect_success 'thread via config' '
361 git config format.thread true &&
362 check_threading expect.thread master
363 '
365 test_expect_success 'thread deep via config' '
366 git config format.thread deep &&
367 check_threading expect.deep master
368 '
370 test_expect_success 'thread config + override' '
371 git config format.thread deep &&
372 check_threading expect.thread --thread master
373 '
375 test_expect_success 'thread config + --no-thread' '
376 git config format.thread deep &&
377 check_threading expect.no-threading --no-thread master
378 '
380 test_expect_success 'excessive subject' '
382 rm -rf patches/ &&
383 git checkout side &&
384 for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
385 git update-index file &&
386 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." &&
387 git format-patch -o patches/ master..side &&
388 ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
389 '
391 test_expect_success 'cover-letter inherits diff options' '
393 git mv file foo &&
394 git commit -m foo &&
395 git format-patch --cover-letter -1 &&
396 ! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
397 git format-patch --cover-letter -1 -M &&
398 grep "file => foo .* 0 *$" 0000-cover-letter.patch
400 '
402 cat > expect << EOF
403 This is an excessively long subject line for a message due to the
404 habit some projects have of not having a short, one-line subject at
405 the start of the commit message, but rather sticking a whole
406 paragraph right at the start as the only thing in the commit
407 message. It had better not become the filename for the patch.
408 foo
410 EOF
412 test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
414 git format-patch --cover-letter -2 &&
415 sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
416 test_cmp expect output
418 '
420 cat > expect << EOF
421 ---
422 file | 16 ++++++++++++++++
423 1 files changed, 16 insertions(+), 0 deletions(-)
425 diff --git a/file b/file
426 index 40f36c6..2dc5c23 100644
427 --- a/file
428 +++ b/file
429 @@ -13,4 +13,20 @@ C
430 10
431 D
432 E
433 F
434 +5
435 EOF
437 test_expect_success 'format-patch respects -U' '
439 git format-patch -U4 -2 &&
440 sed -e "1,/^$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
441 test_cmp expect output
443 '
445 test_expect_success 'format-patch from a subdirectory (1)' '
446 filename=$(
447 rm -rf sub &&
448 mkdir -p sub/dir &&
449 cd sub/dir &&
450 git format-patch -1
451 ) &&
452 case "$filename" in
453 0*)
454 ;; # ok
455 *)
456 echo "Oops? $filename"
457 false
458 ;;
459 esac &&
460 test -f "$filename"
461 '
463 test_expect_success 'format-patch from a subdirectory (2)' '
464 filename=$(
465 rm -rf sub &&
466 mkdir -p sub/dir &&
467 cd sub/dir &&
468 git format-patch -1 -o ..
469 ) &&
470 case "$filename" in
471 ../0*)
472 ;; # ok
473 *)
474 echo "Oops? $filename"
475 false
476 ;;
477 esac &&
478 basename=$(expr "$filename" : ".*/\(.*\)") &&
479 test -f "sub/$basename"
480 '
482 test_expect_success 'format-patch from a subdirectory (3)' '
483 here="$TEST_DIRECTORY/$test" &&
484 rm -f 0* &&
485 filename=$(
486 rm -rf sub &&
487 mkdir -p sub/dir &&
488 cd sub/dir &&
489 git format-patch -1 -o "$here"
490 ) &&
491 basename=$(expr "$filename" : ".*/\(.*\)") &&
492 test -f "$basename"
493 '
495 test_done