1#!/bin/sh
2#
3# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
4# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
5#
6
7test_description='Support for verbose submodule differences in git diff
8
9This test tries to verify the sanity of the --submodule option of git diff.
10'
11
12GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
13export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
14
15. ./test-lib.sh
16
17# Tested non-UTF-8 encoding
18test_encoding="ISO8859-1"
19
20# String "added" in German (translated with Google Translate), encoded in UTF-8,
21# used in sample commit log messages in add_file() function below.
22added=$(printf "hinzugef\303\274gt")
23add_file () {
24	(
25		cd "$1" &&
26		shift &&
27		for name
28		do
29			echo "$name" >"$name" &&
30			git add "$name" &&
31			test_tick &&
32			# "git commit -m" would break MinGW, as Windows refuse to pass
33			# $test_encoding encoded parameter to git.
34			echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding |
35			git -c "i18n.commitEncoding=$test_encoding" commit -F -
36		done >/dev/null &&
37		git rev-parse --short --verify HEAD
38	)
39}
40commit_file () {
41	test_tick &&
42	git commit "$@" -m "Commit $*" >/dev/null
43}
44
45test_create_repo sm1 &&
46add_file . foo >/dev/null
47
48head1=$(add_file sm1 foo1 foo2)
49fullhead1=$(cd sm1; git rev-parse --verify HEAD)
50
51test_expect_success 'added submodule' '
52	git add sm1 &&
53	git diff-index -p --submodule=log HEAD >actual &&
54	cat >expected <<-EOF &&
55	Submodule sm1 0000000...$head1 (new submodule)
56	EOF
57	test_cmp expected actual
58'
59
60test_expect_success 'added submodule, set diff.submodule' '
61	git config diff.submodule log &&
62	git add sm1 &&
63	git diff --cached >actual &&
64	cat >expected <<-EOF &&
65	Submodule sm1 0000000...$head1 (new submodule)
66	EOF
67	git config --unset diff.submodule &&
68	test_cmp expected actual
69'
70
71test_expect_success '--submodule=short overrides diff.submodule' '
72	test_config diff.submodule log &&
73	git add sm1 &&
74	git diff --submodule=short --cached >actual &&
75	cat >expected <<-EOF &&
76	diff --git a/sm1 b/sm1
77	new file mode 160000
78	index 0000000..$head1
79	--- /dev/null
80	+++ b/sm1
81	@@ -0,0 +1 @@
82	+Subproject commit $fullhead1
83	EOF
84	test_cmp expected actual
85'
86
87test_expect_success 'diff.submodule does not affect plumbing' '
88	test_config diff.submodule log &&
89	git diff-index -p HEAD >actual &&
90	cat >expected <<-EOF &&
91	diff --git a/sm1 b/sm1
92	new file mode 160000
93	index 0000000..$head1
94	--- /dev/null
95	+++ b/sm1
96	@@ -0,0 +1 @@
97	+Subproject commit $fullhead1
98	EOF
99	test_cmp expected actual
100'
101
102commit_file sm1 &&
103head2=$(add_file sm1 foo3)
104
105test_expect_success 'modified submodule(forward)' '
106	git diff-index -p --submodule=log HEAD >actual &&
107	cat >expected <<-EOF &&
108	Submodule sm1 $head1..$head2:
109	  > Add foo3 ($added foo3)
110	EOF
111	test_cmp expected actual
112'
113
114test_expect_success 'modified submodule(forward)' '
115	git diff --submodule=log >actual &&
116	cat >expected <<-EOF &&
117	Submodule sm1 $head1..$head2:
118	  > Add foo3 ($added foo3)
119	EOF
120	test_cmp expected actual
121'
122
123test_expect_success 'modified submodule(forward) --submodule' '
124	git diff --submodule >actual &&
125	cat >expected <<-EOF &&
126	Submodule sm1 $head1..$head2:
127	  > Add foo3 ($added foo3)
128	EOF
129	test_cmp expected actual
130'
131
132fullhead2=$(cd sm1; git rev-parse --verify HEAD)
133test_expect_success 'modified submodule(forward) --submodule=short' '
134	git diff --submodule=short >actual &&
135	cat >expected <<-EOF &&
136	diff --git a/sm1 b/sm1
137	index $head1..$head2 160000
138	--- a/sm1
139	+++ b/sm1
140	@@ -1 +1 @@
141	-Subproject commit $fullhead1
142	+Subproject commit $fullhead2
143	EOF
144	test_cmp expected actual
145'
146
147commit_file sm1 &&
148head3=$(
149	cd sm1 &&
150	git reset --hard HEAD~2 >/dev/null &&
151	git rev-parse --short --verify HEAD
152)
153
154test_expect_success 'modified submodule(backward)' '
155	git diff-index -p --submodule=log HEAD >actual &&
156	cat >expected <<-EOF &&
157	Submodule sm1 $head2..$head3 (rewind):
158	  < Add foo3 ($added foo3)
159	  < Add foo2 ($added foo2)
160	EOF
161	test_cmp expected actual
162'
163
164head4=$(add_file sm1 foo4 foo5)
165test_expect_success 'modified submodule(backward and forward)' '
166	git diff-index -p --submodule=log HEAD >actual &&
167	cat >expected <<-EOF &&
168	Submodule sm1 $head2...$head4:
169	  > Add foo5 ($added foo5)
170	  > Add foo4 ($added foo4)
171	  < Add foo3 ($added foo3)
172	  < Add foo2 ($added foo2)
173	EOF
174	test_cmp expected actual
175'
176
177commit_file sm1 &&
178mv sm1 sm1-bak &&
179echo sm1 >sm1 &&
180head5=$(git hash-object sm1 | cut -c1-7) &&
181git add sm1 &&
182rm -f sm1 &&
183mv sm1-bak sm1
184
185test_expect_success 'typechanged submodule(submodule->blob), --cached' '
186	git diff --submodule=log --cached >actual &&
187	cat >expected <<-EOF &&
188	Submodule sm1 $head4...0000000 (submodule deleted)
189	diff --git a/sm1 b/sm1
190	new file mode 100644
191	index 0000000..$head5
192	--- /dev/null
193	+++ b/sm1
194	@@ -0,0 +1 @@
195	+sm1
196	EOF
197	test_cmp expected actual
198'
199
200test_expect_success 'typechanged submodule(submodule->blob)' '
201	git diff --submodule=log >actual &&
202	cat >expected <<-EOF &&
203	diff --git a/sm1 b/sm1
204	deleted file mode 100644
205	index $head5..0000000
206	--- a/sm1
207	+++ /dev/null
208	@@ -1 +0,0 @@
209	-sm1
210	Submodule sm1 0000000...$head4 (new submodule)
211	EOF
212	test_cmp expected actual
213'
214
215rm -rf sm1 &&
216git checkout-index sm1
217test_expect_success 'typechanged submodule(submodule->blob)' '
218	git diff-index -p --submodule=log HEAD >actual &&
219	cat >expected <<-EOF &&
220	Submodule sm1 $head4...0000000 (submodule deleted)
221	diff --git a/sm1 b/sm1
222	new file mode 100644
223	index 0000000..$head5
224	--- /dev/null
225	+++ b/sm1
226	@@ -0,0 +1 @@
227	+sm1
228	EOF
229	test_cmp expected actual
230'
231
232rm -f sm1 &&
233test_create_repo sm1 &&
234head6=$(add_file sm1 foo6 foo7)
235fullhead6=$(cd sm1; git rev-parse --verify HEAD)
236test_expect_success 'nonexistent commit' '
237	git diff-index -p --submodule=log HEAD >actual &&
238	cat >expected <<-EOF &&
239	Submodule sm1 $head4...$head6 (commits not present)
240	EOF
241	test_cmp expected actual
242'
243
244commit_file
245test_expect_success 'typechanged submodule(blob->submodule)' '
246	git diff-index -p --submodule=log HEAD >actual &&
247	cat >expected <<-EOF &&
248	diff --git a/sm1 b/sm1
249	deleted file mode 100644
250	index $head5..0000000
251	--- a/sm1
252	+++ /dev/null
253	@@ -1 +0,0 @@
254	-sm1
255	Submodule sm1 0000000...$head6 (new submodule)
256	EOF
257	test_cmp expected actual
258'
259
260commit_file sm1 &&
261test_expect_success 'submodule is up to date' '
262	git diff-index -p --submodule=log HEAD >actual &&
263	test_must_be_empty actual
264'
265
266test_expect_success 'submodule contains untracked content' '
267	echo new > sm1/new-file &&
268	git diff-index -p --ignore-submodules=none --submodule=log HEAD >actual &&
269	cat >expected <<-EOF &&
270	Submodule sm1 contains untracked content
271	EOF
272	test_cmp expected actual
273'
274
275test_expect_success 'submodule contains untracked content (untracked ignored)' '
276	git diff-index -p --submodule=log HEAD >actual &&
277	test_must_be_empty actual
278'
279
280test_expect_success 'submodule contains untracked content (dirty ignored)' '
281	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
282	test_must_be_empty actual
283'
284
285test_expect_success 'submodule contains untracked content (all ignored)' '
286	git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual &&
287	test_must_be_empty actual
288'
289
290test_expect_success 'submodule contains untracked and modified content' '
291	echo new > sm1/foo6 &&
292	git diff-index -p --ignore-submodules=none --submodule=log HEAD >actual &&
293	cat >expected <<-EOF &&
294	Submodule sm1 contains untracked content
295	Submodule sm1 contains modified content
296	EOF
297	test_cmp expected actual
298'
299
300test_expect_success 'submodule contains untracked and modified content (untracked ignored)' '
301	echo new > sm1/foo6 &&
302	git diff-index -p --submodule=log HEAD >actual &&
303	cat >expected <<-EOF &&
304	Submodule sm1 contains modified content
305	EOF
306	test_cmp expected actual
307'
308
309test_expect_success 'submodule contains untracked and modified content (dirty ignored)' '
310	echo new > sm1/foo6 &&
311	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
312	test_must_be_empty actual
313'
314
315test_expect_success 'submodule contains untracked and modified content (all ignored)' '
316	echo new > sm1/foo6 &&
317	git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
318	test_must_be_empty actual
319'
320
321test_expect_success 'submodule contains modified content' '
322	rm -f sm1/new-file &&
323	git diff-index -p --submodule=log HEAD >actual &&
324	cat >expected <<-EOF &&
325	Submodule sm1 contains modified content
326	EOF
327	test_cmp expected actual
328'
329
330(cd sm1; git commit -mchange foo6 >/dev/null) &&
331head8=$(cd sm1; git rev-parse --short --verify HEAD) &&
332test_expect_success 'submodule is modified' '
333	git diff-index -p --submodule=log HEAD >actual &&
334	cat >expected <<-EOF &&
335	Submodule sm1 $head6..$head8:
336	  > change
337	EOF
338	test_cmp expected actual
339'
340
341test_expect_success 'modified submodule contains untracked content' '
342	echo new > sm1/new-file &&
343	git diff-index -p  --ignore-submodules=none --submodule=log HEAD >actual &&
344	cat >expected <<-EOF &&
345	Submodule sm1 contains untracked content
346	Submodule sm1 $head6..$head8:
347	  > change
348	EOF
349	test_cmp expected actual
350'
351
352test_expect_success 'modified submodule contains untracked content (untracked ignored)' '
353	git diff-index -p --submodule=log HEAD >actual &&
354	cat >expected <<-EOF &&
355	Submodule sm1 $head6..$head8:
356	  > change
357	EOF
358	test_cmp expected actual
359'
360
361test_expect_success 'modified submodule contains untracked content (dirty ignored)' '
362	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
363	cat >expected <<-EOF &&
364	Submodule sm1 $head6..$head8:
365	  > change
366	EOF
367	test_cmp expected actual
368'
369
370test_expect_success 'modified submodule contains untracked content (all ignored)' '
371	git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual &&
372	test_must_be_empty actual
373'
374
375test_expect_success 'modified submodule contains untracked and modified content' '
376	echo modification >> sm1/foo6 &&
377	git diff-index -p --ignore-submodules=none --submodule=log HEAD >actual &&
378	cat >expected <<-EOF &&
379	Submodule sm1 contains untracked content
380	Submodule sm1 contains modified content
381	Submodule sm1 $head6..$head8:
382	  > change
383	EOF
384	test_cmp expected actual
385'
386
387test_expect_success 'modified submodule contains untracked and modified content (untracked ignored)' '
388	echo modification >> sm1/foo6 &&
389	git diff-index -p --submodule=log HEAD >actual &&
390	cat >expected <<-EOF &&
391	Submodule sm1 contains modified content
392	Submodule sm1 $head6..$head8:
393	  > change
394	EOF
395	test_cmp expected actual
396'
397
398test_expect_success 'modified submodule contains untracked and modified content (dirty ignored)' '
399	echo modification >> sm1/foo6 &&
400	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
401	cat >expected <<-EOF &&
402	Submodule sm1 $head6..$head8:
403	  > change
404	EOF
405	test_cmp expected actual
406'
407
408test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '
409	echo modification >> sm1/foo6 &&
410	git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
411	test_must_be_empty actual
412'
413
414test_expect_success 'modified submodule contains modified content' '
415	rm -f sm1/new-file &&
416	git diff-index -p --submodule=log HEAD >actual &&
417	cat >expected <<-EOF &&
418	Submodule sm1 contains modified content
419	Submodule sm1 $head6..$head8:
420	  > change
421	EOF
422	test_cmp expected actual
423'
424
425rm -rf sm1
426test_expect_success 'deleted submodule' '
427	git diff-index -p --submodule=log HEAD >actual &&
428	cat >expected <<-EOF &&
429	Submodule sm1 $head6...0000000 (submodule deleted)
430	EOF
431	test_cmp expected actual
432'
433
434test_expect_success 'create second submodule' '
435	test_create_repo sm2 &&
436	head7=$(add_file sm2 foo8 foo9) &&
437	git add sm2
438'
439
440test_expect_success 'multiple submodules' '
441	git diff-index -p --submodule=log HEAD >actual &&
442	cat >expected <<-EOF &&
443	Submodule sm1 $head6...0000000 (submodule deleted)
444	Submodule sm2 0000000...$head7 (new submodule)
445	EOF
446	test_cmp expected actual
447'
448
449test_expect_success 'path filter' '
450	git diff-index -p --submodule=log HEAD sm2 >actual &&
451	cat >expected <<-EOF &&
452	Submodule sm2 0000000...$head7 (new submodule)
453	EOF
454	test_cmp expected actual
455'
456
457commit_file sm2
458test_expect_success 'given commit' '
459	git diff-index -p --submodule=log HEAD^ >actual &&
460	cat >expected <<-EOF &&
461	Submodule sm1 $head6...0000000 (submodule deleted)
462	Submodule sm2 0000000...$head7 (new submodule)
463	EOF
464	test_cmp expected actual
465'
466
467test_expect_success 'given commit --submodule' '
468	git diff-index -p --submodule HEAD^ >actual &&
469	cat >expected <<-EOF &&
470	Submodule sm1 $head6...0000000 (submodule deleted)
471	Submodule sm2 0000000...$head7 (new submodule)
472	EOF
473	test_cmp expected actual
474'
475
476fullhead7=$(cd sm2; git rev-parse --verify HEAD)
477
478test_expect_success 'given commit --submodule=short' '
479	git diff-index -p --submodule=short HEAD^ >actual &&
480	cat >expected <<-EOF &&
481	diff --git a/sm1 b/sm1
482	deleted file mode 160000
483	index $head6..0000000
484	--- a/sm1
485	+++ /dev/null
486	@@ -1 +0,0 @@
487	-Subproject commit $fullhead6
488	diff --git a/sm2 b/sm2
489	new file mode 160000
490	index 0000000..$head7
491	--- /dev/null
492	+++ b/sm2
493	@@ -0,0 +1 @@
494	+Subproject commit $fullhead7
495	EOF
496	test_cmp expected actual
497'
498
499test_expect_success 'setup .git file for sm2' '
500	(cd sm2 &&
501	 REAL="$(pwd)/../.real" &&
502	 mv .git "$REAL" &&
503	 echo "gitdir: $REAL" >.git)
504'
505
506test_expect_success 'diff --submodule with .git file' '
507	git diff --submodule HEAD^ >actual &&
508	cat >expected <<-EOF &&
509	Submodule sm1 $head6...0000000 (submodule deleted)
510	Submodule sm2 0000000...$head7 (new submodule)
511	EOF
512	test_cmp expected actual
513'
514
515test_expect_success 'diff --submodule with objects referenced by alternates' '
516	mkdir sub_alt &&
517	(cd sub_alt &&
518		git init &&
519		echo a >a &&
520		git add a &&
521		git commit -m a
522	) &&
523	mkdir super &&
524	(cd super &&
525		git clone -s ../sub_alt sub &&
526		git init &&
527		git add sub &&
528		git commit -m "sub a"
529	) &&
530	(cd sub_alt &&
531		sha1_before=$(git rev-parse --short HEAD) &&
532		echo b >b &&
533		git add b &&
534		git commit -m b &&
535		sha1_after=$(git rev-parse --short HEAD) &&
536		{
537			echo "Submodule sub $sha1_before..$sha1_after:" &&
538			echo "  > b"
539		} >../expected
540	) &&
541	(cd super &&
542		(cd sub &&
543			git fetch &&
544			git checkout origin/main
545		) &&
546		git diff --submodule > ../actual
547	) &&
548	test_cmp expected actual
549'
550
551test_done
552