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