commit: don't rewrite shared index unnecessarily
[git] / t / t4150-am.sh
1 #!/bin/sh
2
3 test_description='git am running'
4
5 . ./test-lib.sh
6
7 test_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
73 test_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
145 test_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
157 test_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
168 test_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
179 test_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
190 test_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
198 compare () {
199         a=$(git cat-file commit "$2" | grep "^$1 ") &&
200         b=$(git cat-file commit "$3" | grep "^$1 ") &&
201         test "$a" = "$b"
202 }
203
204 test_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
220 test_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
234 test_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
240 test_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
251 test_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
257 test_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
267 test_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
277 test_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
288 test_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
297 test_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
306 test_expect_success 'am can rename a file' '
307         grep "^rename from" rename.patch &&
308         rm -fr .git/rebase-apply &&
309         git reset --hard &&
310         git checkout lorem^0 &&
311         git am rename.patch &&
312         test_path_is_missing .git/rebase-apply &&
313         git update-index --refresh &&
314         git diff --exit-code rename
315 '
316
317 test_expect_success 'am -3 can rename a file' '
318         grep "^rename from" rename.patch &&
319         rm -fr .git/rebase-apply &&
320         git reset --hard &&
321         git checkout lorem^0 &&
322         git am -3 rename.patch &&
323         test_path_is_missing .git/rebase-apply &&
324         git update-index --refresh &&
325         git diff --exit-code rename
326 '
327
328 test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
329         grep "^rename from" rename-add.patch &&
330         rm -fr .git/rebase-apply &&
331         git reset --hard &&
332         git checkout lorem^0 &&
333         git am -3 rename-add.patch &&
334         test_path_is_missing .git/rebase-apply &&
335         git update-index --refresh &&
336         git diff --exit-code rename
337 '
338
339 test_expect_success 'am -3 -q is quiet' '
340         rm -fr .git/rebase-apply &&
341         git checkout -f lorem2 &&
342         git reset base3way --hard &&
343         git am -3 -q lorem-move.patch >output.out 2>&1 &&
344         ! test -s output.out
345 '
346
347 test_expect_success 'am pauses on conflict' '
348         rm -fr .git/rebase-apply &&
349         git reset --hard &&
350         git checkout lorem2^^ &&
351         test_must_fail git am lorem-move.patch &&
352         test -d .git/rebase-apply
353 '
354
355 test_expect_success 'am --skip works' '
356         echo goodbye >expected &&
357         git am --skip &&
358         test_path_is_missing .git/rebase-apply &&
359         git diff --exit-code lorem2^^ -- file &&
360         test_cmp expected another
361 '
362
363 test_expect_success 'am --abort removes a stray directory' '
364         mkdir .git/rebase-apply &&
365         git am --abort &&
366         test_path_is_missing .git/rebase-apply
367 '
368
369 test_expect_success 'am --resolved works' '
370         echo goodbye >expected &&
371         rm -fr .git/rebase-apply &&
372         git reset --hard &&
373         git checkout lorem2^^ &&
374         test_must_fail git am lorem-move.patch &&
375         test -d .git/rebase-apply &&
376         echo resolved >>file &&
377         git add file &&
378         git am --resolved &&
379         test_path_is_missing .git/rebase-apply &&
380         test_cmp expected another
381 '
382
383 test_expect_success 'am takes patches from a Pine mailbox' '
384         rm -fr .git/rebase-apply &&
385         git reset --hard &&
386         git checkout first &&
387         cat pine patch1 | git am &&
388         test_path_is_missing .git/rebase-apply &&
389         git diff --exit-code master^..HEAD
390 '
391
392 test_expect_success 'am fails on mail without patch' '
393         rm -fr .git/rebase-apply &&
394         git reset --hard &&
395         test_must_fail git am <failmail &&
396         git am --abort &&
397         test_path_is_missing .git/rebase-apply
398 '
399
400 test_expect_success 'am fails on empty patch' '
401         rm -fr .git/rebase-apply &&
402         git reset --hard &&
403         echo "---" >>failmail &&
404         test_must_fail git am <failmail &&
405         git am --skip &&
406         test_path_is_missing .git/rebase-apply
407 '
408
409 test_expect_success 'am works from stdin in subdirectory' '
410         rm -fr subdir &&
411         rm -fr .git/rebase-apply &&
412         git reset --hard &&
413         git checkout first &&
414         (
415                 mkdir -p subdir &&
416                 cd subdir &&
417                 git am <../patch1
418         ) &&
419         git diff --exit-code second
420 '
421
422 test_expect_success 'am works from file (relative path given) in subdirectory' '
423         rm -fr subdir &&
424         rm -fr .git/rebase-apply &&
425         git reset --hard &&
426         git checkout first &&
427         (
428                 mkdir -p subdir &&
429                 cd subdir &&
430                 git am ../patch1
431         ) &&
432         git diff --exit-code second
433 '
434
435 test_expect_success 'am works from file (absolute path given) in subdirectory' '
436         rm -fr subdir &&
437         rm -fr .git/rebase-apply &&
438         git reset --hard &&
439         git checkout first &&
440         P=$(pwd) &&
441         (
442                 mkdir -p subdir &&
443                 cd subdir &&
444                 git am "$P/patch1"
445         ) &&
446         git diff --exit-code second
447 '
448
449 test_expect_success 'am --committer-date-is-author-date' '
450         rm -fr .git/rebase-apply &&
451         git reset --hard &&
452         git checkout first &&
453         test_tick &&
454         git am --committer-date-is-author-date patch1 &&
455         git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
456         sed -ne "/^author /s/.*> //p" head1 >at &&
457         sed -ne "/^committer /s/.*> //p" head1 >ct &&
458         test_cmp at ct
459 '
460
461 test_expect_success 'am without --committer-date-is-author-date' '
462         rm -fr .git/rebase-apply &&
463         git reset --hard &&
464         git checkout first &&
465         test_tick &&
466         git am patch1 &&
467         git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
468         sed -ne "/^author /s/.*> //p" head1 >at &&
469         sed -ne "/^committer /s/.*> //p" head1 >ct &&
470         ! test_cmp at ct
471 '
472
473 # This checks for +0000 because TZ is set to UTC and that should
474 # show up when the current time is used. The date in message is set
475 # by test_tick that uses -0700 timezone; if this feature does not
476 # work, we will see that instead of +0000.
477 test_expect_success 'am --ignore-date' '
478         rm -fr .git/rebase-apply &&
479         git reset --hard &&
480         git checkout first &&
481         test_tick &&
482         git am --ignore-date patch1 &&
483         git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
484         sed -ne "/^author /s/.*> //p" head1 >at &&
485         grep "+0000" at
486 '
487
488 test_expect_success 'am into an unborn branch' '
489         git rev-parse first^{tree} >expected &&
490         rm -fr .git/rebase-apply &&
491         git reset --hard &&
492         rm -fr subdir &&
493         mkdir subdir &&
494         git format-patch --numbered-files -o subdir -1 first &&
495         (
496                 cd subdir &&
497                 git init &&
498                 git am 1
499         ) &&
500         (
501                 cd subdir &&
502                 git rev-parse HEAD^{tree} >../actual
503         ) &&
504         test_cmp expected actual
505 '
506
507 test_expect_success 'am newline in subject' '
508         rm -fr .git/rebase-apply &&
509         git reset --hard &&
510         git checkout first &&
511         test_tick &&
512         sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
513         git am <patchnl >output.out 2>&1 &&
514         test_i18ngrep "^Applying: second \\\n foo$" output.out
515 '
516
517 test_expect_success 'am -q is quiet' '
518         rm -fr .git/rebase-apply &&
519         git reset --hard &&
520         git checkout first &&
521         test_tick &&
522         git am -q <patch1 >output.out 2>&1 &&
523         ! test -s output.out
524 '
525
526 test_expect_success 'am empty-file does not infloop' '
527         rm -fr .git/rebase-apply &&
528         git reset --hard &&
529         touch empty-file &&
530         test_tick &&
531         test_must_fail git am empty-file 2>actual &&
532         echo Patch format detection failed. >expected &&
533         test_i18ncmp expected actual
534 '
535
536 test_expect_success 'am --message-id really adds the message id' '
537         rm -fr .git/rebase-apply &&
538         git reset --hard &&
539         git checkout HEAD^ &&
540         git am --message-id patch1.eml &&
541         test_path_is_missing .git/rebase-apply &&
542         git cat-file commit HEAD | tail -n1 >actual &&
543         grep Message-Id patch1.eml >expected &&
544         test_cmp expected actual
545 '
546
547 test_expect_success 'am --message-id -s signs off after the message id' '
548         rm -fr .git/rebase-apply &&
549         git reset --hard &&
550         git checkout HEAD^ &&
551         git am -s --message-id patch1.eml &&
552         test_path_is_missing .git/rebase-apply &&
553         git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
554         grep Message-Id patch1.eml >expected &&
555         test_cmp expected actual
556 '
557
558 test_done