Merge branch 'js/fsmonitor-unpack-fix'
[git] / t / t9301-fast-import-notes.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2009 Johan Herland
4 #
5
6 test_description='test git fast-import of notes objects'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9
10 . ./test-lib.sh
11
12
13 test_tick
14 cat >input <<INPUT_END
15 commit refs/heads/main
16 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
17 data <<COMMIT
18 first commit
19 COMMIT
20
21 M 644 inline foo
22 data <<EOF
23 file foo in first commit
24 EOF
25
26 M 755 inline bar
27 data <<EOF
28 file bar in first commit
29 EOF
30
31 M 644 inline baz/xyzzy
32 data <<EOF
33 file baz/xyzzy in first commit
34 EOF
35
36 commit refs/heads/main
37 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
38 data <<COMMIT
39 second commit
40 COMMIT
41
42 M 644 inline foo
43 data <<EOF
44 file foo in second commit
45 EOF
46
47 M 755 inline baz/xyzzy
48 data <<EOF
49 file baz/xyzzy in second commit
50 EOF
51
52 commit refs/heads/main
53 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
54 data <<COMMIT
55 third commit
56 COMMIT
57
58 M 644 inline foo
59 data <<EOF
60 file foo in third commit
61 EOF
62
63 commit refs/heads/main
64 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
65 data <<COMMIT
66 fourth commit
67 COMMIT
68
69 M 755 inline bar
70 data <<EOF
71 file bar in fourth commit
72 EOF
73
74 INPUT_END
75
76 test_expect_success 'set up main branch' '
77
78         git fast-import <input &&
79         git whatchanged main
80 '
81
82 commit4=$(git rev-parse refs/heads/main)
83 commit3=$(git rev-parse "$commit4^")
84 commit2=$(git rev-parse "$commit4~2")
85 commit1=$(git rev-parse "$commit4~3")
86
87 test_tick
88 cat >input <<INPUT_END
89 commit refs/notes/test
90 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
91 data <<COMMIT
92 first notes commit
93 COMMIT
94
95 M 644 inline $commit1
96 data <<EOF
97 first note for first commit
98 EOF
99
100 M 755 inline $commit2
101 data <<EOF
102 first note for second commit
103 EOF
104
105 INPUT_END
106
107 cat >expect <<EXPECT_END
108     fourth commit
109     third commit
110     second commit
111     first note for second commit
112     first commit
113     first note for first commit
114 EXPECT_END
115
116 test_expect_success 'add notes with simple M command' '
117
118         git fast-import <input &&
119         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
120         test_cmp expect actual
121
122 '
123
124 test_tick
125 cat >input <<INPUT_END
126 feature notes
127 commit refs/notes/test
128 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
129 data <<COMMIT
130 second notes commit
131 COMMIT
132
133 from refs/notes/test^0
134 N inline $commit3
135 data <<EOF
136 first note for third commit
137 EOF
138
139 N inline $commit4
140 data <<EOF
141 first note for fourth commit
142 EOF
143
144 INPUT_END
145
146 cat >expect <<EXPECT_END
147     fourth commit
148     first note for fourth commit
149     third commit
150     first note for third commit
151     second commit
152     first note for second commit
153     first commit
154     first note for first commit
155 EXPECT_END
156
157 test_expect_success 'add notes with simple N command' '
158
159         git fast-import <input &&
160         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
161         test_cmp expect actual
162
163 '
164
165 test_tick
166 cat >input <<INPUT_END
167 commit refs/notes/test
168 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
169 data <<COMMIT
170 third notes commit
171 COMMIT
172
173 from refs/notes/test^0
174 N inline $commit1
175 data <<EOF
176 second note for first commit
177 EOF
178
179 N inline $commit2
180 data <<EOF
181 second note for second commit
182 EOF
183
184 N inline $commit3
185 data <<EOF
186 second note for third commit
187 EOF
188
189 N inline $commit4
190 data <<EOF
191 second note for fourth commit
192 EOF
193
194 INPUT_END
195
196 cat >expect <<EXPECT_END
197     fourth commit
198     second note for fourth commit
199     third commit
200     second note for third commit
201     second commit
202     second note for second commit
203     first commit
204     second note for first commit
205 EXPECT_END
206
207 test_expect_success 'update existing notes with N command' '
208
209         git fast-import <input &&
210         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
211         test_cmp expect actual
212
213 '
214
215 test_tick
216 cat >input <<INPUT_END
217 commit refs/notes/test
218 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
219 data <<COMMIT
220 fourth notes commit
221 COMMIT
222
223 from refs/notes/test^0
224 M 644 inline $(echo "$commit3" | sed "s|^..|&/|")
225 data <<EOF
226 prefix of note for third commit
227 EOF
228
229 M 644 inline $(echo "$commit4" | sed "s|^..|&/|")
230 data <<EOF
231 prefix of note for fourth commit
232 EOF
233
234 M 644 inline $(echo "$commit4" | sed "s|^\(..\)\(..\)|\1/\2/|")
235 data <<EOF
236 pre-prefix of note for fourth commit
237 EOF
238
239 N inline $commit1
240 data <<EOF
241 third note for first commit
242 EOF
243
244 N inline $commit2
245 data <<EOF
246 third note for second commit
247 EOF
248
249 N inline $commit3
250 data <<EOF
251 third note for third commit
252 EOF
253
254 N inline $commit4
255 data <<EOF
256 third note for fourth commit
257 EOF
258
259
260 INPUT_END
261
262 whitespace="    "
263
264 cat >expect <<EXPECT_END
265     fourth commit
266     pre-prefix of note for fourth commit
267 $whitespace
268     prefix of note for fourth commit
269 $whitespace
270     third note for fourth commit
271     third commit
272     prefix of note for third commit
273 $whitespace
274     third note for third commit
275     second commit
276     third note for second commit
277     first commit
278     third note for first commit
279 EXPECT_END
280
281 test_expect_success 'add concatenation notes with M command' '
282
283         git fast-import <input &&
284         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
285         test_cmp expect actual
286
287 '
288
289 test_tick
290 cat >input <<INPUT_END
291 commit refs/notes/test
292 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
293 data <<COMMIT
294 fifth notes commit
295 COMMIT
296
297 from refs/notes/test^0
298 deleteall
299
300 INPUT_END
301
302 cat >expect <<EXPECT_END
303     fourth commit
304     third commit
305     second commit
306     first commit
307 EXPECT_END
308
309 test_expect_success 'verify that deleteall also removes notes' '
310
311         git fast-import <input &&
312         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
313         test_cmp expect actual
314
315 '
316
317 test_tick
318 cat >input <<INPUT_END
319 commit refs/notes/test
320 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
321 data <<COMMIT
322 sixth notes commit
323 COMMIT
324
325 from refs/notes/test^0
326 M 644 inline $commit1
327 data <<EOF
328 third note for first commit
329 EOF
330
331 M 644 inline $commit3
332 data <<EOF
333 third note for third commit
334 EOF
335
336 N inline $commit1
337 data <<EOF
338 fourth note for first commit
339 EOF
340
341 N inline $commit3
342 data <<EOF
343 fourth note for third commit
344 EOF
345
346 INPUT_END
347
348 cat >expect <<EXPECT_END
349     fourth commit
350     third commit
351     fourth note for third commit
352     second commit
353     first commit
354     fourth note for first commit
355 EXPECT_END
356
357 test_expect_success 'verify that later N commands override earlier M commands' '
358
359         git fast-import <input &&
360         GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
361         test_cmp expect actual
362
363 '
364
365 # Write fast-import commands to create the given number of commits
366 fast_import_commits () {
367         my_ref=$1
368         my_num_commits=$2
369         my_append_to_file=$3
370         my_i=0
371         while test $my_i -lt $my_num_commits
372         do
373                 my_i=$(($my_i + 1))
374                 test_tick
375                 cat >>"$my_append_to_file" <<INPUT_END
376 commit $my_ref
377 mark :$my_i
378 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
379 data <<COMMIT
380 commit #$my_i
381 COMMIT
382
383 M 644 inline file
384 data <<EOF
385 file contents in commit #$my_i
386 EOF
387
388 INPUT_END
389         done
390 }
391
392 # Write fast-import commands to create the given number of notes annotating
393 # the commits created by fast_import_commits()
394 fast_import_notes () {
395         my_notes_ref=$1
396         my_num_commits=$2
397         my_append_to_file=$3
398         my_note_append=$4
399         test_tick
400         cat >>"$my_append_to_file" <<INPUT_END
401 commit $my_notes_ref
402 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
403 data <<COMMIT
404 committing $my_num_commits notes
405 COMMIT
406
407 INPUT_END
408
409         my_i=0
410         while test $my_i -lt $my_num_commits
411         do
412                 my_i=$(($my_i + 1))
413                 cat >>"$my_append_to_file" <<INPUT_END
414 N inline :$my_i
415 data <<EOF
416 note for commit #$my_i$my_note_append
417 EOF
418
419 INPUT_END
420         done
421 }
422
423
424 rm input expect
425 num_commits=400
426 # Create lots of commits
427 fast_import_commits "refs/heads/many_commits" $num_commits input
428 # Create one note per above commit
429 fast_import_notes "refs/notes/many_notes" $num_commits input
430 # Add a couple of non-notes as well
431 test_tick
432 cat >>input <<INPUT_END
433 commit refs/notes/many_notes
434 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
435 data <<COMMIT
436 committing some non-notes to the notes tree
437 COMMIT
438
439 M 755 inline foobar/non-note.txt
440 data <<EOF
441 This is not a note, but rather a regular file residing in a notes tree
442 EOF
443
444 M 644 inline deadbeef
445 data <<EOF
446 Non-note file
447 EOF
448
449 M 644 inline de/adbeef
450 data <<EOF
451 Another non-note file
452 EOF
453
454 INPUT_END
455 # Finally create the expected output from all these notes and commits
456 i=$num_commits
457 while test $i -gt 0
458 do
459         cat >>expect <<EXPECT_END
460     commit #$i
461     note for commit #$i
462 EXPECT_END
463         i=$(($i - 1))
464 done
465
466 test_expect_success 'add lots of commits and notes' '
467
468         git fast-import <input &&
469         GIT_NOTES_REF=refs/notes/many_notes git log refs/heads/many_commits |
470             grep "^    " > actual &&
471         test_cmp expect actual
472
473 '
474
475 test_expect_success 'verify that lots of notes trigger a fanout scheme' '
476         hexsz=$(test_oid hexsz) &&
477
478         # None of the entries in the top-level notes tree should be a full SHA1
479         git ls-tree --name-only refs/notes/many_notes |
480         while read path
481         do
482                 if test $(expr length "$path") -ge $hexsz
483                 then
484                         return 1
485                 fi
486         done
487
488 '
489
490 # Create another notes tree from the one above
491 SP=" "
492 cat >>input <<INPUT_END
493 commit refs/heads/other_commits
494 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
495 data <<COMMIT
496 commit #$(($num_commit + 1))
497 COMMIT
498
499 from refs/heads/many_commits
500 M 644 inline file
501 data <<EOF
502 file contents in commit #$(($num_commit + 1))
503 EOF
504
505 commit refs/notes/other_notes
506 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
507 data <<COMMIT
508 committing one more note on a tree imported from a previous notes tree
509 COMMIT
510
511 M 040000 $(git log --no-walk --format=%T refs/notes/many_notes)$SP
512 N inline :$(($num_commit + 1))
513 data <<EOF
514 note for commit #$(($num_commit + 1))
515 EOF
516 INPUT_END
517
518 test_expect_success 'verify that importing a notes tree respects the fanout scheme' '
519         git fast-import <input &&
520
521         # None of the entries in the top-level notes tree should be a full SHA1
522         git ls-tree --name-only refs/notes/other_notes |
523         while read path
524         do
525                 if test $(expr length "$path") -ge $hexsz
526                 then
527                         return 1
528                 fi
529         done
530 '
531
532 cat >>expect_non-note1 << EOF
533 This is not a note, but rather a regular file residing in a notes tree
534 EOF
535
536 cat >>expect_non-note2 << EOF
537 Non-note file
538 EOF
539
540 cat >>expect_non-note3 << EOF
541 Another non-note file
542 EOF
543
544 test_expect_success 'verify that non-notes are untouched by a fanout change' '
545
546         git cat-file -p refs/notes/many_notes:foobar/non-note.txt > actual &&
547         test_cmp expect_non-note1 actual &&
548         git cat-file -p refs/notes/many_notes:deadbeef > actual &&
549         test_cmp expect_non-note2 actual &&
550         git cat-file -p refs/notes/many_notes:de/adbeef > actual &&
551         test_cmp expect_non-note3 actual
552
553 '
554
555 # Change the notes for the three top commits
556 test_tick
557 cat >input <<INPUT_END
558 commit refs/notes/many_notes
559 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
560 data <<COMMIT
561 changing notes for the top three commits
562 COMMIT
563 from refs/notes/many_notes^0
564 INPUT_END
565
566 rm expect
567 i=$num_commits
568 j=0
569 while test $j -lt 3
570 do
571         cat >>input <<INPUT_END
572 N inline refs/heads/many_commits~$j
573 data <<EOF
574 changed note for commit #$i
575 EOF
576 INPUT_END
577         cat >>expect <<EXPECT_END
578     commit #$i
579     changed note for commit #$i
580 EXPECT_END
581         i=$(($i - 1))
582         j=$(($j + 1))
583 done
584
585 test_expect_success 'change a few existing notes' '
586
587         git fast-import <input &&
588         GIT_NOTES_REF=refs/notes/many_notes git log -n3 refs/heads/many_commits |
589             grep "^    " > actual &&
590         test_cmp expect actual
591
592 '
593
594 test_expect_success 'verify that changing notes respect existing fanout' '
595
596         # None of the entries in the top-level notes tree should be a full SHA1
597         git ls-tree --name-only refs/notes/many_notes |
598         while read path
599         do
600                 if test $(expr length "$path") -ge $hexsz
601                 then
602                         return 1
603                 fi
604         done
605
606 '
607
608 remaining_notes=10
609 test_tick
610 cat >input <<INPUT_END
611 commit refs/notes/many_notes
612 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
613 data <<COMMIT
614 removing all notes but $remaining_notes
615 COMMIT
616 from refs/notes/many_notes^0
617 INPUT_END
618
619 i=$(($num_commits - $remaining_notes))
620 for sha1 in $(git rev-list -n $i refs/heads/many_commits)
621 do
622         cat >>input <<INPUT_END
623 N $ZERO_OID $sha1
624 INPUT_END
625 done
626
627 i=$num_commits
628 rm expect
629 while test $i -gt 0
630 do
631         cat >>expect <<EXPECT_END
632     commit #$i
633 EXPECT_END
634         if test $i -le $remaining_notes
635         then
636                 cat >>expect <<EXPECT_END
637     note for commit #$i
638 EXPECT_END
639         fi
640         i=$(($i - 1))
641 done
642
643 test_expect_success 'remove lots of notes' '
644
645         git fast-import <input &&
646         GIT_NOTES_REF=refs/notes/many_notes git log refs/heads/many_commits |
647             grep "^    " > actual &&
648         test_cmp expect actual
649
650 '
651
652 test_expect_success 'verify that removing notes trigger fanout consolidation' '
653         # All entries in the top-level notes tree should be a full SHA1
654         git ls-tree --name-only -r refs/notes/many_notes |
655         while read path
656         do
657                 # Explicitly ignore the non-note paths
658                 test "$path" = "foobar/non-note.txt" && continue
659                 test "$path" = "deadbeef" && continue
660                 test "$path" = "de/adbeef" && continue
661
662                 if test $(expr length "$path") -ne $hexsz
663                 then
664                         return 1
665                 fi
666         done
667
668 '
669
670 test_expect_success 'verify that non-notes are untouched by a fanout change' '
671
672         git cat-file -p refs/notes/many_notes:foobar/non-note.txt > actual &&
673         test_cmp expect_non-note1 actual &&
674         git cat-file -p refs/notes/many_notes:deadbeef > actual &&
675         test_cmp expect_non-note2 actual &&
676         git cat-file -p refs/notes/many_notes:de/adbeef > actual &&
677         test_cmp expect_non-note3 actual
678
679 '
680
681
682 rm input expect
683 num_notes_refs=10
684 num_commits=16
685 some_commits=8
686 # Create commits
687 fast_import_commits "refs/heads/more_commits" $num_commits input
688 # Create one note per above commit per notes ref
689 i=0
690 while test $i -lt $num_notes_refs
691 do
692         i=$(($i + 1))
693         fast_import_notes "refs/notes/more_notes_$i" $num_commits input
694 done
695 # Trigger branch reloading in git-fast-import by repeating the note creation
696 i=0
697 while test $i -lt $num_notes_refs
698 do
699         i=$(($i + 1))
700         fast_import_notes "refs/notes/more_notes_$i" $some_commits input " (2)"
701 done
702 # Finally create the expected output from the notes in refs/notes/more_notes_1
703 i=$num_commits
704 while test $i -gt 0
705 do
706         note_data="note for commit #$i"
707         if test $i -le $some_commits
708         then
709                 note_data="$note_data (2)"
710         fi
711         cat >>expect <<EXPECT_END
712     commit #$i
713     $note_data
714 EXPECT_END
715         i=$(($i - 1))
716 done
717
718 test_expect_success "add notes to $num_commits commits in each of $num_notes_refs refs" '
719
720         git fast-import --active-branches=5 <input &&
721         GIT_NOTES_REF=refs/notes/more_notes_1 git log refs/heads/more_commits |
722             grep "^    " > actual &&
723         test_cmp expect actual
724
725 '
726
727 test_done