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 test_chmod +x elif &&
20 git commit -m "Side changes #1" &&
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 &&
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." &&
31 git checkout master &&
32 git diff-tree -p C2 | git apply --index &&
33 git commit -m "Master accepts moral equivalent of #2"
35 '
37 test_expect_success "format-patch --ignore-if-in-upstream" '
39 git format-patch --stdout master..side >patch0 &&
40 cnt=`grep "^From " patch0 | wc -l` &&
41 test $cnt = 3
43 '
45 test_expect_success "format-patch --ignore-if-in-upstream" '
47 git format-patch --stdout \
48 --ignore-if-in-upstream master..side >patch1 &&
49 cnt=`grep "^From " patch1 | wc -l` &&
50 test $cnt = 2
52 '
54 test_expect_success "format-patch result applies" '
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 '
62 test_expect_success "format-patch --ignore-if-in-upstream result applies" '
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 '
70 test_expect_success 'commit did not screw up the log message' '
72 git cat-file commit side | grep "^Side .* with .* backslash-n"
74 '
76 test_expect_success 'format-patch did not screw up the log message' '
78 grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
79 grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
81 '
83 test_expect_success 'replay did not screw up the log message' '
85 git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
87 '
89 test_expect_success 'extra headers' '
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
100 '
102 test_expect_success 'extra headers without newlines' '
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
111 '
113 test_expect_success 'extra headers with multiple To:s' '
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 '
123 test_expect_success 'additional command line cc' '
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 '
131 test_expect_success 'command line headers' '
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 '
138 test_expect_success 'configuration headers and command line headers' '
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 '
146 test_expect_success 'command line To: header' '
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 '
153 test_expect_success 'configuration To: header' '
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 '
160 test_expect_success 'multiple files' '
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 '
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 }
191 cat >> expect.no-threading <<EOF
192 ---
193 ---
194 ---
195 EOF
197 test_expect_success 'no threading' '
198 git checkout side &&
199 check_threading expect.no-threading master
200 '
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
215 test_expect_success 'thread' '
216 check_threading expect.thread --thread master
217 '
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
234 test_expect_success 'thread in-reply-to' '
235 check_threading expect.in-reply-to --in-reply-to="<test.message>" \
236 --thread master
237 '
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
256 test_expect_success 'thread cover-letter' '
257 check_threading expect.cover-letter --cover-letter --thread master
258 '
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
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 '
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 '
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
306 test_expect_success 'thread deep' '
307 check_threading expect.deep --thread=deep master
308 '
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
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 '
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
353 test_expect_success 'thread deep cover-letter' '
354 check_threading expect.deep-cl --cover-letter --thread=deep master
355 '
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
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 '
387 test_expect_success 'thread via config' '
388 git config format.thread true &&
389 check_threading expect.thread master
390 '
392 test_expect_success 'thread deep via config' '
393 git config format.thread deep &&
394 check_threading expect.deep master
395 '
397 test_expect_success 'thread config + override' '
398 git config format.thread deep &&
399 check_threading expect.thread --thread master
400 '
402 test_expect_success 'thread config + --no-thread' '
403 git config format.thread deep &&
404 check_threading expect.no-threading --no-thread master
405 '
407 test_expect_success 'excessive subject' '
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 '
418 test_expect_success 'cover-letter inherits diff options' '
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
427 '
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
437 EOF
439 test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
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
445 '
447 cat > expect << EOF
448 ---
449 file | 16 ++++++++++++++++
450 1 files changed, 16 insertions(+), 0 deletions(-)
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
464 test_expect_success 'format-patch respects -U' '
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
470 '
472 cat > expect << EOF
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
485 test_expect_success 'format-patch -p suppresses stat' '
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
491 '
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 '
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 '
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 '
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 '
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 '
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
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'
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)'
569 test_expect_success 'format-patch -- <path>' '
570 git format-patch master..side -- file 2>error &&
571 ! grep "Use .--" error
572 '
574 test_done