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 q_to_tab <<-\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 "X-Fake-Field: Line One" &&
89 echo "X-Fake-Field: Line Two" &&
90 echo "X-Fake-Field: Line Three" &&
91 git format-patch --stdout first | sed -e "1d"
92 } > patch1.eml &&
93 {
94 echo "X-Fake-Field: Line One" &&
95 echo "X-Fake-Field: Line Two" &&
96 echo "X-Fake-Field: Line Three" &&
97 git format-patch --stdout first | sed -e "1d"
98 } | append_cr >patch1-crlf.eml &&
99 {
100 printf "%255s\\n" ""
101 echo "X-Fake-Field: Line One" &&
102 echo "X-Fake-Field: Line Two" &&
103 echo "X-Fake-Field: Line Three" &&
104 git format-patch --stdout first | sed -e "1d"
105 } > patch1-ws.eml &&
106
107 sed -n -e "3,\$p" msg >file &&
108 git add file &&
109 test_tick &&
110 git commit -m third &&
111
112 git format-patch --stdout first >patch2 &&
113
114 git checkout -b lorem &&
115 sed -n -e "11,\$p" msg >file &&
116 head -n 9 msg >>file &&
117 test_tick &&
118 git commit -a -m "moved stuff" &&
119
120 echo goodbye >another &&
121 git add another &&
122 test_tick &&
123 git commit -m "added another file" &&
124
125 git format-patch --stdout master >lorem-move.patch &&
126
127 git checkout -b rename &&
128 git mv file renamed &&
129 git commit -m "renamed a file" &&
130
131 git format-patch -M --stdout lorem >rename.patch &&
132
133 git reset --soft lorem^ &&
134 git commit -m "renamed a file and added another" &&
135
136 git format-patch -M --stdout lorem^ >rename-add.patch &&
137
138 # reset time
139 sane_unset test_tick &&
140 test_tick
141'
142
143test_expect_success 'am applies patch correctly' '
144 rm -fr .git/rebase-apply &&
145 git reset --hard &&
146 git checkout first &&
147 test_tick &&
148 git am <patch1 &&
149 ! test -d .git/rebase-apply &&
150 git diff --exit-code second &&
151 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
152 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
153'
154
155test_expect_success 'am applies patch e-mail not in a mbox' '
156 rm -fr .git/rebase-apply &&
157 git reset --hard &&
158 git checkout first &&
159 git am patch1.eml &&
160 ! test -d .git/rebase-apply &&
161 git diff --exit-code second &&
162 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
163 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
164'
165
166test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
167 rm -fr .git/rebase-apply &&
168 git reset --hard &&
169 git checkout first &&
170 git am patch1-crlf.eml &&
171 ! test -d .git/rebase-apply &&
172 git diff --exit-code second &&
173 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
174 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
175'
176
177test_expect_success 'am applies patch e-mail with preceding whitespace' '
178 rm -fr .git/rebase-apply &&
179 git reset --hard &&
180 git checkout first &&
181 git am patch1-ws.eml &&
182 ! test -d .git/rebase-apply &&
183 git diff --exit-code second &&
184 test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
185 test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
186'
187
188test_expect_success 'setup: new author and committer' '
189 GIT_AUTHOR_NAME="Another Thor" &&
190 GIT_AUTHOR_EMAIL="a.thor@example.com" &&
191 GIT_COMMITTER_NAME="Co M Miter" &&
192 GIT_COMMITTER_EMAIL="c.miter@example.com" &&
193 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
194'
195
196compare () {
197 a=$(git cat-file commit "$2" | grep "^$1 ") &&
198 b=$(git cat-file commit "$3" | grep "^$1 ") &&
199 test "$a" = "$b"
200}
201
202test_expect_success 'am changes committer and keeps author' '
203 test_tick &&
204 rm -fr .git/rebase-apply &&
205 git reset --hard &&
206 git checkout first &&
207 git am patch2 &&
208 ! test -d .git/rebase-apply &&
209 test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" &&
210 git diff --exit-code master..HEAD &&
211 git diff --exit-code master^..HEAD^ &&
212 compare author master HEAD &&
213 compare author master^ HEAD^ &&
214 test "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" = \
215 "$(git log -1 --pretty=format:"%cn <%ce>" HEAD)"
216'
217
218test_expect_success 'am --signoff adds Signed-off-by: line' '
219 rm -fr .git/rebase-apply &&
220 git reset --hard &&
221 git checkout -b master2 first &&
222 git am --signoff <patch2 &&
223 printf "%s\n" "$signoff" >expected &&
224 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >>expected &&
225 git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
226 test_cmp expected actual &&
227 echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
228 git cat-file commit HEAD | grep "Signed-off-by:" >actual &&
229 test_cmp expected actual
230'
231
232test_expect_success 'am stays in branch' '
233 echo refs/heads/master2 >expected &&
234 git symbolic-ref HEAD >actual &&
235 test_cmp expected actual
236'
237
238test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
239 git format-patch --stdout HEAD^ >patch3 &&
240 sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4 &&
241 rm -fr .git/rebase-apply &&
242 git reset --hard &&
243 git checkout HEAD^ &&
244 git am --signoff patch4 &&
245 git cat-file commit HEAD >actual &&
246 test $(grep -c "^Signed-off-by:" actual) -eq 1
247'
248
249test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
250 git rev-parse HEAD >expected &&
251 git rev-parse master2 >actual &&
252 test_cmp expected actual
253'
254
255test_expect_success 'am --keep really keeps the subject' '
256 rm -fr .git/rebase-apply &&
257 git reset --hard &&
258 git checkout HEAD^ &&
259 git am --keep patch4 &&
260 ! test -d .git/rebase-apply &&
261 git cat-file commit HEAD >actual &&
262 grep "Re: Re: Re: \[PATCH 1/5 v2\] third" actual
263'
264
265test_expect_success 'am -3 falls back to 3-way merge' '
266 rm -fr .git/rebase-apply &&
267 git reset --hard &&
268 git checkout -b lorem2 master2 &&
269 sed -n -e "3,\$p" msg >file &&
270 head -n 9 msg >>file &&
271 git add file &&
272 test_tick &&
273 git commit -m "copied stuff" &&
274 git am -3 lorem-move.patch &&
275 ! test -d .git/rebase-apply &&
276 git diff --exit-code lorem
277'
278
279test_expect_success 'am can rename a file' '
280 grep "^rename from" rename.patch &&
281 rm -fr .git/rebase-apply &&
282 git reset --hard &&
283 git checkout lorem^0 &&
284 git am rename.patch &&
285 ! test -d .git/rebase-apply &&
286 git update-index --refresh &&
287 git diff --exit-code rename
288'
289
290test_expect_success 'am -3 can rename a file' '
291 grep "^rename from" rename.patch &&
292 rm -fr .git/rebase-apply &&
293 git reset --hard &&
294 git checkout lorem^0 &&
295 git am -3 rename.patch &&
296 ! test -d .git/rebase-apply &&
297 git update-index --refresh &&
298 git diff --exit-code rename
299'
300
301test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
302 grep "^rename from" rename-add.patch &&
303 rm -fr .git/rebase-apply &&
304 git reset --hard &&
305 git checkout lorem^0 &&
306 git am -3 rename-add.patch &&
307 ! test -d .git/rebase-apply &&
308 git update-index --refresh &&
309 git diff --exit-code rename
310'
311
312test_expect_success 'am -3 -q is quiet' '
313 rm -fr .git/rebase-apply &&
314 git checkout -f lorem2 &&
315 git reset master2 --hard &&
316 sed -n -e "3,\$p" msg >file &&
317 head -n 9 msg >>file &&
318 git add file &&
319 test_tick &&
320 git commit -m "copied stuff" &&
321 git am -3 -q lorem-move.patch >output.out 2>&1 &&
322 ! test -s output.out
323'
324
325test_expect_success 'am pauses on conflict' '
326 rm -fr .git/rebase-apply &&
327 git reset --hard &&
328 git checkout lorem2^^ &&
329 test_must_fail git am lorem-move.patch &&
330 test -d .git/rebase-apply
331'
332
333test_expect_success 'am --skip works' '
334 echo goodbye >expected &&
335 git am --skip &&
336 ! test -d .git/rebase-apply &&
337 git diff --exit-code lorem2^^ -- file &&
338 test_cmp expected another
339'
340
341test_expect_success 'am --resolved works' '
342 echo goodbye >expected &&
343 rm -fr .git/rebase-apply &&
344 git reset --hard &&
345 git checkout lorem2^^ &&
346 test_must_fail git am lorem-move.patch &&
347 test -d .git/rebase-apply &&
348 echo resolved >>file &&
349 git add file &&
350 git am --resolved &&
351 ! test -d .git/rebase-apply &&
352 test_cmp expected another
353'
354
355test_expect_success 'am takes patches from a Pine mailbox' '
356 rm -fr .git/rebase-apply &&
357 git reset --hard &&
358 git checkout first &&
359 cat pine patch1 | git am &&
360 ! test -d .git/rebase-apply &&
361 git diff --exit-code master^..HEAD
362'
363
364test_expect_success 'am fails on mail without patch' '
365 rm -fr .git/rebase-apply &&
366 git reset --hard &&
367 test_must_fail git am <failmail &&
368 git am --abort &&
369 ! test -d .git/rebase-apply
370'
371
372test_expect_success 'am fails on empty patch' '
373 rm -fr .git/rebase-apply &&
374 git reset --hard &&
375 echo "---" >>failmail &&
376 test_must_fail git am <failmail &&
377 git am --skip &&
378 ! test -d .git/rebase-apply
379'
380
381test_expect_success 'am works from stdin in subdirectory' '
382 rm -fr subdir &&
383 rm -fr .git/rebase-apply &&
384 git reset --hard &&
385 git checkout first &&
386 (
387 mkdir -p subdir &&
388 cd subdir &&
389 git am <../patch1
390 ) &&
391 git diff --exit-code second
392'
393
394test_expect_success 'am works from file (relative path given) in subdirectory' '
395 rm -fr subdir &&
396 rm -fr .git/rebase-apply &&
397 git reset --hard &&
398 git checkout first &&
399 (
400 mkdir -p subdir &&
401 cd subdir &&
402 git am ../patch1
403 ) &&
404 git diff --exit-code second
405'
406
407test_expect_success 'am works from file (absolute path given) in subdirectory' '
408 rm -fr subdir &&
409 rm -fr .git/rebase-apply &&
410 git reset --hard &&
411 git checkout first &&
412 P=$(pwd) &&
413 (
414 mkdir -p subdir &&
415 cd subdir &&
416 git am "$P/patch1"
417 ) &&
418 git diff --exit-code second
419'
420
421test_expect_success 'am --committer-date-is-author-date' '
422 rm -fr .git/rebase-apply &&
423 git reset --hard &&
424 git checkout first &&
425 test_tick &&
426 git am --committer-date-is-author-date patch1 &&
427 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
428 sed -ne "/^author /s/.*> //p" head1 >at &&
429 sed -ne "/^committer /s/.*> //p" head1 >ct &&
430 test_cmp at ct
431'
432
433test_expect_success 'am without --committer-date-is-author-date' '
434 rm -fr .git/rebase-apply &&
435 git reset --hard &&
436 git checkout first &&
437 test_tick &&
438 git am patch1 &&
439 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
440 sed -ne "/^author /s/.*> //p" head1 >at &&
441 sed -ne "/^committer /s/.*> //p" head1 >ct &&
442 ! test_cmp at ct
443'
444
445# This checks for +0000 because TZ is set to UTC and that should
446# show up when the current time is used. The date in message is set
447# by test_tick that uses -0700 timezone; if this feature does not
448# work, we will see that instead of +0000.
449test_expect_success 'am --ignore-date' '
450 rm -fr .git/rebase-apply &&
451 git reset --hard &&
452 git checkout first &&
453 test_tick &&
454 git am --ignore-date patch1 &&
455 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
456 sed -ne "/^author /s/.*> //p" head1 >at &&
457 grep "+0000" at
458'
459
460test_expect_success 'am into an unborn branch' '
461 git rev-parse first^{tree} >expected &&
462 rm -fr .git/rebase-apply &&
463 git reset --hard &&
464 rm -fr subdir &&
465 mkdir subdir &&
466 git format-patch --numbered-files -o subdir -1 first &&
467 (
468 cd subdir &&
469 git init &&
470 git am 1
471 ) &&
472 (
473 cd subdir &&
474 git rev-parse HEAD^{tree} >../actual
475 ) &&
476 test_cmp expected actual
477'
478
479test_expect_success 'am newline in subject' '
480 rm -fr .git/rebase-apply &&
481 git reset --hard &&
482 git checkout first &&
483 test_tick &&
484 sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
485 git am <patchnl >output.out 2>&1 &&
486 test_i18ngrep "^Applying: second \\\n foo$" output.out
487'
488
489test_expect_success 'am -q is quiet' '
490 rm -fr .git/rebase-apply &&
491 git reset --hard &&
492 git checkout first &&
493 test_tick &&
494 git am -q <patch1 >output.out 2>&1 &&
495 ! test -s output.out
496'
497
498test_expect_success 'am empty-file does not infloop' '
499 rm -fr .git/rebase-apply &&
500 git reset --hard &&
501 touch empty-file &&
502 test_tick &&
503 { git am empty-file > actual 2>&1 && false || :; } &&
504 echo Patch format detection failed. >expected &&
505 test_cmp expected actual
506'
507
508test_done