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 -ne "1p" msg &&
109 echo &&
110 echo "From: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" &&
111 echo "Date: $GIT_AUTHOR_DATE" &&
112 echo &&
113 sed -e "1,2d" msg &&
114 echo &&
115 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
116 echo "---" &&
117 git diff-tree --no-commit-id --stat -p second
118 } >patch1-stgit.eml &&
119 mkdir stgit-series &&
120 cp patch1-stgit.eml stgit-series/patch &&
121 {
122 echo "# This series applies on GIT commit $(git rev-parse first)" &&
123 echo "patch"
124 } >stgit-series/series &&
125 {
126 echo "# HG changeset patch" &&
127 echo "# User $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" &&
128 echo "# Date $test_tick 25200" &&
129 echo "# $(git show --pretty="%aD" -s second)" &&
130 echo "# Node ID $_z40" &&
131 echo "# Parent $_z40" &&
132 cat msg &&
133 echo &&
134 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
135 echo &&
136 git diff-tree --no-commit-id -p second
137 } >patch1-hg.eml &&
138
139
140 sed -n -e "3,\$p" msg >file &&
141 git add file &&
142 test_tick &&
143 git commit -m third &&
144
145 git format-patch --stdout first >patch2 &&
146
147 git checkout -b lorem &&
148 sed -n -e "11,\$p" msg >file &&
149 head -n 9 msg >>file &&
150 test_tick &&
151 git commit -a -m "moved stuff" &&
152
153 echo goodbye >another &&
154 git add another &&
155 test_tick &&
156 git commit -m "added another file" &&
157
158 git format-patch --stdout master >lorem-move.patch &&
159 git format-patch --no-prefix --stdout master >lorem-zero.patch &&
160
161 git checkout -b rename &&
162 git mv file renamed &&
163 git commit -m "renamed a file" &&
164
165 git format-patch -M --stdout lorem >rename.patch &&
166
167 git reset --soft lorem^ &&
168 git commit -m "renamed a file and added another" &&
169
170 git format-patch -M --stdout lorem^ >rename-add.patch &&
171
172 # reset time
173 sane_unset test_tick &&
174 test_tick
175'
176
177test_expect_success 'am applies patch correctly' '
178 rm -fr .git/rebase-apply &&
179 git reset --hard &&
180 git checkout first &&
181 test_tick &&
182 git am <patch1 &&
183 test_path_is_missing .git/rebase-apply &&
184 git diff --exit-code second &&
185 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
186 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
187'
188
189test_expect_success 'am applies patch e-mail not in a mbox' '
190 rm -fr .git/rebase-apply &&
191 git reset --hard &&
192 git checkout first &&
193 git am patch1.eml &&
194 test_path_is_missing .git/rebase-apply &&
195 git diff --exit-code second &&
196 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
197 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
198'
199
200test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
201 rm -fr .git/rebase-apply &&
202 git reset --hard &&
203 git checkout first &&
204 git am patch1-crlf.eml &&
205 test_path_is_missing .git/rebase-apply &&
206 git diff --exit-code second &&
207 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
208 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
209'
210
211test_expect_success 'am applies patch e-mail with preceding whitespace' '
212 rm -fr .git/rebase-apply &&
213 git reset --hard &&
214 git checkout first &&
215 git am patch1-ws.eml &&
216 test_path_is_missing .git/rebase-apply &&
217 git diff --exit-code second &&
218 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
219 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
220'
221
222test_expect_success 'am applies stgit patch' '
223 rm -fr .git/rebase-apply &&
224 git checkout -f first &&
225 git am patch1-stgit.eml &&
226 test_path_is_missing .git/rebase-apply &&
227 git diff --exit-code second &&
228 test_cmp_rev second HEAD &&
229 test_cmp_rev second^ HEAD^
230'
231
232test_expect_success 'am --patch-format=stgit applies stgit patch' '
233 rm -fr .git/rebase-apply &&
234 git checkout -f first &&
235 git am --patch-format=stgit <patch1-stgit.eml &&
236 test_path_is_missing .git/rebase-apply &&
237 git diff --exit-code second &&
238 test_cmp_rev second HEAD &&
239 test_cmp_rev second^ HEAD^
240'
241
242test_expect_success 'am applies stgit series' '
243 rm -fr .git/rebase-apply &&
244 git checkout -f first &&
245 git am stgit-series/series &&
246 test_path_is_missing .git/rebase-apply &&
247 git diff --exit-code second &&
248 test_cmp_rev second HEAD &&
249 test_cmp_rev second^ HEAD^
250'
251
252test_expect_success 'am applies hg patch' '
253 rm -fr .git/rebase-apply &&
254 git checkout -f first &&
255 git am patch1-hg.eml &&
256 test_path_is_missing .git/rebase-apply &&
257 git diff --exit-code second &&
258 test_cmp_rev second HEAD &&
259 test_cmp_rev second^ HEAD^
260'
261
262test_expect_success 'am --patch-format=hg applies hg patch' '
263 rm -fr .git/rebase-apply &&
264 git checkout -f first &&
265 git am --patch-format=hg <patch1-hg.eml &&
266 test_path_is_missing .git/rebase-apply &&
267 git diff --exit-code second &&
268 test_cmp_rev second HEAD &&
269 test_cmp_rev second^ HEAD^
270'
271
272test_expect_success 'setup: new author and committer' '
273 GIT_AUTHOR_NAME="Another Thor" &&
274 GIT_AUTHOR_EMAIL="a.thor@example.com" &&
275 GIT_COMMITTER_NAME="Co M Miter" &&
276 GIT_COMMITTER_EMAIL="c.miter@example.com" &&
277 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
278'
279
280compare () {
281 a=$(git cat-file commit "$2" | grep "^$1 ") &&
282 b=$(git cat-file commit "$3" | grep "^$1 ") &&
283 test "$a" = "$b"
284}
285
286test_expect_success 'am changes committer and keeps author' '
287 test_tick &&
288 rm -fr .git/rebase-apply &&
289 git reset --hard &&
290 git checkout first &&
291 git am patch2 &&
292 test_path_is_missing .git/rebase-apply &&
293 test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" &&
294 git diff --exit-code master..HEAD &&
295 git diff --exit-code master^..HEAD^ &&
296 compare author master HEAD &&
297 compare author master^ HEAD^ &&
298 test "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" = \
299 "$(git log -1 --pretty=format:"%cn <%ce>" HEAD)"
300'
301
302test_expect_success 'am --signoff adds Signed-off-by: line' '
303 rm -fr .git/rebase-apply &&
304 git reset --hard &&
305 git checkout -b master2 first &&
306 git am --signoff <patch2 &&
307 printf "%s\n" "$signoff" >expected &&
308 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >>expected &&
309 git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
310 test_cmp expected actual &&
311 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
312 git cat-file commit HEAD | grep "Signed-off-by:" >actual &&
313 test_cmp expected actual
314'
315
316test_expect_success 'am stays in branch' '
317 echo refs/heads/master2 >expected &&
318 git symbolic-ref HEAD >actual &&
319 test_cmp expected actual
320'
321
322test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
323 git format-patch --stdout HEAD^ >patch3 &&
324 sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," patch3 >patch4 &&
325 rm -fr .git/rebase-apply &&
326 git reset --hard &&
327 git checkout HEAD^ &&
328 git am --signoff patch4 &&
329 git cat-file commit HEAD >actual &&
330 test $(grep -c "^Signed-off-by:" actual) -eq 1
331'
332
333test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
334 git rev-parse HEAD >expected &&
335 git rev-parse master2 >actual &&
336 test_cmp expected actual
337'
338
339test_expect_success 'am --keep really keeps the subject' '
340 rm -fr .git/rebase-apply &&
341 git reset --hard &&
342 git checkout HEAD^ &&
343 git am --keep patch4 &&
344 test_path_is_missing .git/rebase-apply &&
345 git cat-file commit HEAD >actual &&
346 grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual
347'
348
349test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
350 rm -fr .git/rebase-apply &&
351 git reset --hard &&
352 git checkout HEAD^ &&
353 git am --keep-non-patch patch4 &&
354 test_path_is_missing .git/rebase-apply &&
355 git cat-file commit HEAD >actual &&
356 grep "^\[foo\] third" actual
357'
358
359test_expect_success 'am -3 falls back to 3-way merge' '
360 rm -fr .git/rebase-apply &&
361 git reset --hard &&
362 git checkout -b lorem2 master2 &&
363 sed -n -e "3,\$p" msg >file &&
364 head -n 9 msg >>file &&
365 git add file &&
366 test_tick &&
367 git commit -m "copied stuff" &&
368 git am -3 lorem-move.patch &&
369 test_path_is_missing .git/rebase-apply &&
370 git diff --exit-code lorem
371'
372
373test_expect_success 'am -3 -p0 can read --no-prefix patch' '
374 rm -fr .git/rebase-apply &&
375 git reset --hard &&
376 git checkout -b lorem3 master2 &&
377 sed -n -e "3,\$p" msg >file &&
378 head -n 9 msg >>file &&
379 git add file &&
380 test_tick &&
381 git commit -m "copied stuff" &&
382 git am -3 -p0 lorem-zero.patch &&
383 test_path_is_missing .git/rebase-apply &&
384 git diff --exit-code lorem
385'
386
387test_expect_success 'am can rename a file' '
388 grep "^rename from" rename.patch &&
389 rm -fr .git/rebase-apply &&
390 git reset --hard &&
391 git checkout lorem^0 &&
392 git am rename.patch &&
393 test_path_is_missing .git/rebase-apply &&
394 git update-index --refresh &&
395 git diff --exit-code rename
396'
397
398test_expect_success 'am -3 can rename a file' '
399 grep "^rename from" rename.patch &&
400 rm -fr .git/rebase-apply &&
401 git reset --hard &&
402 git checkout lorem^0 &&
403 git am -3 rename.patch &&
404 test_path_is_missing .git/rebase-apply &&
405 git update-index --refresh &&
406 git diff --exit-code rename
407'
408
409test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
410 grep "^rename from" rename-add.patch &&
411 rm -fr .git/rebase-apply &&
412 git reset --hard &&
413 git checkout lorem^0 &&
414 git am -3 rename-add.patch &&
415 test_path_is_missing .git/rebase-apply &&
416 git update-index --refresh &&
417 git diff --exit-code rename
418'
419
420test_expect_success 'am -3 -q is quiet' '
421 rm -fr .git/rebase-apply &&
422 git checkout -f lorem2 &&
423 git reset master2 --hard &&
424 sed -n -e "3,\$p" msg >file &&
425 head -n 9 msg >>file &&
426 git add file &&
427 test_tick &&
428 git commit -m "copied stuff" &&
429 git am -3 -q lorem-move.patch >output.out 2>&1 &&
430 ! test -s output.out
431'
432
433test_expect_success 'am pauses on conflict' '
434 rm -fr .git/rebase-apply &&
435 git reset --hard &&
436 git checkout lorem2^^ &&
437 test_must_fail git am lorem-move.patch &&
438 test -d .git/rebase-apply
439'
440
441test_expect_success 'am --skip works' '
442 echo goodbye >expected &&
443 git am --skip &&
444 test_path_is_missing .git/rebase-apply &&
445 git diff --exit-code lorem2^^ -- file &&
446 test_cmp expected another
447'
448
449test_expect_success 'am --abort removes a stray directory' '
450 mkdir .git/rebase-apply &&
451 git am --abort &&
452 test_path_is_missing .git/rebase-apply
453'
454
455test_expect_success 'am --resolved works' '
456 echo goodbye >expected &&
457 rm -fr .git/rebase-apply &&
458 git reset --hard &&
459 git checkout lorem2^^ &&
460 test_must_fail git am lorem-move.patch &&
461 test -d .git/rebase-apply &&
462 echo resolved >>file &&
463 git add file &&
464 git am --resolved &&
465 test_path_is_missing .git/rebase-apply &&
466 test_cmp expected another
467'
468
469test_expect_success 'am takes patches from a Pine mailbox' '
470 rm -fr .git/rebase-apply &&
471 git reset --hard &&
472 git checkout first &&
473 cat pine patch1 | git am &&
474 test_path_is_missing .git/rebase-apply &&
475 git diff --exit-code master^..HEAD
476'
477
478test_expect_success 'am fails on mail without patch' '
479 rm -fr .git/rebase-apply &&
480 git reset --hard &&
481 test_must_fail git am <failmail &&
482 git am --abort &&
483 test_path_is_missing .git/rebase-apply
484'
485
486test_expect_success 'am fails on empty patch' '
487 rm -fr .git/rebase-apply &&
488 git reset --hard &&
489 echo "---" >>failmail &&
490 test_must_fail git am <failmail &&
491 git am --skip &&
492 test_path_is_missing .git/rebase-apply
493'
494
495test_expect_success 'am works from stdin in subdirectory' '
496 rm -fr subdir &&
497 rm -fr .git/rebase-apply &&
498 git reset --hard &&
499 git checkout first &&
500 (
501 mkdir -p subdir &&
502 cd subdir &&
503 git am <../patch1
504 ) &&
505 git diff --exit-code second
506'
507
508test_expect_success 'am works from file (relative path given) in subdirectory' '
509 rm -fr subdir &&
510 rm -fr .git/rebase-apply &&
511 git reset --hard &&
512 git checkout first &&
513 (
514 mkdir -p subdir &&
515 cd subdir &&
516 git am ../patch1
517 ) &&
518 git diff --exit-code second
519'
520
521test_expect_success 'am works from file (absolute path given) in subdirectory' '
522 rm -fr subdir &&
523 rm -fr .git/rebase-apply &&
524 git reset --hard &&
525 git checkout first &&
526 P=$(pwd) &&
527 (
528 mkdir -p subdir &&
529 cd subdir &&
530 git am "$P/patch1"
531 ) &&
532 git diff --exit-code second
533'
534
535test_expect_success 'am --committer-date-is-author-date' '
536 rm -fr .git/rebase-apply &&
537 git reset --hard &&
538 git checkout first &&
539 test_tick &&
540 git am --committer-date-is-author-date patch1 &&
541 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
542 sed -ne "/^author /s/.*> //p" head1 >at &&
543 sed -ne "/^committer /s/.*> //p" head1 >ct &&
544 test_cmp at ct
545'
546
547test_expect_success 'am without --committer-date-is-author-date' '
548 rm -fr .git/rebase-apply &&
549 git reset --hard &&
550 git checkout first &&
551 test_tick &&
552 git am patch1 &&
553 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
554 sed -ne "/^author /s/.*> //p" head1 >at &&
555 sed -ne "/^committer /s/.*> //p" head1 >ct &&
556 ! test_cmp at ct
557'
558
559# This checks for +0000 because TZ is set to UTC and that should
560# show up when the current time is used. The date in message is set
561# by test_tick that uses -0700 timezone; if this feature does not
562# work, we will see that instead of +0000.
563test_expect_success 'am --ignore-date' '
564 rm -fr .git/rebase-apply &&
565 git reset --hard &&
566 git checkout first &&
567 test_tick &&
568 git am --ignore-date patch1 &&
569 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
570 sed -ne "/^author /s/.*> //p" head1 >at &&
571 grep "+0000" at
572'
573
574test_expect_success 'am into an unborn branch' '
575 git rev-parse first^{tree} >expected &&
576 rm -fr .git/rebase-apply &&
577 git reset --hard &&
578 rm -fr subdir &&
579 mkdir subdir &&
580 git format-patch --numbered-files -o subdir -1 first &&
581 (
582 cd subdir &&
583 git init &&
584 git am 1
585 ) &&
586 (
587 cd subdir &&
588 git rev-parse HEAD^{tree} >../actual
589 ) &&
590 test_cmp expected actual
591'
592
593test_expect_success 'am newline in subject' '
594 rm -fr .git/rebase-apply &&
595 git reset --hard &&
596 git checkout first &&
597 test_tick &&
598 sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
599 git am <patchnl >output.out 2>&1 &&
600 test_i18ngrep "^Applying: second \\\n foo$" output.out
601'
602
603test_expect_success 'am -q is quiet' '
604 rm -fr .git/rebase-apply &&
605 git reset --hard &&
606 git checkout first &&
607 test_tick &&
608 git am -q <patch1 >output.out 2>&1 &&
609 ! test -s output.out
610'
611
612test_expect_success 'am empty-file does not infloop' '
613 rm -fr .git/rebase-apply &&
614 git reset --hard &&
615 touch empty-file &&
616 test_tick &&
617 test_must_fail git am empty-file 2>actual &&
618 echo Patch format detection failed. >expected &&
619 test_i18ncmp expected actual
620'
621
622test_expect_success 'am --message-id really adds the message id' '
623 rm -fr .git/rebase-apply &&
624 git reset --hard &&
625 git checkout HEAD^ &&
626 git am --message-id patch1.eml &&
627 test_path_is_missing .git/rebase-apply &&
628 git cat-file commit HEAD | tail -n1 >actual &&
629 grep Message-Id patch1.eml >expected &&
630 test_cmp expected actual
631'
632
633test_expect_success 'am --message-id -s signs off after the message id' '
634 rm -fr .git/rebase-apply &&
635 git reset --hard &&
636 git checkout HEAD^ &&
637 git am -s --message-id patch1.eml &&
638 test_path_is_missing .git/rebase-apply &&
639 git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
640 grep Message-Id patch1.eml >expected &&
641 test_cmp expected actual
642'
643
644test_done