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] [foo," 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\] \[foo\] third" actual
263'
264
265test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
266 rm -fr .git/rebase-apply &&
267 git reset --hard &&
268 git checkout HEAD^ &&
269 git am --keep-non-patch patch4 &&
270 ! test -d .git/rebase-apply &&
271 git cat-file commit HEAD >actual &&
272 grep "^\[foo\] third" actual
273'
274
275test_expect_success 'am -3 falls back to 3-way merge' '
276 rm -fr .git/rebase-apply &&
277 git reset --hard &&
278 git checkout -b lorem2 master2 &&
279 sed -n -e "3,\$p" msg >file &&
280 head -n 9 msg >>file &&
281 git add file &&
282 test_tick &&
283 git commit -m "copied stuff" &&
284 git am -3 lorem-move.patch &&
285 ! test -d .git/rebase-apply &&
286 git diff --exit-code lorem
287'
288
289test_expect_success 'am can rename a file' '
290 grep "^rename from" rename.patch &&
291 rm -fr .git/rebase-apply &&
292 git reset --hard &&
293 git checkout lorem^0 &&
294 git am rename.patch &&
295 ! test -d .git/rebase-apply &&
296 git update-index --refresh &&
297 git diff --exit-code rename
298'
299
300test_expect_success 'am -3 can rename a file' '
301 grep "^rename from" rename.patch &&
302 rm -fr .git/rebase-apply &&
303 git reset --hard &&
304 git checkout lorem^0 &&
305 git am -3 rename.patch &&
306 ! test -d .git/rebase-apply &&
307 git update-index --refresh &&
308 git diff --exit-code rename
309'
310
311test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
312 grep "^rename from" rename-add.patch &&
313 rm -fr .git/rebase-apply &&
314 git reset --hard &&
315 git checkout lorem^0 &&
316 git am -3 rename-add.patch &&
317 ! test -d .git/rebase-apply &&
318 git update-index --refresh &&
319 git diff --exit-code rename
320'
321
322test_expect_success 'am -3 -q is quiet' '
323 rm -fr .git/rebase-apply &&
324 git checkout -f lorem2 &&
325 git reset master2 --hard &&
326 sed -n -e "3,\$p" msg >file &&
327 head -n 9 msg >>file &&
328 git add file &&
329 test_tick &&
330 git commit -m "copied stuff" &&
331 git am -3 -q lorem-move.patch >output.out 2>&1 &&
332 ! test -s output.out
333'
334
335test_expect_success 'am pauses on conflict' '
336 rm -fr .git/rebase-apply &&
337 git reset --hard &&
338 git checkout lorem2^^ &&
339 test_must_fail git am lorem-move.patch &&
340 test -d .git/rebase-apply
341'
342
343test_expect_success 'am --skip works' '
344 echo goodbye >expected &&
345 git am --skip &&
346 ! test -d .git/rebase-apply &&
347 git diff --exit-code lorem2^^ -- file &&
348 test_cmp expected another
349'
350
351test_expect_success 'am --resolved works' '
352 echo goodbye >expected &&
353 rm -fr .git/rebase-apply &&
354 git reset --hard &&
355 git checkout lorem2^^ &&
356 test_must_fail git am lorem-move.patch &&
357 test -d .git/rebase-apply &&
358 echo resolved >>file &&
359 git add file &&
360 git am --resolved &&
361 ! test -d .git/rebase-apply &&
362 test_cmp expected another
363'
364
365test_expect_success 'am takes patches from a Pine mailbox' '
366 rm -fr .git/rebase-apply &&
367 git reset --hard &&
368 git checkout first &&
369 cat pine patch1 | git am &&
370 ! test -d .git/rebase-apply &&
371 git diff --exit-code master^..HEAD
372'
373
374test_expect_success 'am fails on mail without patch' '
375 rm -fr .git/rebase-apply &&
376 git reset --hard &&
377 test_must_fail git am <failmail &&
378 git am --abort &&
379 ! test -d .git/rebase-apply
380'
381
382test_expect_success 'am fails on empty patch' '
383 rm -fr .git/rebase-apply &&
384 git reset --hard &&
385 echo "---" >>failmail &&
386 test_must_fail git am <failmail &&
387 git am --skip &&
388 ! test -d .git/rebase-apply
389'
390
391test_expect_success 'am works from stdin in subdirectory' '
392 rm -fr subdir &&
393 rm -fr .git/rebase-apply &&
394 git reset --hard &&
395 git checkout first &&
396 (
397 mkdir -p subdir &&
398 cd subdir &&
399 git am <../patch1
400 ) &&
401 git diff --exit-code second
402'
403
404test_expect_success 'am works from file (relative path given) in subdirectory' '
405 rm -fr subdir &&
406 rm -fr .git/rebase-apply &&
407 git reset --hard &&
408 git checkout first &&
409 (
410 mkdir -p subdir &&
411 cd subdir &&
412 git am ../patch1
413 ) &&
414 git diff --exit-code second
415'
416
417test_expect_success 'am works from file (absolute path given) in subdirectory' '
418 rm -fr subdir &&
419 rm -fr .git/rebase-apply &&
420 git reset --hard &&
421 git checkout first &&
422 P=$(pwd) &&
423 (
424 mkdir -p subdir &&
425 cd subdir &&
426 git am "$P/patch1"
427 ) &&
428 git diff --exit-code second
429'
430
431test_expect_success 'am --committer-date-is-author-date' '
432 rm -fr .git/rebase-apply &&
433 git reset --hard &&
434 git checkout first &&
435 test_tick &&
436 git am --committer-date-is-author-date patch1 &&
437 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
438 sed -ne "/^author /s/.*> //p" head1 >at &&
439 sed -ne "/^committer /s/.*> //p" head1 >ct &&
440 test_cmp at ct
441'
442
443test_expect_success 'am without --committer-date-is-author-date' '
444 rm -fr .git/rebase-apply &&
445 git reset --hard &&
446 git checkout first &&
447 test_tick &&
448 git am patch1 &&
449 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
450 sed -ne "/^author /s/.*> //p" head1 >at &&
451 sed -ne "/^committer /s/.*> //p" head1 >ct &&
452 ! test_cmp at ct
453'
454
455# This checks for +0000 because TZ is set to UTC and that should
456# show up when the current time is used. The date in message is set
457# by test_tick that uses -0700 timezone; if this feature does not
458# work, we will see that instead of +0000.
459test_expect_success 'am --ignore-date' '
460 rm -fr .git/rebase-apply &&
461 git reset --hard &&
462 git checkout first &&
463 test_tick &&
464 git am --ignore-date patch1 &&
465 git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
466 sed -ne "/^author /s/.*> //p" head1 >at &&
467 grep "+0000" at
468'
469
470test_expect_success 'am into an unborn branch' '
471 git rev-parse first^{tree} >expected &&
472 rm -fr .git/rebase-apply &&
473 git reset --hard &&
474 rm -fr subdir &&
475 mkdir subdir &&
476 git format-patch --numbered-files -o subdir -1 first &&
477 (
478 cd subdir &&
479 git init &&
480 git am 1
481 ) &&
482 (
483 cd subdir &&
484 git rev-parse HEAD^{tree} >../actual
485 ) &&
486 test_cmp expected actual
487'
488
489test_expect_success 'am newline in subject' '
490 rm -fr .git/rebase-apply &&
491 git reset --hard &&
492 git checkout first &&
493 test_tick &&
494 sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
495 git am <patchnl >output.out 2>&1 &&
496 test_i18ngrep "^Applying: second \\\n foo$" output.out
497'
498
499test_expect_success 'am -q is quiet' '
500 rm -fr .git/rebase-apply &&
501 git reset --hard &&
502 git checkout first &&
503 test_tick &&
504 git am -q <patch1 >output.out 2>&1 &&
505 ! test -s output.out
506'
507
508test_expect_success 'am empty-file does not infloop' '
509 rm -fr .git/rebase-apply &&
510 git reset --hard &&
511 touch empty-file &&
512 test_tick &&
513 { git am empty-file > actual 2>&1 && false || :; } &&
514 echo Patch format detection failed. >expected &&
515 test_cmp expected actual
516'
517
518test_done