1#!/bin/sh
2
3test_description='git am running'
4
5GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8. ./test-lib.sh
9
10test_expect_success 'setup: messages' '
11	cat >msg <<-\EOF &&
12	second
13
14	Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy
15	eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
16	voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
17	kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem
18	ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
19	tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
20	vero eos et accusam et justo duo dolores et ea rebum.
21
22	EOF
23	qz_to_tab_space <<-\EOF >>msg &&
24	QDuis autem vel eum iriure dolor in hendrerit in vulputate velit
25	Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis
26	Qat vero eros et accumsan et iusto odio dignissim qui blandit
27	Qpraesent luptatum zzril delenit augue duis dolore te feugait nulla
28	Qfacilisi.
29	EOF
30	cat >>msg <<-\EOF &&
31
32	Lorem ipsum dolor sit amet,
33	consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
34	laoreet dolore magna aliquam erat volutpat.
35
36	  git
37	  ---
38	  +++
39
40	Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
41	lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
42	dolor in hendrerit in vulputate velit esse molestie consequat, vel illum
43	dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
44	dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te
45	feugait nulla facilisi.
46
47	Reported-by: A N Other <a.n.other@example.com>
48	EOF
49
50	cat >failmail <<-\EOF &&
51	From foo@example.com Fri May 23 10:43:49 2008
52	From:	foo@example.com
53	To:	bar@example.com
54	Subject: Re: [RFC/PATCH] git-foo.sh
55	Date:	Fri, 23 May 2008 05:23:42 +0200
56
57	Sometimes we have to find out that there'\''s nothing left.
58
59	EOF
60
61	cat >pine <<-\EOF &&
62	From MAILER-DAEMON Fri May 23 10:43:49 2008
63	Date: 23 May 2008 05:23:42 +0200
64	From: Mail System Internal Data <MAILER-DAEMON@example.com>
65	Subject: DON'\''T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA
66	Message-ID: <foo-0001@example.com>
67
68	This text is part of the internal format of your mail folder, and is not
69	a real message.  It is created automatically by the mail system software.
70	If deleted, important folder data will be lost, and it will be re-created
71	with the data reset to initial values.
72
73	EOF
74
75	cat >msg-without-scissors-line <<-\EOF &&
76	Test that git-am --scissors cuts at the scissors line
77
78	This line should be included in the commit message.
79	EOF
80
81	printf "Subject: " >subject-prefix &&
82
83	cat - subject-prefix msg-without-scissors-line >msg-with-scissors-line <<-\EOF
84	This line should not be included in the commit message with --scissors enabled.
85
86	 - - >8 - - remove everything above this line - - >8 - -
87
88	EOF
89'
90
91test_expect_success setup '
92	echo hello >file &&
93	git add file &&
94	test_tick &&
95	git commit -m first &&
96	git tag first &&
97
98	echo world >>file &&
99	git add file &&
100	test_tick &&
101	git commit -F msg &&
102	git tag second &&
103
104	git format-patch --stdout first >patch1 &&
105	{
106		echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
107		echo "X-Fake-Field: Line One" &&
108		echo "X-Fake-Field: Line Two" &&
109		echo "X-Fake-Field: Line Three" &&
110		git format-patch --stdout first | sed -e "1d"
111	} > patch1.eml &&
112	{
113		echo "X-Fake-Field: Line One" &&
114		echo "X-Fake-Field: Line Two" &&
115		echo "X-Fake-Field: Line Three" &&
116		git format-patch --stdout first | sed -e "1d"
117	} | append_cr >patch1-crlf.eml &&
118	{
119		printf "%255s\\n" ""
120		echo "X-Fake-Field: Line One" &&
121		echo "X-Fake-Field: Line Two" &&
122		echo "X-Fake-Field: Line Three" &&
123		git format-patch --stdout first | sed -e "1d"
124	} > patch1-ws.eml &&
125	{
126		sed -ne "1p" msg &&
127		echo &&
128		echo "From: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" &&
129		echo "Date: $GIT_AUTHOR_DATE" &&
130		echo &&
131		sed -e "1,2d" msg &&
132		echo "---" &&
133		git diff-tree --no-commit-id --stat -p second
134	} >patch1-stgit.eml &&
135	mkdir stgit-series &&
136	cp patch1-stgit.eml stgit-series/patch &&
137	{
138		echo "# This series applies on GIT commit $(git rev-parse first)" &&
139		echo "patch"
140	} >stgit-series/series &&
141	{
142		echo "# HG changeset patch" &&
143		echo "# User $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" &&
144		echo "# Date $test_tick 25200" &&
145		echo "#      $(git show --pretty="%aD" -s second)" &&
146		echo "# Node ID $ZERO_OID" &&
147		echo "# Parent  $ZERO_OID" &&
148		cat msg &&
149		echo &&
150		git diff-tree --no-commit-id -p second
151	} >patch1-hg.eml &&
152
153
154	echo file >file &&
155	git add file &&
156	git commit -F msg-without-scissors-line &&
157	git tag expected-for-scissors &&
158	git reset --hard HEAD^ &&
159
160	echo file >file &&
161	git add file &&
162	git commit -F msg-with-scissors-line &&
163	git tag expected-for-no-scissors &&
164	git format-patch --stdout expected-for-no-scissors^ >patch-with-scissors-line.eml &&
165	git reset --hard HEAD^ &&
166
167	sed -n -e "3,\$p" msg >file &&
168	git add file &&
169	test_tick &&
170	git commit -m third &&
171
172	git format-patch --stdout first >patch2 &&
173
174	git checkout -b lorem &&
175	sed -n -e "11,\$p" msg >file &&
176	head -n 9 msg >>file &&
177	test_tick &&
178	git commit -a -m "moved stuff" &&
179
180	echo goodbye >another &&
181	git add another &&
182	test_tick &&
183	git commit -m "added another file" &&
184
185	git format-patch --stdout main >lorem-move.patch &&
186	git format-patch --no-prefix --stdout main >lorem-zero.patch &&
187
188	git checkout -b rename &&
189	git mv file renamed &&
190	git commit -m "renamed a file" &&
191
192	git format-patch -M --stdout lorem >rename.patch &&
193
194	git reset --soft lorem^ &&
195	git commit -m "renamed a file and added another" &&
196
197	git format-patch -M --stdout lorem^ >rename-add.patch &&
198
199	# reset time
200	sane_unset test_tick &&
201	test_tick
202'
203
204test_expect_success 'am applies patch correctly' '
205	rm -fr .git/rebase-apply &&
206	git reset --hard &&
207	git checkout first &&
208	test_tick &&
209	git am <patch1 &&
210	test_path_is_missing .git/rebase-apply &&
211	git diff --exit-code second &&
212	test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
213	test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
214'
215
216test_expect_success 'am fails if index is dirty' '
217	test_when_finished "rm -f dirtyfile" &&
218	rm -fr .git/rebase-apply &&
219	git reset --hard &&
220	git checkout first &&
221	echo dirtyfile >dirtyfile &&
222	git add dirtyfile &&
223	test_must_fail git am patch1 &&
224	test_path_is_dir .git/rebase-apply &&
225	test_cmp_rev first HEAD
226'
227
228test_expect_success 'am applies patch e-mail not in a mbox' '
229	rm -fr .git/rebase-apply &&
230	git reset --hard &&
231	git checkout first &&
232	git am patch1.eml &&
233	test_path_is_missing .git/rebase-apply &&
234	git diff --exit-code second &&
235	test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
236	test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
237'
238
239test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
240	rm -fr .git/rebase-apply &&
241	git reset --hard &&
242	git checkout first &&
243	git am patch1-crlf.eml &&
244	test_path_is_missing .git/rebase-apply &&
245	git diff --exit-code second &&
246	test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
247	test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
248'
249
250test_expect_success 'am applies patch e-mail with preceding whitespace' '
251	rm -fr .git/rebase-apply &&
252	git reset --hard &&
253	git checkout first &&
254	git am patch1-ws.eml &&
255	test_path_is_missing .git/rebase-apply &&
256	git diff --exit-code second &&
257	test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
258	test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
259'
260
261test_expect_success 'am applies stgit patch' '
262	rm -fr .git/rebase-apply &&
263	git checkout -f first &&
264	git am patch1-stgit.eml &&
265	test_path_is_missing .git/rebase-apply &&
266	git diff --exit-code second &&
267	test_cmp_rev second HEAD &&
268	test_cmp_rev second^ HEAD^
269'
270
271test_expect_success 'am --patch-format=stgit applies stgit patch' '
272	rm -fr .git/rebase-apply &&
273	git checkout -f first &&
274	git am --patch-format=stgit <patch1-stgit.eml &&
275	test_path_is_missing .git/rebase-apply &&
276	git diff --exit-code second &&
277	test_cmp_rev second HEAD &&
278	test_cmp_rev second^ HEAD^
279'
280
281test_expect_success 'am applies stgit series' '
282	rm -fr .git/rebase-apply &&
283	git checkout -f first &&
284	git am stgit-series/series &&
285	test_path_is_missing .git/rebase-apply &&
286	git diff --exit-code second &&
287	test_cmp_rev second HEAD &&
288	test_cmp_rev second^ HEAD^
289'
290
291test_expect_success 'am applies hg patch' '
292	rm -fr .git/rebase-apply &&
293	git checkout -f first &&
294	git am patch1-hg.eml &&
295	test_path_is_missing .git/rebase-apply &&
296	git diff --exit-code second &&
297	test_cmp_rev second HEAD &&
298	test_cmp_rev second^ HEAD^
299'
300
301test_expect_success 'am --patch-format=hg applies hg patch' '
302	rm -fr .git/rebase-apply &&
303	git checkout -f first &&
304	git am --patch-format=hg <patch1-hg.eml &&
305	test_path_is_missing .git/rebase-apply &&
306	git diff --exit-code second &&
307	test_cmp_rev second HEAD &&
308	test_cmp_rev second^ HEAD^
309'
310
311test_expect_success 'am with applypatch-msg hook' '
312	test_when_finished "rm -f .git/hooks/applypatch-msg" &&
313	rm -fr .git/rebase-apply &&
314	git reset --hard &&
315	git checkout first &&
316	mkdir -p .git/hooks &&
317	write_script .git/hooks/applypatch-msg <<-\EOF &&
318	cat "$1" >actual-msg &&
319	echo hook-message >"$1"
320	EOF
321	git am patch1 &&
322	test_path_is_missing .git/rebase-apply &&
323	git diff --exit-code second &&
324	echo hook-message >expected &&
325	git log -1 --format=format:%B >actual &&
326	test_cmp expected actual &&
327	git log -1 --format=format:%B second >expected &&
328	test_cmp expected actual-msg
329'
330
331test_expect_success 'am with failing applypatch-msg hook' '
332	test_when_finished "rm -f .git/hooks/applypatch-msg" &&
333	rm -fr .git/rebase-apply &&
334	git reset --hard &&
335	git checkout first &&
336	mkdir -p .git/hooks &&
337	write_script .git/hooks/applypatch-msg <<-\EOF &&
338	exit 1
339	EOF
340	test_must_fail git am patch1 &&
341	test_path_is_dir .git/rebase-apply &&
342	git diff --exit-code first &&
343	test_cmp_rev first HEAD
344'
345
346test_expect_success 'am with pre-applypatch hook' '
347	test_when_finished "rm -f .git/hooks/pre-applypatch" &&
348	rm -fr .git/rebase-apply &&
349	git reset --hard &&
350	git checkout first &&
351	mkdir -p .git/hooks &&
352	write_script .git/hooks/pre-applypatch <<-\EOF &&
353	git diff first >diff.actual
354	exit 0
355	EOF
356	git am patch1 &&
357	test_path_is_missing .git/rebase-apply &&
358	git diff --exit-code second &&
359	test_cmp_rev second HEAD &&
360	git diff first..second >diff.expected &&
361	test_cmp diff.expected diff.actual
362'
363
364test_expect_success 'am with failing pre-applypatch hook' '
365	test_when_finished "rm -f .git/hooks/pre-applypatch" &&
366	rm -fr .git/rebase-apply &&
367	git reset --hard &&
368	git checkout first &&
369	mkdir -p .git/hooks &&
370	write_script .git/hooks/pre-applypatch <<-\EOF &&
371	exit 1
372	EOF
373	test_must_fail git am patch1 &&
374	test_path_is_dir .git/rebase-apply &&
375	git diff --exit-code second &&
376	test_cmp_rev first HEAD
377'
378
379test_expect_success 'am with post-applypatch hook' '
380	test_when_finished "rm -f .git/hooks/post-applypatch" &&
381	rm -fr .git/rebase-apply &&
382	git reset --hard &&
383	git checkout first &&
384	mkdir -p .git/hooks &&
385	write_script .git/hooks/post-applypatch <<-\EOF &&
386	git rev-parse HEAD >head.actual
387	git diff second >diff.actual
388	exit 0
389	EOF
390	git am patch1 &&
391	test_path_is_missing .git/rebase-apply &&
392	test_cmp_rev second HEAD &&
393	git rev-parse second >head.expected &&
394	test_cmp head.expected head.actual &&
395	git diff second >diff.expected &&
396	test_cmp diff.expected diff.actual
397'
398
399test_expect_success 'am with failing post-applypatch hook' '
400	test_when_finished "rm -f .git/hooks/post-applypatch" &&
401	rm -fr .git/rebase-apply &&
402	git reset --hard &&
403	git checkout first &&
404	mkdir -p .git/hooks &&
405	write_script .git/hooks/post-applypatch <<-\EOF &&
406	git rev-parse HEAD >head.actual
407	exit 1
408	EOF
409	git am patch1 &&
410	test_path_is_missing .git/rebase-apply &&
411	git diff --exit-code second &&
412	test_cmp_rev second HEAD &&
413	git rev-parse second >head.expected &&
414	test_cmp head.expected head.actual
415'
416
417test_expect_success 'am --scissors cuts the message at the scissors line' '
418	rm -fr .git/rebase-apply &&
419	git reset --hard &&
420	git checkout second &&
421	git am --scissors patch-with-scissors-line.eml &&
422	test_path_is_missing .git/rebase-apply &&
423	git diff --exit-code expected-for-scissors &&
424	test_cmp_rev expected-for-scissors HEAD
425'
426
427test_expect_success 'am --no-scissors overrides mailinfo.scissors' '
428	rm -fr .git/rebase-apply &&
429	git reset --hard &&
430	git checkout second &&
431	test_config mailinfo.scissors true &&
432	git am --no-scissors patch-with-scissors-line.eml &&
433	test_path_is_missing .git/rebase-apply &&
434	git diff --exit-code expected-for-no-scissors &&
435	test_cmp_rev expected-for-no-scissors HEAD
436'
437
438test_expect_success 'setup: new author and committer' '
439	GIT_AUTHOR_NAME="Another Thor" &&
440	GIT_AUTHOR_EMAIL="a.thor@example.com" &&
441	GIT_COMMITTER_NAME="Co M Miter" &&
442	GIT_COMMITTER_EMAIL="c.miter@example.com" &&
443	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
444'
445
446compare () {
447	a=$(git cat-file commit "$2" | grep "^$1 ") &&
448	b=$(git cat-file commit "$3" | grep "^$1 ") &&
449	test "$a" = "$b"
450}
451
452test_expect_success 'am changes committer and keeps author' '
453	test_tick &&
454	rm -fr .git/rebase-apply &&
455	git reset --hard &&
456	git checkout first &&
457	git am patch2 &&
458	test_path_is_missing .git/rebase-apply &&
459	test "$(git rev-parse main^^)" = "$(git rev-parse HEAD^^)" &&
460	git diff --exit-code main..HEAD &&
461	git diff --exit-code main^..HEAD^ &&
462	compare author main HEAD &&
463	compare author main^ HEAD^ &&
464	test "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" = \
465	     "$(git log -1 --pretty=format:"%cn <%ce>" HEAD)"
466'
467
468test_expect_success 'am --signoff adds Signed-off-by: line' '
469	rm -fr .git/rebase-apply &&
470	git reset --hard &&
471	git checkout -b topic_2 first &&
472	git am --signoff <patch2 &&
473	{
474		printf "third\n\nSigned-off-by: %s <%s>\n\n" \
475			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" &&
476		cat msg &&
477		printf "Signed-off-by: %s <%s>\n\n" \
478			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL"
479	} >expected-log &&
480	git log --pretty=%B -2 HEAD >actual &&
481	test_cmp expected-log actual
482'
483
484test_expect_success 'am stays in branch' '
485	echo refs/heads/topic_2 >expected &&
486	git symbolic-ref HEAD >actual &&
487	test_cmp expected actual
488'
489
490test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
491	git format-patch --stdout first >patch3 &&
492	git reset --hard first &&
493	git am --signoff <patch3 &&
494	git log --pretty=%B -2 HEAD >actual &&
495	test_cmp expected-log actual
496'
497
498test_expect_success 'am --signoff adds Signed-off-by: if another author is preset' '
499	NAME="A N Other" &&
500	EMAIL="a.n.other@example.com" &&
501	{
502		printf "third\n\nSigned-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
503			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
504			"$NAME" "$EMAIL" &&
505		cat msg &&
506		printf "Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
507			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
508			"$NAME" "$EMAIL"
509	} >expected-log &&
510	git reset --hard first &&
511	GIT_COMMITTER_NAME="$NAME" GIT_COMMITTER_EMAIL="$EMAIL" \
512		git am --signoff <patch3 &&
513	git log --pretty=%B -2 HEAD >actual &&
514	test_cmp expected-log actual
515'
516
517test_expect_success 'am --signoff duplicates Signed-off-by: if it is not the last one' '
518	NAME="A N Other" &&
519	EMAIL="a.n.other@example.com" &&
520	{
521		printf "third\n\nSigned-off-by: %s <%s>\n\
522Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
523			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
524			"$NAME" "$EMAIL" \
525			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" &&
526		cat msg &&
527		printf "Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\
528Signed-off-by: %s <%s>\n\n" \
529			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
530			"$NAME" "$EMAIL" \
531			"$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL"
532	} >expected-log &&
533	git format-patch --stdout first >patch3 &&
534	git reset --hard first &&
535	git am --signoff <patch3 &&
536	git log --pretty=%B -2 HEAD >actual &&
537	test_cmp expected-log actual
538'
539
540test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
541	git format-patch --stdout HEAD^ >tmp &&
542	sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," tmp >patch4 &&
543	git reset --hard HEAD^ &&
544	git am <patch4 &&
545	git rev-parse HEAD >expected &&
546	git rev-parse topic_2 >actual &&
547	test_cmp expected actual
548'
549
550test_expect_success 'am --keep really keeps the subject' '
551	rm -fr .git/rebase-apply &&
552	git reset --hard &&
553	git checkout HEAD^ &&
554	git am --keep patch4 &&
555	test_path_is_missing .git/rebase-apply &&
556	git cat-file commit HEAD >actual &&
557	grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual
558'
559
560test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
561	rm -fr .git/rebase-apply &&
562	git reset --hard &&
563	git checkout HEAD^ &&
564	git am --keep-non-patch patch4 &&
565	test_path_is_missing .git/rebase-apply &&
566	git cat-file commit HEAD >actual &&
567	grep "^\[foo\] third" actual
568'
569
570test_expect_success 'setup am -3' '
571	rm -fr .git/rebase-apply &&
572	git reset --hard &&
573	git checkout -b base3way topic_2 &&
574	sed -n -e "3,\$p" msg >file &&
575	head -n 9 msg >>file &&
576	git add file &&
577	test_tick &&
578	git commit -m "copied stuff"
579'
580
581test_expect_success 'am -3 falls back to 3-way merge' '
582	rm -fr .git/rebase-apply &&
583	git reset --hard &&
584	git checkout -b lorem2 base3way &&
585	git am -3 lorem-move.patch &&
586	test_path_is_missing .git/rebase-apply &&
587	git diff --exit-code lorem
588'
589
590test_expect_success 'am -3 -p0 can read --no-prefix patch' '
591	rm -fr .git/rebase-apply &&
592	git reset --hard &&
593	git checkout -b lorem3 base3way &&
594	git am -3 -p0 lorem-zero.patch &&
595	test_path_is_missing .git/rebase-apply &&
596	git diff --exit-code lorem
597'
598
599test_expect_success 'am with config am.threeWay falls back to 3-way merge' '
600	rm -fr .git/rebase-apply &&
601	git reset --hard &&
602	git checkout -b lorem4 base3way &&
603	test_config am.threeWay 1 &&
604	git am lorem-move.patch &&
605	test_path_is_missing .git/rebase-apply &&
606	git diff --exit-code lorem
607'
608
609test_expect_success 'am with config am.threeWay overridden by --no-3way' '
610	rm -fr .git/rebase-apply &&
611	git reset --hard &&
612	git checkout -b lorem5 base3way &&
613	test_config am.threeWay 1 &&
614	test_must_fail git am --no-3way lorem-move.patch &&
615	test_path_is_dir .git/rebase-apply
616'
617
618test_expect_success 'am can rename a file' '
619	grep "^rename from" rename.patch &&
620	rm -fr .git/rebase-apply &&
621	git reset --hard &&
622	git checkout lorem^0 &&
623	git am rename.patch &&
624	test_path_is_missing .git/rebase-apply &&
625	git update-index --refresh &&
626	git diff --exit-code rename
627'
628
629test_expect_success 'am -3 can rename a file' '
630	grep "^rename from" rename.patch &&
631	rm -fr .git/rebase-apply &&
632	git reset --hard &&
633	git checkout lorem^0 &&
634	git am -3 rename.patch &&
635	test_path_is_missing .git/rebase-apply &&
636	git update-index --refresh &&
637	git diff --exit-code rename
638'
639
640test_expect_success 'am -3 can rename a file after falling back to 3-way merge' '
641	grep "^rename from" rename-add.patch &&
642	rm -fr .git/rebase-apply &&
643	git reset --hard &&
644	git checkout lorem^0 &&
645	git am -3 rename-add.patch &&
646	test_path_is_missing .git/rebase-apply &&
647	git update-index --refresh &&
648	git diff --exit-code rename
649'
650
651test_expect_success 'am -3 -q is quiet' '
652	rm -fr .git/rebase-apply &&
653	git checkout -f lorem2 &&
654	git reset base3way --hard &&
655	git am -3 -q lorem-move.patch >output.out 2>&1 &&
656	test_must_be_empty output.out
657'
658
659test_expect_success 'am pauses on conflict' '
660	rm -fr .git/rebase-apply &&
661	git reset --hard &&
662	git checkout lorem2^^ &&
663	test_must_fail git am lorem-move.patch &&
664	test -d .git/rebase-apply
665'
666
667test_expect_success 'am --show-current-patch' '
668	git am --show-current-patch >actual.patch &&
669	test_cmp .git/rebase-apply/0001 actual.patch
670'
671
672test_expect_success 'am --show-current-patch=raw' '
673	git am --show-current-patch=raw >actual.patch &&
674	test_cmp .git/rebase-apply/0001 actual.patch
675'
676
677test_expect_success 'am --show-current-patch=diff' '
678	git am --show-current-patch=diff >actual.patch &&
679	test_cmp .git/rebase-apply/patch actual.patch
680'
681
682test_expect_success 'am accepts repeated --show-current-patch' '
683	git am --show-current-patch --show-current-patch=raw >actual.patch &&
684	test_cmp .git/rebase-apply/0001 actual.patch
685'
686
687test_expect_success 'am detects incompatible --show-current-patch' '
688	test_must_fail git am --show-current-patch=raw --show-current-patch=diff &&
689	test_must_fail git am --show-current-patch --show-current-patch=diff
690'
691
692test_expect_success 'am --skip works' '
693	echo goodbye >expected &&
694	git am --skip &&
695	test_path_is_missing .git/rebase-apply &&
696	git diff --exit-code lorem2^^ -- file &&
697	test_cmp expected another
698'
699
700test_expect_success 'am --abort removes a stray directory' '
701	mkdir .git/rebase-apply &&
702	git am --abort &&
703	test_path_is_missing .git/rebase-apply
704'
705
706test_expect_success 'am refuses patches when paused' '
707	rm -fr .git/rebase-apply &&
708	git reset --hard &&
709	git checkout lorem2^^ &&
710
711	test_must_fail git am lorem-move.patch &&
712	test_path_is_dir .git/rebase-apply &&
713	test_cmp_rev lorem2^^ HEAD &&
714
715	test_must_fail git am <lorem-move.patch &&
716	test_path_is_dir .git/rebase-apply &&
717	test_cmp_rev lorem2^^ HEAD
718'
719
720test_expect_success 'am --resolved works' '
721	echo goodbye >expected &&
722	rm -fr .git/rebase-apply &&
723	git reset --hard &&
724	git checkout lorem2^^ &&
725	test_must_fail git am lorem-move.patch &&
726	test -d .git/rebase-apply &&
727	echo resolved >>file &&
728	git add file &&
729	git am --resolved &&
730	test_path_is_missing .git/rebase-apply &&
731	test_cmp expected another
732'
733
734test_expect_success 'am --resolved fails if index has no changes' '
735	rm -fr .git/rebase-apply &&
736	git reset --hard &&
737	git checkout lorem2^^ &&
738	test_must_fail git am lorem-move.patch &&
739	test_path_is_dir .git/rebase-apply &&
740	test_cmp_rev lorem2^^ HEAD &&
741	test_must_fail git am --resolved &&
742	test_path_is_dir .git/rebase-apply &&
743	test_cmp_rev lorem2^^ HEAD
744'
745
746test_expect_success 'am --resolved fails if index has unmerged entries' '
747	rm -fr .git/rebase-apply &&
748	git reset --hard &&
749	git checkout second &&
750	test_must_fail git am -3 lorem-move.patch &&
751	test_path_is_dir .git/rebase-apply &&
752	test_cmp_rev second HEAD &&
753	test_must_fail git am --resolved >err &&
754	test_path_is_dir .git/rebase-apply &&
755	test_cmp_rev second HEAD &&
756	test_i18ngrep "still have unmerged paths" err
757'
758
759test_expect_success 'am takes patches from a Pine mailbox' '
760	rm -fr .git/rebase-apply &&
761	git reset --hard &&
762	git checkout first &&
763	cat pine patch1 | git am &&
764	test_path_is_missing .git/rebase-apply &&
765	git diff --exit-code main^..HEAD
766'
767
768test_expect_success 'am fails on mail without patch' '
769	rm -fr .git/rebase-apply &&
770	git reset --hard &&
771	test_must_fail git am <failmail &&
772	git am --abort &&
773	test_path_is_missing .git/rebase-apply
774'
775
776test_expect_success 'am fails on empty patch' '
777	rm -fr .git/rebase-apply &&
778	git reset --hard &&
779	echo "---" >>failmail &&
780	test_must_fail git am <failmail &&
781	git am --skip &&
782	test_path_is_missing .git/rebase-apply
783'
784
785test_expect_success 'am works from stdin in subdirectory' '
786	rm -fr subdir &&
787	rm -fr .git/rebase-apply &&
788	git reset --hard &&
789	git checkout first &&
790	(
791		mkdir -p subdir &&
792		cd subdir &&
793		git am <../patch1
794	) &&
795	git diff --exit-code second
796'
797
798test_expect_success 'am works from file (relative path given) in subdirectory' '
799	rm -fr subdir &&
800	rm -fr .git/rebase-apply &&
801	git reset --hard &&
802	git checkout first &&
803	(
804		mkdir -p subdir &&
805		cd subdir &&
806		git am ../patch1
807	) &&
808	git diff --exit-code second
809'
810
811test_expect_success 'am works from file (absolute path given) in subdirectory' '
812	rm -fr subdir &&
813	rm -fr .git/rebase-apply &&
814	git reset --hard &&
815	git checkout first &&
816	P=$(pwd) &&
817	(
818		mkdir -p subdir &&
819		cd subdir &&
820		git am "$P/patch1"
821	) &&
822	git diff --exit-code second
823'
824
825test_expect_success 'am --committer-date-is-author-date' '
826	rm -fr .git/rebase-apply &&
827	git reset --hard &&
828	git checkout first &&
829	test_tick &&
830	git am --committer-date-is-author-date patch1 &&
831	git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
832	sed -ne "/^author /s/.*> //p" head1 >at &&
833	sed -ne "/^committer /s/.*> //p" head1 >ct &&
834	test_cmp at ct
835'
836
837test_expect_success 'am without --committer-date-is-author-date' '
838	rm -fr .git/rebase-apply &&
839	git reset --hard &&
840	git checkout first &&
841	test_tick &&
842	git am patch1 &&
843	git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
844	sed -ne "/^author /s/.*> //p" head1 >at &&
845	sed -ne "/^committer /s/.*> //p" head1 >ct &&
846	! test_cmp at ct
847'
848
849# This checks for +0000 because TZ is set to UTC and that should
850# show up when the current time is used. The date in message is set
851# by test_tick that uses -0700 timezone; if this feature does not
852# work, we will see that instead of +0000.
853test_expect_success 'am --ignore-date' '
854	rm -fr .git/rebase-apply &&
855	git reset --hard &&
856	git checkout first &&
857	test_tick &&
858	git am --ignore-date patch1 &&
859	git cat-file commit HEAD | sed -e "/^\$/q" >head1 &&
860	sed -ne "/^author /s/.*> //p" head1 >at &&
861	grep "+0000" at
862'
863
864test_expect_success 'am into an unborn branch' '
865	git rev-parse first^{tree} >expected &&
866	rm -fr .git/rebase-apply &&
867	git reset --hard &&
868	rm -fr subdir &&
869	mkdir subdir &&
870	git format-patch --numbered-files -o subdir -1 first &&
871	(
872		cd subdir &&
873		git init &&
874		git am 1
875	) &&
876	(
877		cd subdir &&
878		git rev-parse HEAD^{tree} >../actual
879	) &&
880	test_cmp expected actual
881'
882
883test_expect_success 'am newline in subject' '
884	rm -fr .git/rebase-apply &&
885	git reset --hard &&
886	git checkout first &&
887	test_tick &&
888	sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
889	git am <patchnl >output.out 2>&1 &&
890	test_i18ngrep "^Applying: second \\\n foo$" output.out
891'
892
893test_expect_success 'am -q is quiet' '
894	rm -fr .git/rebase-apply &&
895	git reset --hard &&
896	git checkout first &&
897	test_tick &&
898	git am -q <patch1 >output.out 2>&1 &&
899	test_must_be_empty output.out
900'
901
902test_expect_success 'am empty-file does not infloop' '
903	rm -fr .git/rebase-apply &&
904	git reset --hard &&
905	touch empty-file &&
906	test_tick &&
907	test_must_fail git am empty-file 2>actual &&
908	echo Patch format detection failed. >expected &&
909	test_cmp expected actual
910'
911
912test_expect_success 'am --message-id really adds the message id' '
913	rm -fr .git/rebase-apply &&
914	git reset --hard &&
915	git checkout HEAD^ &&
916	git am --message-id patch1.eml &&
917	test_path_is_missing .git/rebase-apply &&
918	git cat-file commit HEAD | tail -n1 >actual &&
919	grep Message-Id patch1.eml >expected &&
920	test_cmp expected actual
921'
922
923test_expect_success 'am.messageid really adds the message id' '
924	rm -fr .git/rebase-apply &&
925	git reset --hard &&
926	git checkout HEAD^ &&
927	test_config am.messageid true &&
928	git am patch1.eml &&
929	test_path_is_missing .git/rebase-apply &&
930	git cat-file commit HEAD | tail -n1 >actual &&
931	grep Message-Id patch1.eml >expected &&
932	test_cmp expected actual
933'
934
935test_expect_success 'am --message-id -s signs off after the message id' '
936	rm -fr .git/rebase-apply &&
937	git reset --hard &&
938	git checkout HEAD^ &&
939	git am -s --message-id patch1.eml &&
940	test_path_is_missing .git/rebase-apply &&
941	git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
942	grep Message-Id patch1.eml >expected &&
943	test_cmp expected actual
944'
945
946test_expect_success 'am -3 works with rerere' '
947	rm -fr .git/rebase-apply &&
948	git reset --hard &&
949
950	# make patches one->two and two->three...
951	test_commit one file &&
952	test_commit two file &&
953	test_commit three file &&
954	git format-patch -2 --stdout >seq.patch &&
955
956	# and create a situation that conflicts...
957	git reset --hard one &&
958	test_commit other file &&
959
960	# enable rerere...
961	test_config rerere.enabled true &&
962	test_when_finished "rm -rf .git/rr-cache" &&
963
964	# ...and apply. Our resolution is to skip the first
965	# patch, and the rerere the second one.
966	test_must_fail git am -3 seq.patch &&
967	test_must_fail git am --skip &&
968	echo resolved >file &&
969	git add file &&
970	git am --resolved &&
971
972	# now apply again, and confirm that rerere engaged (we still
973	# expect failure from am because rerere does not auto-commit
974	# for us).
975	git reset --hard other &&
976	test_must_fail git am -3 seq.patch &&
977	test_must_fail git am --skip &&
978	echo resolved >expect &&
979	test_cmp expect file
980'
981
982test_expect_success 'am -s unexpected trailer block' '
983	rm -fr .git/rebase-apply &&
984	git reset --hard &&
985	echo signed >file &&
986	git add file &&
987	cat >msg <<-EOF &&
988	subject here
989
990	Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
991	[jc: tweaked log message]
992	Signed-off-by: J C H <j@c.h>
993	EOF
994	git commit -F msg &&
995	git cat-file commit HEAD | sed -e "1,/^$/d" >original &&
996	git format-patch --stdout -1 >patch &&
997
998	git reset --hard HEAD^ &&
999	git am -s patch &&
1000	(
1001		cat original &&
1002		echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
1003	) >expect &&
1004	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
1005	test_cmp expect actual &&
1006
1007	cat >msg <<-\EOF &&
1008	subject here
1009
1010	We make sure that there is a blank line between the log
1011	message proper and Signed-off-by: line added.
1012	EOF
1013	git reset HEAD^ &&
1014	git commit -F msg file &&
1015	git cat-file commit HEAD | sed -e "1,/^$/d" >original &&
1016	git format-patch --stdout -1 >patch &&
1017
1018	git reset --hard HEAD^ &&
1019	git am -s patch &&
1020
1021	(
1022		cat original &&
1023		echo &&
1024		echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
1025	) >expect &&
1026	git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
1027	test_cmp expect actual
1028'
1029
1030test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
1031	rm -fr .git/rebase-apply &&
1032	git checkout -f first &&
1033	echo mboxrd >>file &&
1034	git add file &&
1035	cat >msg <<-\INPUT_END &&
1036	mboxrd should escape the body
1037
1038	From could trip up a loose mbox parser
1039	>From extra escape for reversibility
1040	INPUT_END
1041	git commit -F msg &&
1042	git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&
1043	grep "^>From could trip up a loose mbox parser" mboxrd1 &&
1044	git checkout -f first &&
1045	git am --patch-format=mboxrd mboxrd1 &&
1046	git cat-file commit HEAD | tail -n4 >out &&
1047	test_cmp msg out
1048'
1049
1050test_expect_success 'am works with multi-line in-body headers' '
1051	FORTY="String that has a length of more than forty characters" &&
1052	LONG="$FORTY $FORTY" &&
1053	rm -fr .git/rebase-apply &&
1054	git checkout -f first &&
1055	echo one >> file &&
1056	git commit -am "$LONG
1057
1058    Body test" --author="$LONG <long@example.com>" &&
1059	git format-patch --stdout -1 >patch &&
1060	# bump from, date, and subject down to in-body header
1061	perl -lpe "
1062		if (/^From:/) {
1063			print \"From: x <x\@example.com>\";
1064			print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
1065			print \"Subject: x\n\";
1066		}
1067	" patch >msg &&
1068	git checkout HEAD^ &&
1069	git am msg &&
1070	# Ensure that the author and full message are present
1071	git cat-file commit HEAD | grep "^author.*long@example.com" &&
1072	git cat-file commit HEAD | grep "^$LONG$"
1073'
1074
1075test_expect_success 'am --quit keeps HEAD where it is' '
1076	mkdir .git/rebase-apply &&
1077	>.git/rebase-apply/last &&
1078	>.git/rebase-apply/next &&
1079	git rev-parse HEAD^ >.git/ORIG_HEAD &&
1080	git rev-parse HEAD >expected &&
1081	git am --quit &&
1082	test_path_is_missing .git/rebase-apply &&
1083	git rev-parse HEAD >actual &&
1084	test_cmp expected actual
1085'
1086
1087test_expect_success 'am and .gitattibutes' '
1088	test_create_repo attributes &&
1089	(
1090		cd attributes &&
1091		test_commit init &&
1092		git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
1093		git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
1094
1095		test_commit second &&
1096		git checkout -b test HEAD^ &&
1097
1098		echo "*.txt filter=test conflict-marker-size=10" >.gitattributes &&
1099		git add .gitattributes &&
1100		test_commit third &&
1101
1102		echo "This text is smudged." >a.txt &&
1103		git add a.txt &&
1104		test_commit fourth &&
1105
1106		git checkout -b removal HEAD^ &&
1107		git rm .gitattributes &&
1108		git add -u &&
1109		test_commit fifth &&
1110		git cherry-pick test &&
1111
1112		git checkout -b conflict third &&
1113		echo "This text is different." >a.txt &&
1114		git add a.txt &&
1115		test_commit sixth &&
1116
1117		git checkout test &&
1118		git format-patch --stdout main..HEAD >patches &&
1119		git reset --hard main &&
1120		git am patches &&
1121		grep "smudged" a.txt &&
1122
1123		git checkout removal &&
1124		git reset --hard &&
1125		git format-patch --stdout main..HEAD >patches &&
1126		git reset --hard main &&
1127		git am patches &&
1128		grep "clean" a.txt &&
1129
1130		git checkout conflict &&
1131		git reset --hard &&
1132		git format-patch --stdout main..HEAD >patches &&
1133		git reset --hard fourth &&
1134		test_must_fail git am -3 patches &&
1135		grep "<<<<<<<<<<" a.txt
1136	)
1137'
1138
1139test_expect_success 'apply binary blob in partial clone' '
1140	printf "\\000" >binary &&
1141	git add binary &&
1142	git commit -m "binary blob" &&
1143	git format-patch --stdout -m HEAD^ >patch &&
1144
1145	test_create_repo server &&
1146	test_config -C server uploadpack.allowfilter 1 &&
1147	test_config -C server uploadpack.allowanysha1inwant 1 &&
1148	git clone --filter=blob:none "file://$(pwd)/server" client &&
1149	test_when_finished "rm -rf client" &&
1150
1151	# Exercise to make sure that it works
1152	git -C client am ../patch
1153'
1154
1155test_done
1156