1#!/bin/sh
2#
3# Copyright (c) 2007 Johannes E. Schindelin
4#
5
6test_description='Test commit notes'
7
8. ./test-lib.sh
9
10write_script fake_editor <<\EOF
11echo "$MSG" >"$1"
12echo "$MSG" >&2
13EOF
14GIT_EDITOR=./fake_editor
15export GIT_EDITOR
16
17indent="    "
18
19test_expect_success 'cannot annotate non-existing HEAD' '
20	test_must_fail env MSG=3 git notes add
21'
22
23test_expect_success 'setup' '
24	test_commit 1st &&
25	test_commit 2nd
26'
27
28test_expect_success 'need valid notes ref' '
29	test_must_fail env MSG=1 GIT_NOTES_REF=/ git notes show &&
30	test_must_fail env MSG=2 GIT_NOTES_REF=/ git notes show
31'
32
33test_expect_success 'refusing to add notes in refs/heads/' '
34	test_must_fail env MSG=1 GIT_NOTES_REF=refs/heads/bogus git notes add
35'
36
37test_expect_success 'refusing to edit notes in refs/remotes/' '
38	test_must_fail env MSG=1 GIT_NOTES_REF=refs/heads/bogus git notes edit
39'
40
41# 1 indicates caught gracefully by die, 128 means git-show barked
42test_expect_success 'handle empty notes gracefully' '
43	test_expect_code 1 git notes show
44'
45
46test_expect_success 'show non-existent notes entry with %N' '
47	test_write_lines A B >expect &&
48	git show -s --format="A%n%NB" >actual &&
49	test_cmp expect actual
50'
51
52test_expect_success 'create notes' '
53	MSG=b4 git notes add &&
54	test_path_is_missing .git/NOTES_EDITMSG &&
55	git ls-tree -r refs/notes/commits >actual &&
56	test_line_count = 1 actual &&
57	echo b4 >expect &&
58	git notes show >actual &&
59	test_cmp expect actual &&
60	git show HEAD^ &&
61	test_must_fail git notes show HEAD^
62'
63
64test_expect_success 'show notes entry with %N' '
65	test_write_lines A b4 B >expect &&
66	git show -s --format="A%n%NB" >actual &&
67	test_cmp expect actual
68'
69
70test_expect_success 'create reflog entry' '
71	ref=$(git rev-parse --short refs/notes/commits) &&
72	cat <<-EOF >expect &&
73		$ref refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\''
74	EOF
75	git reflog show refs/notes/commits >actual &&
76	test_cmp expect actual
77'
78
79test_expect_success 'edit existing notes' '
80	MSG=b3 git notes edit &&
81	test_path_is_missing .git/NOTES_EDITMSG &&
82	git ls-tree -r refs/notes/commits >actual &&
83	test_line_count = 1 actual &&
84	echo b3 >expect &&
85	git notes show >actual &&
86	test_cmp expect actual &&
87	git show HEAD^ &&
88	test_must_fail git notes show HEAD^
89'
90
91test_expect_success 'show notes from treeish' '
92	echo b3 >expect &&
93	git notes --ref commits^{tree} show >actual &&
94	test_cmp expect actual &&
95
96	echo b4 >expect &&
97	git notes --ref commits@{1} show >actual &&
98	test_cmp expect actual
99'
100
101test_expect_success 'cannot edit notes from non-ref' '
102	test_must_fail git notes --ref commits^{tree} edit &&
103	test_must_fail git notes --ref commits@{1} edit
104'
105
106test_expect_success 'cannot "git notes add -m" where notes already exists' '
107	test_must_fail git notes add -m "b2" &&
108	test_path_is_missing .git/NOTES_EDITMSG &&
109	git ls-tree -r refs/notes/commits >actual &&
110	test_line_count = 1 actual &&
111	echo b3 >expect &&
112	git notes show >actual &&
113	test_cmp expect actual &&
114	git show HEAD^ &&
115	test_must_fail git notes show HEAD^
116'
117
118test_expect_success 'can overwrite existing note with "git notes add -f -m"' '
119	git notes add -f -m "b1" &&
120	test_path_is_missing .git/NOTES_EDITMSG &&
121	git ls-tree -r refs/notes/commits >actual &&
122	test_line_count = 1 actual &&
123	echo b1 >expect &&
124	git notes show >actual &&
125	test_cmp expect actual &&
126	git show HEAD^ &&
127	test_must_fail git notes show HEAD^
128'
129
130test_expect_success 'add w/no options on existing note morphs into edit' '
131	MSG=b2 git notes add &&
132	test_path_is_missing .git/NOTES_EDITMSG &&
133	git ls-tree -r refs/notes/commits >actual &&
134	test_line_count = 1 actual &&
135	echo b2 >expect &&
136	git notes show >actual &&
137	test_cmp expect actual &&
138	git show HEAD^ &&
139	test_must_fail git notes show HEAD^
140'
141
142test_expect_success 'can overwrite existing note with "git notes add -f"' '
143	MSG=b1 git notes add -f &&
144	test_path_is_missing .git/NOTES_EDITMSG &&
145	git ls-tree -r refs/notes/commits >actual &&
146	test_line_count = 1 actual &&
147	echo b1 >expect &&
148	git notes show >actual &&
149	test_cmp expect actual &&
150	git show HEAD^ &&
151	test_must_fail git notes show HEAD^
152'
153
154test_expect_success 'show notes' '
155	commit=$(git rev-parse HEAD) &&
156	cat >expect <<-EOF &&
157		commit $commit
158		Author: A U Thor <author@example.com>
159		Date:   Thu Apr 7 15:14:13 2005 -0700
160
161		${indent}2nd
162
163		Notes:
164		${indent}b1
165	EOF
166	git cat-file commit HEAD >commits &&
167	! grep b1 commits &&
168	git log -1 >actual &&
169	test_cmp expect actual
170'
171
172test_expect_success 'show multi-line notes' '
173	test_commit 3rd &&
174	MSG="b3${LF}c3c3c3c3${LF}d3d3d3" git notes add &&
175	commit=$(git rev-parse HEAD) &&
176	cat >expect-multiline <<-EOF &&
177		commit $commit
178		Author: A U Thor <author@example.com>
179		Date:   Thu Apr 7 15:15:13 2005 -0700
180
181		${indent}3rd
182
183		Notes:
184		${indent}b3
185		${indent}c3c3c3c3
186		${indent}d3d3d3
187
188	EOF
189	cat expect >>expect-multiline &&
190	git log -2 >actual &&
191	test_cmp expect-multiline actual
192'
193
194test_expect_success 'show -F notes' '
195	test_commit 4th &&
196	echo "xyzzy" >note5 &&
197	git notes add -F note5 &&
198	commit=$(git rev-parse HEAD) &&
199	cat >expect-F <<-EOF &&
200		commit $commit
201		Author: A U Thor <author@example.com>
202		Date:   Thu Apr 7 15:16:13 2005 -0700
203
204		${indent}4th
205
206		Notes:
207		${indent}xyzzy
208
209	EOF
210	cat expect-multiline >>expect-F &&
211	git log -3 >actual &&
212	test_cmp expect-F actual
213'
214
215test_expect_success 'Re-adding -F notes without -f fails' '
216	echo "zyxxy" >note5 &&
217	test_must_fail git notes add -F note5 &&
218	git log -3 >actual &&
219	test_cmp expect-F actual
220'
221
222test_expect_success 'git log --pretty=raw does not show notes' '
223	commit=$(git rev-parse HEAD) &&
224	tree=$(git rev-parse HEAD^{tree}) &&
225	parent=$(git rev-parse HEAD^) &&
226	cat >expect <<-EOF &&
227		commit $commit
228		tree $tree
229		parent $parent
230		author A U Thor <author@example.com> 1112912173 -0700
231		committer C O Mitter <committer@example.com> 1112912173 -0700
232
233		${indent}4th
234	EOF
235	git log -1 --pretty=raw >actual &&
236	test_cmp expect actual
237'
238
239test_expect_success 'git log --show-notes' '
240	cat >>expect <<-EOF &&
241
242	Notes:
243	${indent}xyzzy
244	EOF
245	git log -1 --pretty=raw --show-notes >actual &&
246	test_cmp expect actual
247'
248
249test_expect_success 'git log --no-notes' '
250	git log -1 --no-notes >actual &&
251	! grep xyzzy actual
252'
253
254test_expect_success 'git format-patch does not show notes' '
255	git format-patch -1 --stdout >actual &&
256	! grep xyzzy actual
257'
258
259test_expect_success 'git format-patch --show-notes does show notes' '
260	git format-patch --show-notes -1 --stdout >actual &&
261	grep xyzzy actual
262'
263
264for pretty in \
265	"" --pretty --pretty=raw --pretty=short --pretty=medium \
266	--pretty=full --pretty=fuller --pretty=format:%s --oneline
267do
268	case "$pretty" in
269	"") p= not= negate="" ;;
270	?*) p="$pretty" not=" not" negate="!" ;;
271	esac
272	test_expect_success "git show $pretty does$not show notes" '
273		git show $p >actual &&
274		eval "$negate grep xyzzy actual"
275	'
276done
277
278test_expect_success 'setup alternate notes ref' '
279	git notes --ref=alternate add -m alternate
280'
281
282test_expect_success 'git log --notes shows default notes' '
283	git log -1 --notes >actual &&
284	grep xyzzy actual &&
285	! grep alternate actual
286'
287
288test_expect_success 'git log --notes=X shows only X' '
289	git log -1 --notes=alternate >actual &&
290	! grep xyzzy actual &&
291	grep alternate actual
292'
293
294test_expect_success 'git log --notes --notes=X shows both' '
295	git log -1 --notes --notes=alternate >actual &&
296	grep xyzzy actual &&
297	grep alternate actual
298'
299
300test_expect_success 'git log --no-notes resets default state' '
301	git log -1 --notes --notes=alternate \
302		--no-notes --notes=alternate \
303		>actual &&
304	! grep xyzzy actual &&
305	grep alternate actual
306'
307
308test_expect_success 'git log --no-notes resets ref list' '
309	git log -1 --notes --notes=alternate \
310		--no-notes --notes \
311		>actual &&
312	grep xyzzy actual &&
313	! grep alternate actual
314'
315
316test_expect_success 'show -m notes' '
317	test_commit 5th &&
318	git notes add -m spam -m "foo${LF}bar${LF}baz" &&
319	commit=$(git rev-parse HEAD) &&
320	cat >expect-m <<-EOF &&
321		commit $commit
322		Author: A U Thor <author@example.com>
323		Date:   Thu Apr 7 15:17:13 2005 -0700
324
325		${indent}5th
326
327		Notes:
328		${indent}spam
329		${indent}
330		${indent}foo
331		${indent}bar
332		${indent}baz
333
334	EOF
335	cat expect-F >>expect-m &&
336	git log -4 >actual &&
337	test_cmp expect-m actual
338'
339
340test_expect_success 'remove note with add -f -F /dev/null' '
341	git notes add -f -F /dev/null &&
342	commit=$(git rev-parse HEAD) &&
343	cat >expect-rm-F <<-EOF &&
344		commit $commit
345		Author: A U Thor <author@example.com>
346		Date:   Thu Apr 7 15:17:13 2005 -0700
347
348		${indent}5th
349
350	EOF
351	cat expect-F >>expect-rm-F &&
352	git log -4 >actual &&
353	test_cmp expect-rm-F actual &&
354	test_must_fail git notes show
355'
356
357test_expect_success 'do not create empty note with -m ""' '
358	git notes add -m "" &&
359	git log -4 >actual &&
360	test_cmp expect-rm-F actual &&
361	test_must_fail git notes show
362'
363
364test_expect_success 'create note with combination of -m and -F' '
365	cat >expect-combine_m_and_F <<-EOF &&
366		foo
367
368		xyzzy
369
370		bar
371
372		zyxxy
373
374		baz
375	EOF
376	echo "xyzzy" >note_a &&
377	echo "zyxxy" >note_b &&
378	git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" &&
379	git notes show >actual &&
380	test_cmp expect-combine_m_and_F actual
381'
382
383test_expect_success 'remove note with "git notes remove"' '
384	git notes remove HEAD^ &&
385	git notes remove &&
386	commit=$(git rev-parse HEAD) &&
387	parent=$(git rev-parse HEAD^) &&
388	cat >expect-rm-remove <<-EOF &&
389		commit $commit
390		Author: A U Thor <author@example.com>
391		Date:   Thu Apr 7 15:17:13 2005 -0700
392
393		${indent}5th
394
395		commit $parent
396		Author: A U Thor <author@example.com>
397		Date:   Thu Apr 7 15:16:13 2005 -0700
398
399		${indent}4th
400
401	EOF
402	cat expect-multiline >>expect-rm-remove &&
403	git log -4 >actual &&
404	test_cmp expect-rm-remove actual &&
405	test_must_fail git notes show HEAD^
406'
407
408test_expect_success 'removing non-existing note should not create new commit' '
409	git rev-parse --verify refs/notes/commits >before_commit &&
410	test_must_fail git notes remove HEAD^ &&
411	git rev-parse --verify refs/notes/commits >after_commit &&
412	test_cmp before_commit after_commit
413'
414
415test_expect_success 'removing more than one' '
416	before=$(git rev-parse --verify refs/notes/commits) &&
417	test_when_finished "git update-ref refs/notes/commits $before" &&
418
419	# We have only two -- add another and make sure it stays
420	git notes add -m "extra" &&
421	git notes list HEAD >after-removal-expect &&
422	git notes remove HEAD^^ HEAD^^^ &&
423	git notes list | sed -e "s/ .*//" >actual &&
424	test_cmp after-removal-expect actual
425'
426
427test_expect_success 'removing is atomic' '
428	before=$(git rev-parse --verify refs/notes/commits) &&
429	test_when_finished "git update-ref refs/notes/commits $before" &&
430	test_must_fail git notes remove HEAD^^ HEAD^^^ HEAD^ &&
431	after=$(git rev-parse --verify refs/notes/commits) &&
432	test "$before" = "$after"
433'
434
435test_expect_success 'removing with --ignore-missing' '
436	before=$(git rev-parse --verify refs/notes/commits) &&
437	test_when_finished "git update-ref refs/notes/commits $before" &&
438
439	# We have only two -- add another and make sure it stays
440	git notes add -m "extra" &&
441	git notes list HEAD >after-removal-expect &&
442	git notes remove --ignore-missing HEAD^^ HEAD^^^ HEAD^ &&
443	git notes list | sed -e "s/ .*//" >actual &&
444	test_cmp after-removal-expect actual
445'
446
447test_expect_success 'removing with --ignore-missing but bogus ref' '
448	before=$(git rev-parse --verify refs/notes/commits) &&
449	test_when_finished "git update-ref refs/notes/commits $before" &&
450	test_must_fail git notes remove --ignore-missing HEAD^^ HEAD^^^ NO-SUCH-COMMIT &&
451	after=$(git rev-parse --verify refs/notes/commits) &&
452	test "$before" = "$after"
453'
454
455test_expect_success 'remove reads from --stdin' '
456	before=$(git rev-parse --verify refs/notes/commits) &&
457	test_when_finished "git update-ref refs/notes/commits $before" &&
458
459	# We have only two -- add another and make sure it stays
460	git notes add -m "extra" &&
461	git notes list HEAD >after-removal-expect &&
462	git rev-parse HEAD^^ HEAD^^^ >input &&
463	git notes remove --stdin <input &&
464	git notes list | sed -e "s/ .*//" >actual &&
465	test_cmp after-removal-expect actual
466'
467
468test_expect_success 'remove --stdin is also atomic' '
469	before=$(git rev-parse --verify refs/notes/commits) &&
470	test_when_finished "git update-ref refs/notes/commits $before" &&
471	git rev-parse HEAD^^ HEAD^^^ HEAD^ >input &&
472	test_must_fail git notes remove --stdin <input &&
473	after=$(git rev-parse --verify refs/notes/commits) &&
474	test "$before" = "$after"
475'
476
477test_expect_success 'removing with --stdin --ignore-missing' '
478	before=$(git rev-parse --verify refs/notes/commits) &&
479	test_when_finished "git update-ref refs/notes/commits $before" &&
480
481	# We have only two -- add another and make sure it stays
482	git notes add -m "extra" &&
483	git notes list HEAD >after-removal-expect &&
484	git rev-parse HEAD^^ HEAD^^^ HEAD^ >input &&
485	git notes remove --ignore-missing --stdin <input &&
486	git notes list | sed -e "s/ .*//" >actual &&
487	test_cmp after-removal-expect actual
488'
489
490test_expect_success 'list notes with "git notes list"' '
491	commit_2=$(git rev-parse 2nd) &&
492	commit_3=$(git rev-parse 3rd) &&
493	note_2=$(git rev-parse refs/notes/commits:$commit_2) &&
494	note_3=$(git rev-parse refs/notes/commits:$commit_3) &&
495	sort -t" " -k2 >expect <<-EOF &&
496		$note_2 $commit_2
497		$note_3 $commit_3
498	EOF
499	git notes list >actual &&
500	test_cmp expect actual
501'
502
503test_expect_success 'list notes with "git notes"' '
504	git notes >actual &&
505	test_cmp expect actual
506'
507
508test_expect_success 'list specific note with "git notes list <object>"' '
509	git rev-parse refs/notes/commits:$commit_3 >expect &&
510	git notes list HEAD^^ >actual &&
511	test_cmp expect actual
512'
513
514test_expect_success 'listing non-existing notes fails' '
515	test_must_fail git notes list HEAD >actual &&
516	test_must_be_empty actual
517'
518
519test_expect_success 'append to existing note with "git notes append"' '
520	cat >expect <<-EOF &&
521		Initial set of notes
522
523		More notes appended with git notes append
524	EOF
525	git notes add -m "Initial set of notes" &&
526	git notes append -m "More notes appended with git notes append" &&
527	git notes show >actual &&
528	test_cmp expect actual
529'
530
531test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
532	commit_5=$(git rev-parse 5th) &&
533	note_5=$(git rev-parse refs/notes/commits:$commit_5) &&
534	sort -t" " -k2 >expect_list <<-EOF &&
535		$note_2 $commit_2
536		$note_3 $commit_3
537		$note_5 $commit_5
538	EOF
539	git notes list >actual &&
540	test_cmp expect_list actual
541'
542
543test_expect_success 'appending empty string does not change existing note' '
544	git notes append -m "" &&
545	git notes show >actual &&
546	test_cmp expect actual
547'
548
549test_expect_success 'git notes append == add when there is no existing note' '
550	git notes remove HEAD &&
551	test_must_fail git notes list HEAD &&
552	git notes append -m "Initial set of notes${LF}${LF}More notes appended with git notes append" &&
553	git notes show >actual &&
554	test_cmp expect actual
555'
556
557test_expect_success 'appending empty string to non-existing note does not create note' '
558	git notes remove HEAD &&
559	test_must_fail git notes list HEAD &&
560	git notes append -m "" &&
561	test_must_fail git notes list HEAD
562'
563
564test_expect_success 'create other note on a different notes ref (setup)' '
565	test_commit 6th &&
566	GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" &&
567	commit=$(git rev-parse HEAD) &&
568	cat >expect-not-other <<-EOF &&
569		commit $commit
570		Author: A U Thor <author@example.com>
571		Date:   Thu Apr 7 15:18:13 2005 -0700
572
573		${indent}6th
574	EOF
575	cp expect-not-other expect-other &&
576	cat >>expect-other <<-EOF
577
578		Notes (other):
579		${indent}other note
580	EOF
581'
582
583test_expect_success 'Do not show note on other ref by default' '
584	git log -1 >actual &&
585	test_cmp expect-not-other actual
586'
587
588test_expect_success 'Do show note when ref is given in GIT_NOTES_REF' '
589	GIT_NOTES_REF="refs/notes/other" git log -1 >actual &&
590	test_cmp expect-other actual
591'
592
593test_expect_success 'Do show note when ref is given in core.notesRef config' '
594	test_config core.notesRef "refs/notes/other" &&
595	git log -1 >actual &&
596	test_cmp expect-other actual
597'
598
599test_expect_success 'Do not show note when core.notesRef is overridden' '
600	test_config core.notesRef "refs/notes/other" &&
601	GIT_NOTES_REF="refs/notes/wrong" git log -1 >actual &&
602	test_cmp expect-not-other actual
603'
604
605test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
606	commit=$(git rev-parse HEAD) &&
607	parent=$(git rev-parse HEAD^) &&
608	cat >expect-both <<-EOF &&
609		commit $commit
610		Author: A U Thor <author@example.com>
611		Date:   Thu Apr 7 15:18:13 2005 -0700
612
613		${indent}6th
614
615		Notes:
616		${indent}order test
617
618		Notes (other):
619		${indent}other note
620
621		commit $parent
622		Author: A U Thor <author@example.com>
623		Date:   Thu Apr 7 15:17:13 2005 -0700
624
625		${indent}5th
626
627		Notes:
628		${indent}replacement for deleted note
629	EOF
630	GIT_NOTES_REF=refs/notes/commits git notes add \
631		-m"replacement for deleted note" HEAD^ &&
632	GIT_NOTES_REF=refs/notes/commits git notes add -m"order test" &&
633	test_unconfig core.notesRef &&
634	test_config notes.displayRef "refs/notes/*" &&
635	git log -2 >actual &&
636	test_cmp expect-both actual
637'
638
639test_expect_success 'core.notesRef is implicitly in notes.displayRef' '
640	test_config core.notesRef refs/notes/commits &&
641	test_config notes.displayRef refs/notes/other &&
642	git log -2 >actual &&
643	test_cmp expect-both actual
644'
645
646test_expect_success 'notes.displayRef can be given more than once' '
647	test_unconfig core.notesRef &&
648	test_config notes.displayRef refs/notes/commits &&
649	git config --add notes.displayRef refs/notes/other &&
650	git log -2 >actual &&
651	test_cmp expect-both actual
652'
653
654test_expect_success 'notes.displayRef respects order' '
655	commit=$(git rev-parse HEAD) &&
656	cat >expect-both-reversed <<-EOF &&
657		commit $commit
658		Author: A U Thor <author@example.com>
659		Date:   Thu Apr 7 15:18:13 2005 -0700
660
661		${indent}6th
662
663		Notes (other):
664		${indent}other note
665
666		Notes:
667		${indent}order test
668	EOF
669	test_config core.notesRef refs/notes/other &&
670	test_config notes.displayRef refs/notes/commits &&
671	git log -1 >actual &&
672	test_cmp expect-both-reversed actual
673'
674
675test_expect_success 'notes.displayRef with no value handled gracefully' '
676	test_must_fail git -c notes.displayRef log -0 --notes &&
677	test_must_fail git -c notes.displayRef diff-tree --notes HEAD
678'
679
680test_expect_success 'GIT_NOTES_DISPLAY_REF works' '
681	GIT_NOTES_DISPLAY_REF=refs/notes/commits:refs/notes/other \
682		git log -2 >actual &&
683	test_cmp expect-both actual
684'
685
686test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
687	commit=$(git rev-parse HEAD) &&
688	parent=$(git rev-parse HEAD^) &&
689	cat >expect-none <<-EOF &&
690		commit $commit
691		Author: A U Thor <author@example.com>
692		Date:   Thu Apr 7 15:18:13 2005 -0700
693
694		${indent}6th
695
696		commit $parent
697		Author: A U Thor <author@example.com>
698		Date:   Thu Apr 7 15:17:13 2005 -0700
699
700		${indent}5th
701	EOF
702	test_config notes.displayRef "refs/notes/*" &&
703	GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 >actual &&
704	test_cmp expect-none actual
705'
706
707test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' '
708	GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 >actual &&
709	test_cmp expect-both actual
710'
711
712test_expect_success '--no-standard-notes' '
713	commit=$(git rev-parse HEAD) &&
714	cat >expect-commits <<-EOF &&
715		commit $commit
716		Author: A U Thor <author@example.com>
717		Date:   Thu Apr 7 15:18:13 2005 -0700
718
719		${indent}6th
720
721		Notes:
722		${indent}order test
723	EOF
724	git log --no-standard-notes --show-notes=commits -1 >actual &&
725	test_cmp expect-commits actual
726'
727
728test_expect_success '--standard-notes' '
729	test_config notes.displayRef "refs/notes/*" &&
730	git log --no-standard-notes --show-notes=commits \
731		--standard-notes -2 >actual &&
732	test_cmp expect-both actual
733'
734
735test_expect_success '--show-notes=ref accumulates' '
736	git log --show-notes=other --show-notes=commits \
737		 --no-standard-notes -1 >actual &&
738	test_cmp expect-both-reversed actual
739'
740
741test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
742	test_config core.notesRef refs/notes/other &&
743	echo "Note on a tree" >expect &&
744	git notes add -m "Note on a tree" HEAD: &&
745	git notes show HEAD: >actual &&
746	test_cmp expect actual &&
747	echo "Note on a blob" >expect &&
748	git ls-tree --name-only HEAD >files &&
749	filename=$(head -n1 files) &&
750	git notes add -m "Note on a blob" HEAD:$filename &&
751	git notes show HEAD:$filename >actual &&
752	test_cmp expect actual &&
753	echo "Note on a tag" >expect &&
754	git tag -a -m "This is an annotated tag" foobar HEAD^ &&
755	git notes add -m "Note on a tag" foobar &&
756	git notes show foobar >actual &&
757	test_cmp expect actual
758'
759
760test_expect_success 'create note from other note with "git notes add -C"' '
761	test_commit 7th &&
762	commit=$(git rev-parse HEAD) &&
763	cat >expect <<-EOF &&
764		commit $commit
765		Author: A U Thor <author@example.com>
766		Date:   Thu Apr 7 15:19:13 2005 -0700
767
768		${indent}7th
769
770		Notes:
771		${indent}order test
772	EOF
773	note=$(git notes list HEAD^) &&
774	git notes add -C $note &&
775	git log -1 >actual &&
776	test_cmp expect actual &&
777	git notes list HEAD^ >expect &&
778	git notes list HEAD >actual &&
779	test_cmp expect actual
780'
781
782test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
783	test_commit 8th &&
784	test_must_fail git notes add -C deadbeef &&
785	test_must_fail git notes list HEAD
786'
787
788test_expect_success 'create note from non-blob with "git notes add -C" fails' '
789	commit=$(git rev-parse --verify HEAD) &&
790	tree=$(git rev-parse --verify HEAD:) &&
791	test_must_fail git notes add -C $commit &&
792	test_must_fail git notes add -C $tree &&
793	test_must_fail git notes list HEAD
794'
795
796test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
797	commit=$(git rev-parse HEAD) &&
798	cat >expect <<-EOF &&
799		commit $commit
800		Author: A U Thor <author@example.com>
801		Date:   Thu Apr 7 15:20:13 2005 -0700
802
803		${indent}8th
804
805		Notes:
806		${indent}This is a blob object
807	EOF
808	echo "This is a blob object" | git hash-object -w --stdin >blob &&
809	git notes add -C $(cat blob) &&
810	git log -1 >actual &&
811	test_cmp expect actual &&
812	git notes list HEAD >actual &&
813	test_cmp blob actual
814'
815
816test_expect_success 'create note from other note with "git notes add -c"' '
817	test_commit 9th &&
818	commit=$(git rev-parse HEAD) &&
819	cat >expect <<-EOF &&
820		commit $commit
821		Author: A U Thor <author@example.com>
822		Date:   Thu Apr 7 15:21:13 2005 -0700
823
824		${indent}9th
825
826		Notes:
827		${indent}yet another note
828	EOF
829	note=$(git notes list HEAD^^) &&
830	MSG="yet another note" git notes add -c $note &&
831	git log -1 >actual &&
832	test_cmp expect actual
833'
834
835test_expect_success 'create note from non-existing note with "git notes add -c" fails' '
836	test_commit 10th &&
837	test_must_fail env MSG="yet another note" git notes add -c deadbeef &&
838	test_must_fail git notes list HEAD
839'
840
841test_expect_success 'append to note from other note with "git notes append -C"' '
842	commit=$(git rev-parse HEAD^) &&
843	cat >expect <<-EOF &&
844		commit $commit
845		Author: A U Thor <author@example.com>
846		Date:   Thu Apr 7 15:21:13 2005 -0700
847
848		${indent}9th
849
850		Notes:
851		${indent}yet another note
852		${indent}
853		${indent}yet another note
854	EOF
855	note=$(git notes list HEAD^) &&
856	git notes append -C $note HEAD^ &&
857	git log -1 HEAD^ >actual &&
858	test_cmp expect actual
859'
860
861test_expect_success 'create note from other note with "git notes append -c"' '
862	commit=$(git rev-parse HEAD) &&
863	cat >expect <<-EOF &&
864		commit $commit
865		Author: A U Thor <author@example.com>
866		Date:   Thu Apr 7 15:22:13 2005 -0700
867
868		${indent}10th
869
870		Notes:
871		${indent}other note
872	EOF
873	note=$(git notes list HEAD^) &&
874	MSG="other note" git notes append -c $note &&
875	git log -1 >actual &&
876	test_cmp expect actual
877'
878
879test_expect_success 'append to note from other note with "git notes append -c"' '
880	commit=$(git rev-parse HEAD) &&
881	cat >expect <<-EOF &&
882		commit $commit
883		Author: A U Thor <author@example.com>
884		Date:   Thu Apr 7 15:22:13 2005 -0700
885
886		${indent}10th
887
888		Notes:
889		${indent}other note
890		${indent}
891		${indent}yet another note
892	EOF
893	note=$(git notes list HEAD) &&
894	MSG="yet another note" git notes append -c $note &&
895	git log -1 >actual &&
896	test_cmp expect actual
897'
898
899test_expect_success 'copy note with "git notes copy"' '
900	commit=$(git rev-parse 4th) &&
901	cat >expect <<-EOF &&
902		commit $commit
903		Author: A U Thor <author@example.com>
904		Date:   Thu Apr 7 15:16:13 2005 -0700
905
906		${indent}4th
907
908		Notes:
909		${indent}This is a blob object
910	EOF
911	git notes copy 8th 4th &&
912	git log 3rd..4th >actual &&
913	test_cmp expect actual &&
914	git notes list 4th >expect &&
915	git notes list 8th >actual &&
916	test_cmp expect actual
917'
918
919test_expect_success 'copy note with "git notes copy" with default' '
920	test_commit 11th &&
921	commit=$(git rev-parse HEAD) &&
922	cat >expect <<-EOF &&
923		commit $commit
924		Author: A U Thor <author@example.com>
925		Date:   Thu Apr 7 15:23:13 2005 -0700
926
927		${indent}11th
928
929		Notes:
930		${indent}other note
931		${indent}
932		${indent}yet another note
933	EOF
934	git notes copy HEAD^ &&
935	git log -1 >actual &&
936	test_cmp expect actual &&
937	git notes list HEAD^ >expect &&
938	git notes list HEAD >actual &&
939	test_cmp expect actual
940'
941
942test_expect_success 'prevent overwrite with "git notes copy"' '
943	test_must_fail git notes copy HEAD~2 HEAD &&
944	cat >expect <<-EOF &&
945		commit $commit
946		Author: A U Thor <author@example.com>
947		Date:   Thu Apr 7 15:23:13 2005 -0700
948
949		${indent}11th
950
951		Notes:
952		${indent}other note
953		${indent}
954		${indent}yet another note
955	EOF
956	git log -1 >actual &&
957	test_cmp expect actual &&
958	git notes list HEAD^ >expect &&
959	git notes list HEAD >actual &&
960	test_cmp expect actual
961'
962
963test_expect_success 'allow overwrite with "git notes copy -f"' '
964	commit=$(git rev-parse HEAD) &&
965	cat >expect <<-EOF &&
966		commit $commit
967		Author: A U Thor <author@example.com>
968		Date:   Thu Apr 7 15:23:13 2005 -0700
969
970		${indent}11th
971
972		Notes:
973		${indent}This is a blob object
974	EOF
975	git notes copy -f HEAD~3 HEAD &&
976	git log -1 >actual &&
977	test_cmp expect actual &&
978	git notes list HEAD~3 >expect &&
979	git notes list HEAD >actual &&
980	test_cmp expect actual
981'
982
983test_expect_success 'allow overwrite with "git notes copy -f" with default' '
984	commit=$(git rev-parse HEAD) &&
985	cat >expect <<-EOF &&
986		commit $commit
987		Author: A U Thor <author@example.com>
988		Date:   Thu Apr 7 15:23:13 2005 -0700
989
990		${indent}11th
991
992		Notes:
993		${indent}yet another note
994		${indent}
995		${indent}yet another note
996	EOF
997	git notes copy -f HEAD~2 &&
998	git log -1 >actual &&
999	test_cmp expect actual &&
1000	git notes list HEAD~2 >expect &&
1001	git notes list HEAD >actual &&
1002	test_cmp expect actual
1003'
1004
1005test_expect_success 'cannot copy note from object without notes' '
1006	test_commit 12th &&
1007	test_commit 13th &&
1008	test_must_fail git notes copy HEAD^ HEAD
1009'
1010
1011test_expect_success 'git notes copy --stdin' '
1012	commit=$(git rev-parse HEAD) &&
1013	parent=$(git rev-parse HEAD^) &&
1014	cat >expect <<-EOF &&
1015		commit $commit
1016		Author: A U Thor <author@example.com>
1017		Date:   Thu Apr 7 15:25:13 2005 -0700
1018
1019		${indent}13th
1020
1021		Notes:
1022		${indent}yet another note
1023		${indent}
1024		${indent}yet another note
1025
1026		commit $parent
1027		Author: A U Thor <author@example.com>
1028		Date:   Thu Apr 7 15:24:13 2005 -0700
1029
1030		${indent}12th
1031
1032		Notes:
1033		${indent}other note
1034		${indent}
1035		${indent}yet another note
1036	EOF
1037	from=$(git rev-parse HEAD~3) &&
1038	to=$(git rev-parse HEAD^) &&
1039	echo "$from" "$to" >copy &&
1040	from=$(git rev-parse HEAD~2) &&
1041	to=$(git rev-parse HEAD) &&
1042	echo "$from" "$to" >>copy &&
1043	git notes copy --stdin <copy &&
1044	git log -2 >actual &&
1045	test_cmp expect actual &&
1046	git notes list HEAD~2 >expect &&
1047	git notes list HEAD >actual &&
1048	test_cmp expect actual &&
1049	git notes list HEAD~3 >expect &&
1050	git notes list HEAD^ >actual &&
1051	test_cmp expect actual
1052'
1053
1054test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
1055	test_commit 14th &&
1056	test_commit 15th &&
1057	commit=$(git rev-parse HEAD) &&
1058	parent=$(git rev-parse HEAD^) &&
1059	cat >expect <<-EOF &&
1060		commit $commit
1061		Author: A U Thor <author@example.com>
1062		Date:   Thu Apr 7 15:27:13 2005 -0700
1063
1064		${indent}15th
1065
1066		commit $parent
1067		Author: A U Thor <author@example.com>
1068		Date:   Thu Apr 7 15:26:13 2005 -0700
1069
1070		${indent}14th
1071	EOF
1072	from=$(git rev-parse HEAD~3) &&
1073	to=$(git rev-parse HEAD^) &&
1074	echo "$from" "$to" >copy &&
1075	from=$(git rev-parse HEAD~2) &&
1076	to=$(git rev-parse HEAD) &&
1077	echo "$from" "$to" >>copy &&
1078	git notes copy --for-rewrite=foo <copy &&
1079	git log -2 >actual &&
1080	test_cmp expect actual
1081'
1082
1083test_expect_success 'git notes copy --for-rewrite (enabled)' '
1084	commit=$(git rev-parse HEAD) &&
1085	parent=$(git rev-parse HEAD^) &&
1086	cat >expect <<-EOF &&
1087		commit $commit
1088		Author: A U Thor <author@example.com>
1089		Date:   Thu Apr 7 15:27:13 2005 -0700
1090
1091		${indent}15th
1092
1093		Notes:
1094		${indent}yet another note
1095		${indent}
1096		${indent}yet another note
1097
1098		commit $parent
1099		Author: A U Thor <author@example.com>
1100		Date:   Thu Apr 7 15:26:13 2005 -0700
1101
1102		${indent}14th
1103
1104		Notes:
1105		${indent}other note
1106		${indent}
1107		${indent}yet another note
1108	EOF
1109	test_config notes.rewriteMode overwrite &&
1110	test_config notes.rewriteRef "refs/notes/*" &&
1111	from=$(git rev-parse HEAD~3) &&
1112	to=$(git rev-parse HEAD^) &&
1113	echo "$from" "$to" >copy &&
1114	from=$(git rev-parse HEAD~2) &&
1115	to=$(git rev-parse HEAD) &&
1116	echo "$from" "$to" >>copy &&
1117	git notes copy --for-rewrite=foo <copy &&
1118	git log -2 >actual &&
1119	test_cmp expect actual
1120'
1121
1122test_expect_success 'git notes copy --for-rewrite (disabled)' '
1123	test_config notes.rewrite.bar false &&
1124	from=$(git rev-parse HEAD~3) &&
1125	to=$(git rev-parse HEAD) &&
1126	echo "$from" "$to" >copy &&
1127	git notes copy --for-rewrite=bar <copy &&
1128	git log -2 >actual &&
1129	test_cmp expect actual
1130'
1131
1132test_expect_success 'git notes copy --for-rewrite (overwrite)' '
1133	commit=$(git rev-parse HEAD) &&
1134	cat >expect <<-EOF &&
1135		commit $commit
1136		Author: A U Thor <author@example.com>
1137		Date:   Thu Apr 7 15:27:13 2005 -0700
1138
1139		${indent}15th
1140
1141		Notes:
1142		${indent}a fresh note
1143	EOF
1144	git notes add -f -m"a fresh note" HEAD^ &&
1145	test_config notes.rewriteMode overwrite &&
1146	test_config notes.rewriteRef "refs/notes/*" &&
1147	from=$(git rev-parse HEAD^) &&
1148	to=$(git rev-parse HEAD) &&
1149	echo "$from" "$to" >copy &&
1150	git notes copy --for-rewrite=foo <copy &&
1151	git log -1 >actual &&
1152	test_cmp expect actual
1153'
1154
1155test_expect_success 'git notes copy --for-rewrite (ignore)' '
1156	test_config notes.rewriteMode ignore &&
1157	test_config notes.rewriteRef "refs/notes/*" &&
1158	from=$(git rev-parse HEAD^) &&
1159	to=$(git rev-parse HEAD) &&
1160	echo "$from" "$to" >copy &&
1161	git notes copy --for-rewrite=foo <copy &&
1162	git log -1 >actual &&
1163	test_cmp expect actual
1164'
1165
1166test_expect_success 'git notes copy --for-rewrite (append)' '
1167	commit=$(git rev-parse HEAD) &&
1168	cat >expect <<-EOF &&
1169		commit $commit
1170		Author: A U Thor <author@example.com>
1171		Date:   Thu Apr 7 15:27:13 2005 -0700
1172
1173		${indent}15th
1174
1175		Notes:
1176		${indent}a fresh note
1177		${indent}
1178		${indent}another fresh note
1179	EOF
1180	git notes add -f -m"another fresh note" HEAD^ &&
1181	test_config notes.rewriteMode concatenate &&
1182	test_config notes.rewriteRef "refs/notes/*" &&
1183	from=$(git rev-parse HEAD^) &&
1184	to=$(git rev-parse HEAD) &&
1185	echo "$from" "$to" >copy &&
1186	git notes copy --for-rewrite=foo <copy &&
1187	git log -1 >actual &&
1188	test_cmp expect actual
1189'
1190
1191test_expect_success 'git notes copy --for-rewrite (append two to one)' '
1192	commit=$(git rev-parse HEAD) &&
1193	cat >expect <<-EOF &&
1194		commit $commit
1195		Author: A U Thor <author@example.com>
1196		Date:   Thu Apr 7 15:27:13 2005 -0700
1197
1198		${indent}15th
1199
1200		Notes:
1201		${indent}a fresh note
1202		${indent}
1203		${indent}another fresh note
1204		${indent}
1205		${indent}append 1
1206		${indent}
1207		${indent}append 2
1208	EOF
1209	git notes add -f -m"append 1" HEAD^ &&
1210	git notes add -f -m"append 2" HEAD^^ &&
1211	test_config notes.rewriteMode concatenate &&
1212	test_config notes.rewriteRef "refs/notes/*" &&
1213	from=$(git rev-parse HEAD^) &&
1214	to=$(git rev-parse HEAD) &&
1215	echo "$from" "$to" >copy &&
1216	from=$(git rev-parse HEAD^^) &&
1217	to=$(git rev-parse HEAD) &&
1218	echo "$from" "$to" >>copy &&
1219	git notes copy --for-rewrite=foo <copy &&
1220	git log -1 >actual &&
1221	test_cmp expect actual
1222'
1223
1224test_expect_success 'git notes copy --for-rewrite (append empty)' '
1225	git notes remove HEAD^ &&
1226	test_config notes.rewriteMode concatenate &&
1227	test_config notes.rewriteRef "refs/notes/*" &&
1228	from=$(git rev-parse HEAD^) &&
1229	to=$(git rev-parse HEAD) &&
1230	echo "$from" "$to" >copy &&
1231	git notes copy --for-rewrite=foo <copy &&
1232	git log -1 >actual &&
1233	test_cmp expect actual
1234'
1235
1236test_expect_success 'GIT_NOTES_REWRITE_MODE works' '
1237	commit=$(git rev-parse HEAD) &&
1238	cat >expect <<-EOF &&
1239		commit $commit
1240		Author: A U Thor <author@example.com>
1241		Date:   Thu Apr 7 15:27:13 2005 -0700
1242
1243		${indent}15th
1244
1245		Notes:
1246		${indent}replacement note 1
1247	EOF
1248	test_config notes.rewriteMode concatenate &&
1249	test_config notes.rewriteRef "refs/notes/*" &&
1250	git notes add -f -m"replacement note 1" HEAD^ &&
1251	from=$(git rev-parse HEAD^) &&
1252	to=$(git rev-parse HEAD) &&
1253	echo "$from" "$to" >copy &&
1254	GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo <copy &&
1255	git log -1 >actual &&
1256	test_cmp expect actual
1257'
1258
1259test_expect_success 'GIT_NOTES_REWRITE_REF works' '
1260	commit=$(git rev-parse HEAD) &&
1261	cat >expect <<-EOF &&
1262		commit $commit
1263		Author: A U Thor <author@example.com>
1264		Date:   Thu Apr 7 15:27:13 2005 -0700
1265
1266		${indent}15th
1267
1268		Notes:
1269		${indent}replacement note 2
1270	EOF
1271	git notes add -f -m"replacement note 2" HEAD^ &&
1272	test_config notes.rewriteMode overwrite &&
1273	test_unconfig notes.rewriteRef &&
1274	from=$(git rev-parse HEAD^) &&
1275	to=$(git rev-parse HEAD) &&
1276	echo "$from" "$to" >copy &&
1277	GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \
1278		git notes copy --for-rewrite=foo <copy &&
1279	git log -1 >actual &&
1280	test_cmp expect actual
1281'
1282
1283test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '
1284	git notes add -f -m"replacement note 3" HEAD^ &&
1285	test_config notes.rewriteMode overwrite &&
1286	test_config notes.rewriteRef refs/notes/other &&
1287	from=$(git rev-parse HEAD^) &&
1288	to=$(git rev-parse HEAD) &&
1289	echo "$from" "$to" >copy &&
1290	GIT_NOTES_REWRITE_REF=refs/notes/commits \
1291		git notes copy --for-rewrite=foo <copy &&
1292	git log -1 >actual &&
1293	grep "replacement note 3" actual
1294'
1295
1296test_expect_success 'git notes copy diagnoses too many or too few arguments' '
1297	test_must_fail git notes copy 2>error &&
1298	test_i18ngrep "too few arguments" error &&
1299	test_must_fail git notes copy one two three 2>error &&
1300	test_i18ngrep "too many arguments" error
1301'
1302
1303test_expect_success 'git notes get-ref expands refs/heads/main to refs/notes/refs/heads/main' '
1304	test_unconfig core.notesRef &&
1305	sane_unset GIT_NOTES_REF &&
1306	echo refs/notes/refs/heads/main >expect &&
1307	git notes --ref=refs/heads/main get-ref >actual &&
1308	test_cmp expect actual
1309'
1310
1311test_expect_success 'git notes get-ref (no overrides)' '
1312	test_unconfig core.notesRef &&
1313	sane_unset GIT_NOTES_REF &&
1314	echo refs/notes/commits >expect &&
1315	git notes get-ref >actual &&
1316	test_cmp expect actual
1317'
1318
1319test_expect_success 'git notes get-ref (core.notesRef)' '
1320	test_config core.notesRef refs/notes/foo &&
1321	echo refs/notes/foo >expect &&
1322	git notes get-ref >actual &&
1323	test_cmp expect actual
1324'
1325
1326test_expect_success 'git notes get-ref (GIT_NOTES_REF)' '
1327	echo refs/notes/bar >expect &&
1328	GIT_NOTES_REF=refs/notes/bar git notes get-ref >actual &&
1329	test_cmp expect actual
1330'
1331
1332test_expect_success 'git notes get-ref (--ref)' '
1333	echo refs/notes/baz >expect &&
1334	GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref >actual &&
1335	test_cmp expect actual
1336'
1337
1338test_expect_success 'setup testing of empty notes' '
1339	test_unconfig core.notesRef &&
1340	test_commit 16th &&
1341	empty_blob=$(git hash-object -w /dev/null) &&
1342	echo "$empty_blob" >expect_empty
1343'
1344
1345while read cmd
1346do
1347	test_expect_success "'git notes $cmd' removes empty note" "
1348		test_might_fail git notes remove HEAD &&
1349		MSG= git notes $cmd &&
1350		test_must_fail git notes list HEAD
1351	"
1352
1353	test_expect_success "'git notes $cmd --allow-empty' stores empty note" "
1354		test_might_fail git notes remove HEAD &&
1355		MSG= git notes $cmd --allow-empty &&
1356		git notes list HEAD >actual &&
1357		test_cmp expect_empty actual
1358	"
1359done <<\EOF
1360add
1361add -F /dev/null
1362add -m ""
1363add -c "$empty_blob"
1364add -C "$empty_blob"
1365append
1366append -F /dev/null
1367append -m ""
1368append -c "$empty_blob"
1369append -C "$empty_blob"
1370edit
1371EOF
1372
1373test_expect_success 'empty notes are displayed by git log' '
1374	test_commit 17th &&
1375	git log -1 >expect &&
1376	cat >>expect <<-EOF &&
1377
1378		Notes:
1379	EOF
1380	git notes add -C "$empty_blob" --allow-empty &&
1381	git log -1 >actual &&
1382	test_cmp expect actual
1383'
1384
1385test_done
1386