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