1#!/bin/sh
2
3test_description='git am running'
4
5. ./test-lib.sh
6
7test_expect_success 'setup: messages' '
8 cat >msg <<-\EOF &&
9 second
10
11 Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy
12 eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
13 voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
14 kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem
15 ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
16 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
17 vero eos et accusam et justo duo dolores et ea rebum.
18
19 EOF
20 qz_to_tab_space <<-\EOF >>msg &&
21 QDuis autem vel eum iriure dolor in hendrerit in vulputate velit
22 Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis
23 Qat vero eros et accumsan et iusto odio dignissim qui blandit
24 Qpraesent luptatum zzril delenit augue duis dolore te feugait nulla
25 Qfacilisi.
26 EOF
27 cat >>msg <<-\EOF &&
28
29 Lorem ipsum dolor sit amet,
30 consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
31 laoreet dolore magna aliquam erat volutpat.
32
33 git
34 ---
35 +++
36
37 Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
38 lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
39 dolor in hendrerit in vulputate velit esse molestie consequat, vel illum
40 dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
41 dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te
42 feugait nulla facilisi.
43 EOF
44
45 cat >failmail <<-\EOF &&
46 From foo@example.com Fri May 23 10:43:49 2008
47 From: foo@example.com
48 To: bar@example.com
49 Subject: Re: [RFC/PATCH] git-foo.sh
50 Date: Fri, 23 May 2008 05:23:42 +0200
51
52 Sometimes we have to find out that there'\''s nothing left.
53
54 EOF
55
56 cat >pine <<-\EOF &&
57 From MAILER-DAEMON Fri May 23 10:43:49 2008
58 Date: 23 May 2008 05:23:42 +0200
59 From: Mail System Internal Data <MAILER-DAEMON@example.com>
60 Subject: DON'\''T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA
61 Message-ID: <foo-0001@example.com>
62
63 This text is part of the internal format of your mail folder, and is not
64 a real message. It is created automatically by the mail system software.
65 If deleted, important folder data will be lost, and it will be re-created
66 with the data reset to initial values.
67
68 EOF
69
70 signoff="Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
71'
72
73test_expect_success setup '
74 echo hello >file &&
75 git add file &&
76 test_tick &&
77 git commit -m first &&
78 git tag first &&
79
80 echo world >>file &&
81 git add file &&
82 test_tick &&
83 git commit -s -F msg &&
84 git tag second &&
85
86 git format-patch --stdout first >patch1 &&
87 {
88 echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
89 echo "X-Fake-Field: Line One" &&
90 echo "X-Fake-Field: Line Two" &&
91 echo "X-Fake-Field: Line Three" &&
92 git format-patch --stdout first | sed -e "1d"
93 } > patch1.eml &&
94 {
95 echo "X-Fake-Field: Line One" &&
96 echo "X-Fake-Field: Line Two" &&
97 echo "X-Fake-Field: Line Three" &&
98 git format-patch --stdout first | sed -e "1d"
99 } | append_cr >patch1-crlf.eml &&
100 {
101 printf "%255s\\n" ""
102 echo "X-Fake-Field: Line One" &&
103 echo "X-Fake-Field: Line Two" &&
104 echo "X-Fake-Field: Line Three" &&
105 git format-patch --stdout first | sed -e "1d"
106 } > patch1-ws.eml &&
107
108 sed -n -e "3,\$p" msg >file &&
109 git add file &&
110 test_tick &&
111 git commit -m third &&
112
113 git format-patch --stdout first >patch2 &&
114
115 git checkout -b lorem &&
116 sed -n -e "11,\$p" msg >file &&
117 head -n 9 msg >>file &&
118 test_tick &&
119 git commit -a -m "moved stuff" &&
120
121 echo goodbye >another &&
122 git add another &&
123 test_tick &&
124 git commit -m "added another file" &&
125
126 git format-patch --stdout master >lorem-move.patch &&
127 git format-patch --no-prefix --stdout master >lorem-zero.patch &&
128
129 git checkout -b rename &&
130 git mv file renamed &&
131 git commit -m "renamed a file" &&
132
133 git format-patch -M --stdout lorem >rename.patch &&
134
135 git reset --soft lorem^ &&
136 git commit -m "renamed a file and added another" &&
137
138 git format-patch -M --stdout lorem^ >rename-add.patch &&
139
140 # reset time
141 sane_unset test_tick &&
142 test_tick
143'
144
145test_expect_success 'am applies patch correctly' '
146 rm -fr .git/rebase-apply &&
147 git reset --hard &&
148 git checkout first &&
149 test_tick &&
150 git am <patch1 &&
151 test_path_is_missing .git/rebase-apply &&
152 git diff --exit-code second &&
153 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
154 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
155'
156
157test_expect_success 'am fails if index is dirty' '
158 test_when_finished "rm -f dirtyfile" &&
159 rm -fr .git/rebase-apply &&
160 git reset --hard &&
161 git checkout first &&
162 echo dirtyfile >dirtyfile &&
163 git add dirtyfile &&
164 test_must_fail git am patch1 &&
165 test_path_is_dir .git/rebase-apply &&
166 test_cmp_rev first HEAD
167'
168
169test_expect_success 'am applies patch e-mail not in a mbox' '
170 rm -fr .git/rebase-apply &&
171 git reset --hard &&
172 git checkout first &&
173 git am patch1.eml &&
174 test_path_is_missing .git/rebase-apply &&
175 git diff --exit-code second &&
176 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
177 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
178'
179
180test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
181 rm -fr .git/rebase-apply &&
182 git reset --hard &&
183 git checkout first &&
184 git am patch1-crlf.eml &&
185 test_path_is_missing .git/rebase-apply &&
186 git diff --exit-code second &&
187 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
188 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
189'
190
191test_expect_success 'am applies patch e-mail with preceding whitespace' '
192 rm -fr .git/rebase-apply &&
193 git reset --hard &&
194 git checkout first &&
195 git am patch1-ws.eml &&
196 test_path_is_missing .git/rebase-apply &&
197 git diff --exit-code second &&
198 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
199 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
200'
201
202test_expect_success 'setup: new author and committer' '
203 GIT_AUTHOR_NAME="Another Thor" &&
204 GIT_AUTHOR_EMAIL="a.thor@example.com" &&
205 GIT_COMMITTER_NAME="Co M Miter" &&
206 GIT_COMMITTER_EMAIL="c.miter@example.com" &&
207 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
208'
209
210compare () {
211 a=$(git cat-file commit "$2" | grep "^$1 ") &&
212 b=$(git cat-file commit "$3" | grep "^$1 ") &&
213 test "$a" = "$b"
214}
215
216test_expect_success 'am changes committer and keeps author' '
217 test_tick &&
218 rm -fr .git/rebase-apply &&
219 git reset --hard &&
220 git checkout first &&
221 git am patch2 &&
222 test_path_is_missing .git/rebase-apply &&
223 test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" &&
224 git diff --exit-code master..HEAD &&
225 git diff --exit-code master^..HEAD^ &&
226 compare author master HEAD &&
227 compare author master^ HEAD^ &&
228 test "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" = \
229 "$(git log -1 --pretty=format:"%cn <%ce>" HEAD)"
230'
231
232test_expect_success 'am --signoff adds Signed-off-by: line' '
233 rm -fr .git/rebase-apply &&
234 git reset --hard &&
235 git checkout -b master2 first &&
236 git am --signoff <patch2 &&
237 printf "%s\n" "$signoff" >expected &&
238 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >>expected &&
239 git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
240 test_cmp expected actual &&
241 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
242 git cat-file commit HEAD | grep "Signed-off-by:" >actual &&
243 test_cmp expected actual
244'
245
246test_expect_success 'am stays in branch' '
247 echo refs/heads/master2 >expected &&
248 git symbolic-ref HEAD >actual &&
249 test_cmp expected actual
250'
251
252test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
253 git format-patch --stdout HEAD^ >patch3 &&
254 sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," patch3 >patch4 &&
255 rm -fr .git/rebase-apply &&
256 git reset --hard &&
257 git checkout HEAD^ &&
258 git am --signoff patch4 &&
259 git cat-file commit HEAD >actual &&
260 test $(grep -c "^Signed-off-by:" actual) -eq 1
261'
262
263test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
264 git rev-parse HEAD >expected &&
265 git rev-parse master2 >actual &&
266 test_cmp expected actual
267'
268
269test_expect_success 'am --keep really keeps the subject' '
270 rm -fr .git/rebase-apply &&
271 git reset --hard &&
272 git checkout HEAD^ &&
273 git am --keep patch4 &&
274 test_path_is_missing .git/rebase-apply &&
275 git cat-file commit HEAD >actual &&
276 grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual
277'
278
279test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
280 rm -fr .git/rebase-apply &&
281 git reset --hard &&
282 git checkout HEAD^ &&
283 git am --keep-non-patch patch4 &&
284 test_path_is_missing .git/rebase-apply &&
285 git cat-file commit HEAD >actual &&
286 grep "^\[foo\] third" actual
287'
288
289test_expect_success 'setup am -3' '
290 rm -fr .git/rebase-apply &&
291 git reset --hard &&
292 git checkout -b base3way master2 &&
293 sed -n -e "3,\$p" msg >file &&
294 head -n 9 msg >>file &&
295 git add file &&
296 test_tick &&
297 git commit -m "copied stuff"
298'
299
300test_expect_success 'am -3 falls back to 3-way merge' '
301 rm -fr .git/rebase-apply &&
302 git reset --hard &&
303 git checkout -b lorem2 base3way &&
304 git am -3 lorem-move.patch &&
305 test_path_is_missing .git/rebase-apply &&
306 git diff --exit-code lorem
307'
308
309test_expect_success 'am -3 -p0 can read --no-prefix patch' '
310 rm -fr .git/rebase-apply &&
311 git reset --hard &&
312 git checkout -b lorem3 base3way &&
313 git am -3 -p0 lorem-zero.patch &&
314 test_path_is_missing .git/rebase-apply &&
315 git diff --exit-code lorem
316'
317
318test_expect_success 'am with config am.threeWay falls back to 3-way merge' '
319 rm -fr .git/rebase-apply &&
320 git reset --hard &&
321 git checkout -b lorem4 base3way &&
322 test_config am.threeWay 1 &&
323 git am lorem-move.patch &&
324 test_path_is_missing .git/rebase-apply &&
325 git diff --exit-code lorem
326'
327
328test_expect_success 'am with config am.threeWay overridden by --no-3way' '
329 rm -fr .git/rebase-apply &&
330 git reset --hard &&
331 git checkout -b lorem5 base3way &&
332 test_config am.threeWay 1 &&
333 test_must_fail git am --no-3way lorem-move.patch &&
334 test_path_is_dir .git/rebase-apply
335'
336
337test_expect_success 'am can rename a file' '
338 grep "^rename from" rename.patch &&
339 rm -fr .git/rebase-apply &&
340 git reset --hard &&
341 git checkout lorem^0 &&
342 git am rename.patch &&
343 test_path_is_missing .git/rebase-apply &&
344 git update-index --refresh &&
345 git diff --exit-code rename
346'
347
348test_expect_success 'am -3 can rename a file' '
349 grep "^rename from" rename.patch &&
350 rm -fr .git/rebase-apply &&
351 git reset --hard &&
352 git checkout lorem^0 &&
353 git am -3 rename.patch &&
354 test_path_is_missing .git/rebase-apply &&
355 git update-index --refresh &&
356 git diff --exit-code rename
357'
358
359test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
360 grep "^rename from" rename-add.patch &&
361 rm -fr .git/rebase-apply &&
362 git reset --hard &&
363 git checkout lorem^0 &&
364 git am -3 rename-add.patch &&
365 test_path_is_missing .git/rebase-apply &&
366 git update-index --refresh &&
367 git diff --exit-code rename
368'
369
370test_expect_success 'am -3 -q is quiet' '
371 rm -fr .git/rebase-apply &&
372 git checkout -f lorem2 &&
373 git reset base3way --hard &&
374 git am -3 -q lorem-move.patch >output.out 2>&1 &&
375 ! test -s output.out
376'
377
378test_expect_success 'am pauses on conflict' '
379 rm -fr .git/rebase-apply &&
380 git reset --hard &&
381 git checkout lorem2^^ &&
382 test_must_fail git am lorem-move.patch &&
383 test -d .git/rebase-apply
384'
385
386test_expect_success 'am --skip works' '
387 echo goodbye >expected &&
388 git am --skip &&
389 test_path_is_missing .git/rebase-apply &&
390 git diff --exit-code lorem2^^ -- file &&
391 test_cmp expected another
392'
393
394test_expect_success 'am --abort removes a stray directory' '
395 mkdir .git/rebase-apply &&
396 git am --abort &&
397 test_path_is_missing .git/rebase-apply
398'
399
400test_expect_success 'am refuses patches when paused' '
401 rm -fr .git/rebase-apply &&
402 git reset --hard &&
403 git checkout lorem2^^ &&
404
405 test_must_fail git am lorem-move.patch &&
406 test_path_is_dir .git/rebase-apply &&
407 test_cmp_rev lorem2^^ HEAD &&
408
409 test_must_fail git am <lorem-move.patch &&
410 test_path_is_dir .git/rebase-apply &&
411 test_cmp_rev lorem2^^ HEAD
412'
413
414test_expect_success 'am --resolved works' '
415 echo goodbye >expected &&
416 rm -fr .git/rebase-apply &&
417 git reset --hard &&
418 git checkout lorem2^^ &&
419 test_must_fail git am lorem-move.patch &&
420 test -d .git/rebase-apply &&
421 echo resolved >>file &&
422 git add file &&
423 git am --resolved &&
424 test_path_is_missing .git/rebase-apply &&
425 test_cmp expected another
426'
427
428test_expect_success 'am --resolved fails if index has no changes' '
429 rm -fr .git/rebase-apply &&
430 git reset --hard &&
431 git checkout lorem2^^ &&
432 test_must_fail git am lorem-move.patch &&
433 test_path_is_dir .git/rebase-apply &&
434 test_cmp_rev lorem2^^ HEAD &&
435 test_must_fail git am --resolved &&
436 test_path_is_dir .git/rebase-apply &&
437 test_cmp_rev lorem2^^ HEAD
438'
439
440test_expect_success 'am --resolved fails if index has unmerged entries' '
441 rm -fr .git/rebase-apply &&
442 git reset --hard &&
443 git checkout second &&
444 test_must_fail git am -3 lorem-move.patch &&
445 test_path_is_dir .git/rebase-apply &&
446 test_cmp_rev second HEAD &&
447 test_must_fail git am --resolved >err &&
448 test_path_is_dir .git/rebase-apply &&
449 test_cmp_rev second HEAD &&
450 test_i18ngrep "still have unmerged paths" err
451'
452
453test_expect_success 'am takes patches from a Pine mailbox' '
454 rm -fr .git/rebase-apply &&
455 git reset --hard &&
456 git checkout first &&
457 cat pine patch1 | git am &&
458 test_path_is_missing .git/rebase-apply &&
459 git diff --exit-code master^..HEAD
460'
461
462test_expect_success 'am fails on mail without patch' '
463 rm -fr .git/rebase-apply &&
464 git reset --hard &&
465 test_must_fail git am <failmail &&
466 git am --abort &&
467 test_path_is_missing .git/rebase-apply
468'
469
470test_expect_success 'am fails on empty patch' '
471 rm -fr .git/rebase-apply &&
472 git reset --hard &&
473 echo "---" >>failmail &&
474 test_must_fail git am <failmail &&
475 git am --skip &&
476 test_path_is_missing .git/rebase-apply
477'
478
479test_expect_success 'am works from stdin in subdirectory' '
480 rm -fr subdir &&
481 rm -fr .git/rebase-apply &&
482 git reset --hard &&
483 git checkout first &&
484 (
485 mkdir -p subdir &&
486 cd subdir &&
487 git am <../patch1
488 ) &&
489 git diff --exit-code second
490'
491
492test_expect_success 'am works from file (relative path given) in subdirectory' '
493 rm -fr subdir &&
494 rm -fr .git/rebase-apply &&
495 git reset --hard &&
496 git checkout first &&
497 (
498 mkdir -p subdir &&
499 cd subdir &&
500 git am ../patch1
501 ) &&
502 git diff --exit-code second
503'
504
505test_expect_success 'am works from file (absolute path given) in subdirectory' '
506 rm -fr subdir &&
507 rm -fr .git/rebase-apply &&
508 git reset --hard &&
509 git checkout first &&
510 P=$(pwd) &&
511 (
512 mkdir -p subdir &&
513 cd subdir &&
514 git am "$P/patch1"
515 ) &&
516 git diff --exit-code second
517'
518
519test_expect_success 'am --committer-date-is-author-date' '
520 rm -fr .git/rebase-apply &&
521 git reset --hard &&
522 git checkout first &&
523 test_tick &&
524 git am --committer-date-is-author-date patch1 &&
525 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
526 sed -ne "/^author /s/.*> //p" head1 >at &&
527 sed -ne "/^committer /s/.*> //p" head1 >ct &&
528 test_cmp at ct
529'
530
531test_expect_success 'am without --committer-date-is-author-date' '
532 rm -fr .git/rebase-apply &&
533 git reset --hard &&
534 git checkout first &&
535 test_tick &&
536 git am patch1 &&
537 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
538 sed -ne "/^author /s/.*> //p" head1 >at &&
539 sed -ne "/^committer /s/.*> //p" head1 >ct &&
540 ! test_cmp at ct
541'
542
543# This checks for +0000 because TZ is set to UTC and that should
544# show up when the current time is used. The date in message is set
545# by test_tick that uses -0700 timezone; if this feature does not
546# work, we will see that instead of +0000.
547test_expect_success 'am --ignore-date' '
548 rm -fr .git/rebase-apply &&
549 git reset --hard &&
550 git checkout first &&
551 test_tick &&
552 git am --ignore-date patch1 &&
553 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
554 sed -ne "/^author /s/.*> //p" head1 >at &&
555 grep "+0000" at
556'
557
558test_expect_success 'am into an unborn branch' '
559 git rev-parse first^{tree} >expected &&
560 rm -fr .git/rebase-apply &&
561 git reset --hard &&
562 rm -fr subdir &&
563 mkdir subdir &&
564 git format-patch --numbered-files -o subdir -1 first &&
565 (
566 cd subdir &&
567 git init &&
568 git am 1
569 ) &&
570 (
571 cd subdir &&
572 git rev-parse HEAD^{tree} >../actual
573 ) &&
574 test_cmp expected actual
575'
576
577test_expect_success 'am newline in subject' '
578 rm -fr .git/rebase-apply &&
579 git reset --hard &&
580 git checkout first &&
581 test_tick &&
582 sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
583 git am <patchnl >output.out 2>&1 &&
584 test_i18ngrep "^Applying: second \\\n foo$" output.out
585'
586
587test_expect_success 'am -q is quiet' '
588 rm -fr .git/rebase-apply &&
589 git reset --hard &&
590 git checkout first &&
591 test_tick &&
592 git am -q <patch1 >output.out 2>&1 &&
593 ! test -s output.out
594'
595
596test_expect_success 'am empty-file does not infloop' '
597 rm -fr .git/rebase-apply &&
598 git reset --hard &&
599 touch empty-file &&
600 test_tick &&
601 test_must_fail git am empty-file 2>actual &&
602 echo Patch format detection failed. >expected &&
603 test_i18ncmp expected actual
604'
605
606test_expect_success 'am --message-id really adds the message id' '
607 rm -fr .git/rebase-apply &&
608 git reset --hard &&
609 git checkout HEAD^ &&
610 git am --message-id patch1.eml &&
611 test_path_is_missing .git/rebase-apply &&
612 git cat-file commit HEAD | tail -n1 >actual &&
613 grep Message-Id patch1.eml >expected &&
614 test_cmp expected actual
615'
616
617test_expect_success 'am.messageid really adds the message id' '
618 rm -fr .git/rebase-apply &&
619 git reset --hard &&
620 git checkout HEAD^ &&
621 test_config am.messageid true &&
622 git am patch1.eml &&
623 test_path_is_missing .git/rebase-apply &&
624 git cat-file commit HEAD | tail -n1 >actual &&
625 grep Message-Id patch1.eml >expected &&
626 test_cmp expected actual
627'
628
629test_expect_success 'am --message-id -s signs off after the message id' '
630 rm -fr .git/rebase-apply &&
631 git reset --hard &&
632 git checkout HEAD^ &&
633 git am -s --message-id patch1.eml &&
634 test_path_is_missing .git/rebase-apply &&
635 git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
636 grep Message-Id patch1.eml >expected &&
637 test_cmp expected actual
638'
639
640test_done