stash show: fix segfault with --{include,only}-untracked
[git] / t / t9300-fast-import.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Shawn Pearce
4 #
5
6 test_description='test git fast-import utility'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9
10 . ./test-lib.sh
11 . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash
12
13 verify_packs () {
14         for p in .git/objects/pack/*.pack
15         do
16                 git verify-pack "$@" "$p" || return
17         done
18 }
19
20 file2_data='file2
21 second line of EOF'
22
23 file3_data='EOF
24 in 3rd file
25  END'
26
27 file4_data=abcd
28 file4_len=4
29
30 file5_data='an inline file.
31   we should see it later.'
32
33 file6_data='#!/bin/sh
34 echo "$@"'
35
36 ###
37 ### series A
38 ###
39
40 test_expect_success 'empty stream succeeds' '
41         git config fastimport.unpackLimit 0 &&
42         git fast-import </dev/null
43 '
44
45 test_expect_success 'truncated stream complains' '
46         echo "tag foo" | test_must_fail git fast-import
47 '
48
49 test_expect_success 'A: create pack from stdin' '
50         test_tick &&
51         cat >input <<-INPUT_END &&
52         blob
53         mark :2
54         data <<EOF
55         $file2_data
56         EOF
57
58         blob
59         mark :3
60         data <<END
61         $file3_data
62         END
63
64         blob
65         mark :4
66         data $file4_len
67         $file4_data
68         commit refs/heads/main
69         mark :5
70         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
71         data <<COMMIT
72         initial
73         COMMIT
74
75         M 644 :2 file2
76         M 644 :3 file3
77         M 755 :4 file4
78
79         tag series-A
80         from :5
81         data <<EOF
82         An annotated tag without a tagger
83         EOF
84
85         tag series-A-blob
86         from :3
87         data <<EOF
88         An annotated tag that annotates a blob.
89         EOF
90
91         tag to-be-deleted
92         from :3
93         data <<EOF
94         Another annotated tag that annotates a blob.
95         EOF
96
97         reset refs/tags/to-be-deleted
98         from $ZERO_OID
99
100         tag nested
101         mark :6
102         from :4
103         data <<EOF
104         Tag of our lovely commit
105         EOF
106
107         reset refs/tags/nested
108         from $ZERO_OID
109
110         tag nested
111         mark :7
112         from :6
113         data <<EOF
114         Tag of tag of our lovely commit
115         EOF
116
117         alias
118         mark :8
119         to :5
120
121         INPUT_END
122         git fast-import --export-marks=marks.out <input &&
123         git whatchanged main
124 '
125
126 test_expect_success 'A: verify pack' '
127         verify_packs
128 '
129
130 test_expect_success 'A: verify commit' '
131         cat >expect <<-EOF &&
132         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
133         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
134
135         initial
136         EOF
137         git cat-file commit main | sed 1d >actual &&
138         test_cmp expect actual
139 '
140
141 test_expect_success 'A: verify tree' '
142         cat >expect <<-EOF &&
143         100644 blob file2
144         100644 blob file3
145         100755 blob file4
146         EOF
147         git cat-file -p main^{tree} | sed "s/ [0-9a-f]* / /" >actual &&
148         test_cmp expect actual
149 '
150
151 test_expect_success 'A: verify file2' '
152         echo "$file2_data" >expect &&
153         git cat-file blob main:file2 >actual &&
154         test_cmp expect actual
155 '
156
157 test_expect_success 'A: verify file3' '
158         echo "$file3_data" >expect &&
159         git cat-file blob main:file3 >actual &&
160         test_cmp expect actual
161 '
162
163 test_expect_success 'A: verify file4' '
164         printf "$file4_data" >expect &&
165         git cat-file blob main:file4 >actual &&
166         test_cmp expect actual
167 '
168
169 test_expect_success 'A: verify tag/series-A' '
170         cat >expect <<-EOF &&
171         object $(git rev-parse refs/heads/main)
172         type commit
173         tag series-A
174
175         An annotated tag without a tagger
176         EOF
177         git cat-file tag tags/series-A >actual &&
178         test_cmp expect actual
179 '
180
181 test_expect_success 'A: verify tag/series-A-blob' '
182         cat >expect <<-EOF &&
183         object $(git rev-parse refs/heads/main:file3)
184         type blob
185         tag series-A-blob
186
187         An annotated tag that annotates a blob.
188         EOF
189         git cat-file tag tags/series-A-blob >actual &&
190         test_cmp expect actual
191 '
192
193 test_expect_success 'A: verify tag deletion is successful' '
194         test_must_fail git rev-parse --verify refs/tags/to-be-deleted
195 '
196
197 test_expect_success 'A: verify marks output' '
198         cat >expect <<-EOF &&
199         :2 $(git rev-parse --verify main:file2)
200         :3 $(git rev-parse --verify main:file3)
201         :4 $(git rev-parse --verify main:file4)
202         :5 $(git rev-parse --verify main^0)
203         :6 $(git cat-file tag nested | grep object | cut -d" " -f 2)
204         :7 $(git rev-parse --verify nested)
205         :8 $(git rev-parse --verify main^0)
206         EOF
207         test_cmp expect marks.out
208 '
209
210 test_expect_success 'A: verify marks import' '
211         git fast-import \
212                 --import-marks=marks.out \
213                 --export-marks=marks.new \
214                 </dev/null &&
215         test_cmp expect marks.new
216 '
217
218 test_expect_success 'A: tag blob by sha1' '
219         test_tick &&
220         new_blob=$(echo testing | git hash-object --stdin) &&
221         cat >input <<-INPUT_END &&
222         tag series-A-blob-2
223         from $(git rev-parse refs/heads/main:file3)
224         data <<EOF
225         Tag blob by sha1.
226         EOF
227
228         blob
229         mark :6
230         data <<EOF
231         testing
232         EOF
233
234         commit refs/heads/new_blob
235         committer  <> 0 +0000
236         data 0
237         M 644 :6 new_blob
238         #pretend we got sha1 from fast-import
239         ls "new_blob"
240
241         tag series-A-blob-3
242         from $new_blob
243         data <<EOF
244         Tag new_blob.
245         EOF
246         INPUT_END
247
248         cat >expect <<-EOF &&
249         object $(git rev-parse refs/heads/main:file3)
250         type blob
251         tag series-A-blob-2
252
253         Tag blob by sha1.
254         object $new_blob
255         type blob
256         tag series-A-blob-3
257
258         Tag new_blob.
259         EOF
260
261         git fast-import <input &&
262         git cat-file tag tags/series-A-blob-2 >actual &&
263         git cat-file tag tags/series-A-blob-3 >>actual &&
264         test_cmp expect actual
265 '
266
267 test_expect_success 'A: verify marks import does not crash' '
268         test_tick &&
269         cat >input <<-INPUT_END &&
270         commit refs/heads/verify--import-marks
271         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
272         data <<COMMIT
273         recreate from :5
274         COMMIT
275
276         from :5
277         M 755 :2 copy-of-file2
278
279         INPUT_END
280
281         git fast-import --import-marks=marks.out <input &&
282         git whatchanged verify--import-marks
283 '
284
285 test_expect_success 'A: verify pack' '
286         verify_packs
287 '
288
289 test_expect_success 'A: verify diff' '
290         copy=$(git rev-parse --verify main:file2) &&
291         cat >expect <<-EOF &&
292         :000000 100755 $ZERO_OID $copy A        copy-of-file2
293         EOF
294         git diff-tree -M -r main verify--import-marks >actual &&
295         compare_diff_raw expect actual &&
296         test $(git rev-parse --verify main:file2) \
297             = $(git rev-parse --verify verify--import-marks:copy-of-file2)
298 '
299
300 test_expect_success 'A: export marks with large values' '
301         test_tick &&
302         mt=$(git hash-object --stdin < /dev/null) &&
303         >input.blob &&
304         >marks.exp &&
305         >tree.exp &&
306
307         cat >input.commit <<-EOF &&
308         commit refs/heads/verify--dump-marks
309         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
310         data <<COMMIT
311         test the sparse array dumping routines with exponentially growing marks
312         COMMIT
313         EOF
314
315         i=0 l=4 m=6 n=7 &&
316         while test "$i" -lt 27
317         do
318                 cat >>input.blob <<-EOF &&
319                 blob
320                 mark :$l
321                 data 0
322                 blob
323                 mark :$m
324                 data 0
325                 blob
326                 mark :$n
327                 data 0
328                 EOF
329                 echo "M 100644 :$l l$i" >>input.commit &&
330                 echo "M 100644 :$m m$i" >>input.commit &&
331                 echo "M 100644 :$n n$i" >>input.commit &&
332
333                 echo ":$l $mt" >>marks.exp &&
334                 echo ":$m $mt" >>marks.exp &&
335                 echo ":$n $mt" >>marks.exp &&
336
337                 printf "100644 blob $mt\tl$i\n" >>tree.exp &&
338                 printf "100644 blob $mt\tm$i\n" >>tree.exp &&
339                 printf "100644 blob $mt\tn$i\n" >>tree.exp &&
340
341                 l=$(($l + $l)) &&
342                 m=$(($m + $m)) &&
343                 n=$(($l + $n)) &&
344
345                 i=$((1 + $i)) || return 1
346         done &&
347
348         sort tree.exp > tree.exp_s &&
349
350         cat input.blob input.commit | git fast-import --export-marks=marks.large &&
351         git ls-tree refs/heads/verify--dump-marks >tree.out &&
352         test_cmp tree.exp_s tree.out &&
353         test_cmp marks.exp marks.large
354 '
355
356 ###
357 ### series B
358 ###
359
360 test_expect_success 'B: fail on invalid blob sha1' '
361         test_tick &&
362         cat >input <<-INPUT_END &&
363         commit refs/heads/branch
364         mark :1
365         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
366         data <<COMMIT
367         corrupt
368         COMMIT
369
370         from refs/heads/main
371         M 755 $(echo $ZERO_OID | sed -e "s/0$/1/") zero1
372
373         INPUT_END
374
375         test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" &&
376         test_must_fail git fast-import <input
377 '
378
379 test_expect_success 'B: accept branch name "TEMP_TAG"' '
380         cat >input <<-INPUT_END &&
381         commit TEMP_TAG
382         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
383         data <<COMMIT
384         tag base
385         COMMIT
386
387         from refs/heads/main
388
389         INPUT_END
390
391         test_when_finished "rm -f .git/TEMP_TAG
392                 git gc
393                 git prune" &&
394         git fast-import <input &&
395         test -f .git/TEMP_TAG &&
396         test $(git rev-parse main) = $(git rev-parse TEMP_TAG^)
397 '
398
399 test_expect_success 'B: accept empty committer' '
400         cat >input <<-INPUT_END &&
401         commit refs/heads/empty-committer-1
402         committer  <> $GIT_COMMITTER_DATE
403         data <<COMMIT
404         empty commit
405         COMMIT
406         INPUT_END
407
408         test_when_finished "git update-ref -d refs/heads/empty-committer-1
409                 git gc
410                 git prune" &&
411         git fast-import <input &&
412         out=$(git fsck) &&
413         echo "$out" &&
414         test -z "$out"
415 '
416
417 test_expect_success 'B: reject invalid timezone' '
418         cat >input <<-INPUT_END &&
419         commit refs/heads/invalid-timezone
420         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
421         data <<COMMIT
422         empty commit
423         COMMIT
424         INPUT_END
425
426         test_when_finished "git update-ref -d refs/heads/invalid-timezone" &&
427         test_must_fail git fast-import <input
428 '
429
430 test_expect_success 'B: accept invalid timezone with raw-permissive' '
431         cat >input <<-INPUT_END &&
432         commit refs/heads/invalid-timezone
433         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1234567890 +051800
434         data <<COMMIT
435         empty commit
436         COMMIT
437         INPUT_END
438
439         git init invalid-timezone &&
440         git -C invalid-timezone fast-import --date-format=raw-permissive <input &&
441         git -C invalid-timezone cat-file -p invalid-timezone >out &&
442         grep "1234567890 [+]051800" out
443 '
444
445 test_expect_success 'B: accept and fixup committer with no name' '
446         cat >input <<-INPUT_END &&
447         commit refs/heads/empty-committer-2
448         committer <a@b.com> $GIT_COMMITTER_DATE
449         data <<COMMIT
450         empty commit
451         COMMIT
452         INPUT_END
453
454         test_when_finished "git update-ref -d refs/heads/empty-committer-2
455                 git gc
456                 git prune" &&
457         git fast-import <input &&
458         out=$(git fsck) &&
459         echo "$out" &&
460         test -z "$out"
461 '
462
463 test_expect_success 'B: fail on invalid committer (1)' '
464         cat >input <<-INPUT_END &&
465         commit refs/heads/invalid-committer
466         committer Name email> $GIT_COMMITTER_DATE
467         data <<COMMIT
468         empty commit
469         COMMIT
470         INPUT_END
471
472         test_when_finished "git update-ref -d refs/heads/invalid-committer" &&
473         test_must_fail git fast-import <input
474 '
475
476 test_expect_success 'B: fail on invalid committer (2)' '
477         cat >input <<-INPUT_END &&
478         commit refs/heads/invalid-committer
479         committer Name <e<mail> $GIT_COMMITTER_DATE
480         data <<COMMIT
481         empty commit
482         COMMIT
483         INPUT_END
484
485         test_when_finished "git update-ref -d refs/heads/invalid-committer" &&
486         test_must_fail git fast-import <input
487 '
488
489 test_expect_success 'B: fail on invalid committer (3)' '
490         cat >input <<-INPUT_END &&
491         commit refs/heads/invalid-committer
492         committer Name <email>> $GIT_COMMITTER_DATE
493         data <<COMMIT
494         empty commit
495         COMMIT
496         INPUT_END
497
498         test_when_finished "git update-ref -d refs/heads/invalid-committer" &&
499         test_must_fail git fast-import <input
500 '
501
502 test_expect_success 'B: fail on invalid committer (4)' '
503         cat >input <<-INPUT_END &&
504         commit refs/heads/invalid-committer
505         committer Name <email $GIT_COMMITTER_DATE
506         data <<COMMIT
507         empty commit
508         COMMIT
509         INPUT_END
510
511         test_when_finished "git update-ref -d refs/heads/invalid-committer" &&
512         test_must_fail git fast-import <input
513 '
514
515 test_expect_success 'B: fail on invalid committer (5)' '
516         cat >input <<-INPUT_END &&
517         commit refs/heads/invalid-committer
518         committer Name<email> $GIT_COMMITTER_DATE
519         data <<COMMIT
520         empty commit
521         COMMIT
522         INPUT_END
523
524         test_when_finished "git update-ref -d refs/heads/invalid-committer" &&
525         test_must_fail git fast-import <input
526 '
527
528 ###
529 ### series C
530 ###
531
532 test_expect_success 'C: incremental import create pack from stdin' '
533         newf=$(echo hi newf | git hash-object -w --stdin) &&
534         oldf=$(git rev-parse --verify main:file2) &&
535         thrf=$(git rev-parse --verify main:file3) &&
536         test_tick &&
537         cat >input <<-INPUT_END &&
538         commit refs/heads/branch
539         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
540         data <<COMMIT
541         second
542         COMMIT
543
544         from refs/heads/main
545         M 644 $oldf file2/oldf
546         M 755 $newf file2/newf
547         D file3
548
549         INPUT_END
550
551         git fast-import <input &&
552         git whatchanged branch
553 '
554
555 test_expect_success 'C: verify pack' '
556         verify_packs
557 '
558
559 test_expect_success 'C: validate reuse existing blob' '
560         test $newf = $(git rev-parse --verify branch:file2/newf) &&
561         test $oldf = $(git rev-parse --verify branch:file2/oldf)
562 '
563
564 test_expect_success 'C: verify commit' '
565         cat >expect <<-EOF &&
566         parent $(git rev-parse --verify main^0)
567         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
568         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
569
570         second
571         EOF
572
573         git cat-file commit branch | sed 1d >actual &&
574         test_cmp expect actual
575 '
576
577 test_expect_success 'C: validate rename result' '
578         zero=$ZERO_OID &&
579         cat >expect <<-EOF &&
580         :000000 100755 $zero $newf A    file2/newf
581         :100644 100644 $oldf $oldf R100 file2   file2/oldf
582         :100644 000000 $thrf $zero D    file3
583         EOF
584         git diff-tree -M -r main branch >actual &&
585         compare_diff_raw expect actual
586 '
587
588 ###
589 ### series D
590 ###
591
592 test_expect_success 'D: inline data in commit' '
593         test_tick &&
594         cat >input <<-INPUT_END &&
595         commit refs/heads/branch
596         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
597         data <<COMMIT
598         third
599         COMMIT
600
601         from refs/heads/branch^0
602         M 644 inline newdir/interesting
603         data <<EOF
604         $file5_data
605         EOF
606
607         M 755 inline newdir/exec.sh
608         data <<EOF
609         $file6_data
610         EOF
611
612         INPUT_END
613
614         git fast-import <input &&
615         git whatchanged branch
616 '
617
618 test_expect_success 'D: verify pack' '
619         verify_packs
620 '
621
622 test_expect_success 'D: validate new files added' '
623         f5id=$(echo "$file5_data" | git hash-object --stdin) &&
624         f6id=$(echo "$file6_data" | git hash-object --stdin) &&
625         cat >expect <<-EOF &&
626         :000000 100755 $ZERO_OID $f6id A        newdir/exec.sh
627         :000000 100644 $ZERO_OID $f5id A        newdir/interesting
628         EOF
629         git diff-tree -M -r branch^ branch >actual &&
630         compare_diff_raw expect actual
631 '
632
633 test_expect_success 'D: verify file5' '
634         echo "$file5_data" >expect &&
635         git cat-file blob branch:newdir/interesting >actual &&
636         test_cmp expect actual
637 '
638
639 test_expect_success 'D: verify file6' '
640         echo "$file6_data" >expect &&
641         git cat-file blob branch:newdir/exec.sh >actual &&
642         test_cmp expect actual
643 '
644
645 ###
646 ### series E
647 ###
648
649 test_expect_success 'E: rfc2822 date, --date-format=raw' '
650         cat >input <<-INPUT_END &&
651         commit refs/heads/branch
652         author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> Tue Feb 6 11:22:18 2007 -0500
653         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> Tue Feb 6 12:35:02 2007 -0500
654         data <<COMMIT
655         RFC 2822 type date
656         COMMIT
657
658         from refs/heads/branch^0
659
660         INPUT_END
661
662         test_must_fail git fast-import --date-format=raw <input
663 '
664 test_expect_success 'E: rfc2822 date, --date-format=rfc2822' '
665         git fast-import --date-format=rfc2822 <input
666 '
667
668 test_expect_success 'E: verify pack' '
669         verify_packs
670 '
671
672 test_expect_success 'E: verify commit' '
673         cat >expect <<-EOF &&
674         author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500
675         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1170783302 -0500
676
677         RFC 2822 type date
678         EOF
679         git cat-file commit branch | sed 1,2d >actual &&
680         test_cmp expect actual
681 '
682
683 ###
684 ### series F
685 ###
686
687 test_expect_success 'F: non-fast-forward update skips' '
688         old_branch=$(git rev-parse --verify branch^0) &&
689         test_tick &&
690         cat >input <<-INPUT_END &&
691         commit refs/heads/branch
692         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
693         data <<COMMIT
694         losing things already?
695         COMMIT
696
697         from refs/heads/branch~1
698
699         reset refs/heads/other
700         from refs/heads/branch
701
702         INPUT_END
703
704         test_must_fail git fast-import <input &&
705         # branch must remain unaffected
706         test $old_branch = $(git rev-parse --verify branch^0)
707 '
708
709 test_expect_success 'F: verify pack' '
710         verify_packs
711 '
712
713 test_expect_success 'F: verify other commit' '
714         cat >expect <<-EOF &&
715         tree $(git rev-parse branch~1^{tree})
716         parent $(git rev-parse branch~1)
717         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
718         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
719
720         losing things already?
721         EOF
722         git cat-file commit other >actual &&
723         test_cmp expect actual
724 '
725
726 ###
727 ### series G
728 ###
729
730 test_expect_success 'G: non-fast-forward update forced' '
731         old_branch=$(git rev-parse --verify branch^0) &&
732         test_tick &&
733         cat >input <<-INPUT_END &&
734         commit refs/heads/branch
735         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
736         data <<COMMIT
737         losing things already?
738         COMMIT
739
740         from refs/heads/branch~1
741
742         INPUT_END
743         git fast-import --force <input
744 '
745
746 test_expect_success 'G: verify pack' '
747         verify_packs
748 '
749
750 test_expect_success 'G: branch changed, but logged' '
751         test $old_branch != $(git rev-parse --verify branch^0) &&
752         test $old_branch = $(git rev-parse --verify branch@{1})
753 '
754
755 ###
756 ### series H
757 ###
758
759 test_expect_success 'H: deletall, add 1' '
760         test_tick &&
761         cat >input <<-INPUT_END &&
762         commit refs/heads/H
763         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
764         data <<COMMIT
765         third
766         COMMIT
767
768         from refs/heads/branch^0
769         M 644 inline i-will-die
770         data <<EOF
771         this file will never exist.
772         EOF
773
774         deleteall
775         M 644 inline h/e/l/lo
776         data <<EOF
777         $file5_data
778         EOF
779
780         INPUT_END
781         git fast-import <input &&
782         git whatchanged H
783 '
784
785 test_expect_success 'H: verify pack' '
786         verify_packs
787 '
788
789 test_expect_success 'H: validate old files removed, new files added' '
790         f4id=$(git rev-parse HEAD:file4) &&
791         cat >expect <<-EOF &&
792         :100755 000000 $newf $zero D    file2/newf
793         :100644 000000 $oldf $zero D    file2/oldf
794         :100755 000000 $f4id $zero D    file4
795         :100644 100644 $f5id $f5id R100 newdir/interesting      h/e/l/lo
796         :100755 000000 $f6id $zero D    newdir/exec.sh
797         EOF
798         git diff-tree -M -r H^ H >actual &&
799         compare_diff_raw expect actual
800 '
801
802 test_expect_success 'H: verify file' '
803         echo "$file5_data" >expect &&
804         git cat-file blob H:h/e/l/lo >actual &&
805         test_cmp expect actual
806 '
807
808 ###
809 ### series I
810 ###
811
812 test_expect_success 'I: export-pack-edges' '
813         cat >input <<-INPUT_END &&
814         commit refs/heads/export-boundary
815         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
816         data <<COMMIT
817         we have a border.  its only 40 characters wide.
818         COMMIT
819
820         from refs/heads/branch
821
822         INPUT_END
823         git fast-import --export-pack-edges=edges.list <input
824 '
825
826 test_expect_success 'I: verify edge list' '
827         cat >expect <<-EOF &&
828         .git/objects/pack/pack-.pack: $(git rev-parse --verify export-boundary)
829         EOF
830         sed -e s/pack-.*pack/pack-.pack/ edges.list >actual &&
831         test_cmp expect actual
832 '
833
834 ###
835 ### series J
836 ###
837
838 test_expect_success 'J: reset existing branch creates empty commit' '
839         cat >input <<-INPUT_END &&
840         commit refs/heads/J
841         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
842         data <<COMMIT
843         create J
844         COMMIT
845
846         from refs/heads/branch
847
848         reset refs/heads/J
849
850         commit refs/heads/J
851         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
852         data <<COMMIT
853         initialize J
854         COMMIT
855
856         INPUT_END
857         git fast-import <input
858 '
859 test_expect_success 'J: branch has 1 commit, empty tree' '
860         test 1 = $(git rev-list J | wc -l) &&
861         test 0 = $(git ls-tree J | wc -l)
862 '
863
864 test_expect_success 'J: tag must fail on empty branch' '
865         cat >input <<-INPUT_END &&
866         reset refs/heads/J2
867
868         tag wrong_tag
869         from refs/heads/J2
870         data <<EOF
871         Tag branch that was reset.
872         EOF
873         INPUT_END
874         test_must_fail git fast-import <input
875 '
876
877 ###
878 ### series K
879 ###
880
881 test_expect_success 'K: reinit branch with from' '
882         cat >input <<-INPUT_END &&
883         commit refs/heads/K
884         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
885         data <<COMMIT
886         create K
887         COMMIT
888
889         from refs/heads/branch
890
891         commit refs/heads/K
892         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
893         data <<COMMIT
894         redo K
895         COMMIT
896
897         from refs/heads/branch^1
898
899         INPUT_END
900         git fast-import <input
901 '
902 test_expect_success 'K: verify K^1 = branch^1' '
903         test $(git rev-parse --verify branch^1) \
904                 = $(git rev-parse --verify K^1)
905 '
906
907 ###
908 ### series L
909 ###
910
911 test_expect_success 'L: verify internal tree sorting' '
912         cat >input <<-INPUT_END &&
913         blob
914         mark :1
915         data <<EOF
916         some data
917         EOF
918
919         blob
920         mark :2
921         data <<EOF
922         other data
923         EOF
924
925         commit refs/heads/L
926         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
927         data <<COMMIT
928         create L
929         COMMIT
930
931         M 644 :1 b.
932         M 644 :1 b/other
933         M 644 :1 ba
934
935         commit refs/heads/L
936         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
937         data <<COMMIT
938         update L
939         COMMIT
940
941         M 644 :2 b.
942         M 644 :2 b/other
943         M 644 :2 ba
944         INPUT_END
945
946         cat >expect <<-EXPECT_END &&
947         :100644 100644 M        b.
948         :040000 040000 M        b
949         :100644 100644 M        ba
950         EXPECT_END
951
952         git fast-import <input &&
953         GIT_PRINT_SHA1_ELLIPSIS="yes" git diff-tree --abbrev --raw L^ L >output &&
954         cut -d" " -f1,2,5 output >actual &&
955         test_cmp expect actual
956 '
957
958 test_expect_success 'L: nested tree copy does not corrupt deltas' '
959         cat >input <<-INPUT_END &&
960         blob
961         mark :1
962         data <<EOF
963         the data
964         EOF
965
966         commit refs/heads/L2
967         committer C O Mitter <committer@example.com> 1112912473 -0700
968         data <<COMMIT
969         init L2
970         COMMIT
971         M 644 :1 a/b/c
972         M 644 :1 a/b/d
973         M 644 :1 a/e/f
974
975         commit refs/heads/L2
976         committer C O Mitter <committer@example.com> 1112912473 -0700
977         data <<COMMIT
978         update L2
979         COMMIT
980         C a g
981         C a/e g/b
982         M 644 :1 g/b/h
983         INPUT_END
984
985         cat >expect <<-\EOF &&
986         g/b/f
987         g/b/h
988         EOF
989
990         test_when_finished "git update-ref -d refs/heads/L2" &&
991         git fast-import <input &&
992         git ls-tree L2 g/b/ >tmp &&
993         cat tmp | cut -f 2 >actual &&
994         test_cmp expect actual &&
995         git fsck $(git rev-parse L2)
996 '
997
998 ###
999 ### series M
1000 ###
1001
1002 test_expect_success 'M: rename file in same subdirectory' '
1003         test_tick &&
1004         cat >input <<-INPUT_END &&
1005         commit refs/heads/M1
1006         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1007         data <<COMMIT
1008         file rename
1009         COMMIT
1010
1011         from refs/heads/branch^0
1012         R file2/newf file2/n.e.w.f
1013
1014         INPUT_END
1015
1016         cat >expect <<-EOF &&
1017         :100755 100755 $newf $newf R100 file2/newf      file2/n.e.w.f
1018         EOF
1019         git fast-import <input &&
1020         git diff-tree -M -r M1^ M1 >actual &&
1021         compare_diff_raw expect actual
1022 '
1023
1024 test_expect_success 'M: rename file to new subdirectory' '
1025         cat >input <<-INPUT_END &&
1026         commit refs/heads/M2
1027         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1028         data <<COMMIT
1029         file rename
1030         COMMIT
1031
1032         from refs/heads/branch^0
1033         R file2/newf i/am/new/to/you
1034
1035         INPUT_END
1036
1037         cat >expect <<-EOF &&
1038         :100755 100755 $newf $newf R100 file2/newf      i/am/new/to/you
1039         EOF
1040         git fast-import <input &&
1041         git diff-tree -M -r M2^ M2 >actual &&
1042         compare_diff_raw expect actual
1043 '
1044
1045 test_expect_success 'M: rename subdirectory to new subdirectory' '
1046         cat >input <<-INPUT_END &&
1047         commit refs/heads/M3
1048         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1049         data <<COMMIT
1050         file rename
1051         COMMIT
1052
1053         from refs/heads/M2^0
1054         R i other/sub
1055
1056         INPUT_END
1057
1058         cat >expect <<-EOF &&
1059         :100755 100755 $newf $newf R100 i/am/new/to/you other/sub/am/new/to/you
1060         EOF
1061         git fast-import <input &&
1062         git diff-tree -M -r M3^ M3 >actual &&
1063         compare_diff_raw expect actual
1064 '
1065
1066 test_expect_success 'M: rename root to subdirectory' '
1067         cat >input <<-INPUT_END &&
1068         commit refs/heads/M4
1069         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1070         data <<COMMIT
1071         rename root
1072         COMMIT
1073
1074         from refs/heads/M2^0
1075         R "" sub
1076
1077         INPUT_END
1078
1079         cat >expect <<-EOF &&
1080         :100644 100644 $oldf $oldf R100 file2/oldf      sub/file2/oldf
1081         :100755 100755 $f4id $f4id R100 file4   sub/file4
1082         :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you
1083         :100755 100755 $f6id $f6id R100 newdir/exec.sh  sub/newdir/exec.sh
1084         :100644 100644 $f5id $f5id R100 newdir/interesting      sub/newdir/interesting
1085         EOF
1086         git fast-import <input &&
1087         git diff-tree -M -r M4^ M4 >actual &&
1088         compare_diff_raw expect actual
1089 '
1090
1091 ###
1092 ### series N
1093 ###
1094
1095 test_expect_success 'N: copy file in same subdirectory' '
1096         test_tick &&
1097         cat >input <<-INPUT_END &&
1098         commit refs/heads/N1
1099         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1100         data <<COMMIT
1101         file copy
1102         COMMIT
1103
1104         from refs/heads/branch^0
1105         C file2/newf file2/n.e.w.f
1106
1107         INPUT_END
1108
1109         cat >expect <<-EOF &&
1110         :100755 100755 $newf $newf C100 file2/newf      file2/n.e.w.f
1111         EOF
1112         git fast-import <input &&
1113         git diff-tree -C --find-copies-harder -r N1^ N1 >actual &&
1114         compare_diff_raw expect actual
1115 '
1116
1117 test_expect_success 'N: copy then modify subdirectory' '
1118         cat >input <<-INPUT_END &&
1119         commit refs/heads/N2
1120         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1121         data <<COMMIT
1122         clean directory copy
1123         COMMIT
1124
1125         from refs/heads/branch^0
1126         C file2 file3
1127
1128         commit refs/heads/N2
1129         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1130         data <<COMMIT
1131         modify directory copy
1132         COMMIT
1133
1134         M 644 inline file3/file5
1135         data <<EOF
1136         $file5_data
1137         EOF
1138
1139         INPUT_END
1140
1141         cat >expect <<-EOF &&
1142         :100644 100644 $f5id $f5id C100 newdir/interesting      file3/file5
1143         :100755 100755 $newf $newf C100 file2/newf      file3/newf
1144         :100644 100644 $oldf $oldf C100 file2/oldf      file3/oldf
1145         EOF
1146         git fast-import <input &&
1147         git diff-tree -C --find-copies-harder -r N2^^ N2 >actual &&
1148         compare_diff_raw expect actual
1149 '
1150
1151 test_expect_success 'N: copy dirty subdirectory' '
1152         cat >input <<-INPUT_END &&
1153         commit refs/heads/N3
1154         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1155         data <<COMMIT
1156         dirty directory copy
1157         COMMIT
1158
1159         from refs/heads/branch^0
1160         M 644 inline file2/file5
1161         data <<EOF
1162         $file5_data
1163         EOF
1164
1165         C file2 file3
1166         D file2/file5
1167
1168         INPUT_END
1169
1170         git fast-import <input &&
1171         test $(git rev-parse N2^{tree}) = $(git rev-parse N3^{tree})
1172 '
1173
1174 test_expect_success 'N: copy directory by id' '
1175         cat >expect <<-EOF &&
1176         :100755 100755 $newf $newf C100 file2/newf      file3/newf
1177         :100644 100644 $oldf $oldf C100 file2/oldf      file3/oldf
1178         EOF
1179         subdir=$(git rev-parse refs/heads/branch^0:file2) &&
1180         cat >input <<-INPUT_END &&
1181         commit refs/heads/N4
1182         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1183         data <<COMMIT
1184         copy by tree hash
1185         COMMIT
1186
1187         from refs/heads/branch^0
1188         M 040000 $subdir file3
1189         INPUT_END
1190         git fast-import <input &&
1191         git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
1192         compare_diff_raw expect actual
1193 '
1194
1195 test_expect_success PIPE 'N: read and copy directory' '
1196         cat >expect <<-EOF &&
1197         :100755 100755 $newf $newf C100 file2/newf      file3/newf
1198         :100644 100644 $oldf $oldf C100 file2/oldf      file3/oldf
1199         EOF
1200         git update-ref -d refs/heads/N4 &&
1201         rm -f backflow &&
1202         mkfifo backflow &&
1203         (
1204                 exec <backflow &&
1205                 cat <<-EOF &&
1206                 commit refs/heads/N4
1207                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1208                 data <<COMMIT
1209                 copy by tree hash, part 2
1210                 COMMIT
1211
1212                 from refs/heads/branch^0
1213                 ls "file2"
1214                 EOF
1215                 read mode type tree filename &&
1216                 echo "M 040000 $tree file3"
1217         ) |
1218         git fast-import --cat-blob-fd=3 3>backflow &&
1219         git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
1220         compare_diff_raw expect actual
1221 '
1222
1223 test_expect_success PIPE 'N: empty directory reads as missing' '
1224         cat <<-\EOF >expect &&
1225         OBJNAME
1226         :000000 100644 OBJNAME OBJNAME A        unrelated
1227         EOF
1228         echo "missing src" >expect.response &&
1229         git update-ref -d refs/heads/read-empty &&
1230         rm -f backflow &&
1231         mkfifo backflow &&
1232         (
1233                 exec <backflow &&
1234                 cat <<-EOF &&
1235                 commit refs/heads/read-empty
1236                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1237                 data <<COMMIT
1238                 read "empty" (missing) directory
1239                 COMMIT
1240
1241                 M 100644 inline src/greeting
1242                 data <<BLOB
1243                 hello
1244                 BLOB
1245                 C src/greeting dst1/non-greeting
1246                 C src/greeting unrelated
1247                 # leave behind "empty" src directory
1248                 D src/greeting
1249                 ls "src"
1250                 EOF
1251                 read -r line &&
1252                 printf "%s\n" "$line" >response &&
1253                 cat <<-\EOF
1254                 D dst1
1255                 D dst2
1256                 EOF
1257         ) |
1258         git fast-import --cat-blob-fd=3 3>backflow &&
1259         test_cmp expect.response response &&
1260         git rev-list read-empty |
1261         git diff-tree -r --root --stdin |
1262         sed "s/$OID_REGEX/OBJNAME/g" >actual &&
1263         test_cmp expect actual
1264 '
1265
1266 test_expect_success 'N: copy root directory by tree hash' '
1267         cat >expect <<-EOF &&
1268         :100755 000000 $newf $zero D    file3/newf
1269         :100644 000000 $oldf $zero D    file3/oldf
1270         EOF
1271         root=$(git rev-parse refs/heads/branch^0^{tree}) &&
1272         cat >input <<-INPUT_END &&
1273         commit refs/heads/N6
1274         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1275         data <<COMMIT
1276         copy root directory by tree hash
1277         COMMIT
1278
1279         from refs/heads/branch^0
1280         M 040000 $root ""
1281         INPUT_END
1282         git fast-import <input &&
1283         git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
1284         compare_diff_raw expect actual
1285 '
1286
1287 test_expect_success 'N: copy root by path' '
1288         cat >expect <<-EOF &&
1289         :100755 100755 $newf $newf C100 file2/newf      oldroot/file2/newf
1290         :100644 100644 $oldf $oldf C100 file2/oldf      oldroot/file2/oldf
1291         :100755 100755 $f4id $f4id C100 file4   oldroot/file4
1292         :100755 100755 $f6id $f6id C100 newdir/exec.sh  oldroot/newdir/exec.sh
1293         :100644 100644 $f5id $f5id C100 newdir/interesting      oldroot/newdir/interesting
1294         EOF
1295         cat >input <<-INPUT_END &&
1296         commit refs/heads/N-copy-root-path
1297         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1298         data <<COMMIT
1299         copy root directory by (empty) path
1300         COMMIT
1301
1302         from refs/heads/branch^0
1303         C "" oldroot
1304         INPUT_END
1305         git fast-import <input &&
1306         git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
1307         compare_diff_raw expect actual
1308 '
1309
1310 test_expect_success 'N: delete directory by copying' '
1311         cat >expect <<-\EOF &&
1312         OBJID
1313         :100644 000000 OBJID OBJID D    foo/bar/qux
1314         OBJID
1315         :000000 100644 OBJID OBJID A    foo/bar/baz
1316         :000000 100644 OBJID OBJID A    foo/bar/qux
1317         EOF
1318         empty_tree=$(git mktree </dev/null) &&
1319         cat >input <<-INPUT_END &&
1320         commit refs/heads/N-delete
1321         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1322         data <<COMMIT
1323         collect data to be deleted
1324         COMMIT
1325
1326         deleteall
1327         M 100644 inline foo/bar/baz
1328         data <<DATA_END
1329         hello
1330         DATA_END
1331         C "foo/bar/baz" "foo/bar/qux"
1332         C "foo/bar/baz" "foo/bar/quux/1"
1333         C "foo/bar/baz" "foo/bar/quuux"
1334         M 040000 $empty_tree foo/bar/quux
1335         M 040000 $empty_tree foo/bar/quuux
1336
1337         commit refs/heads/N-delete
1338         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1339         data <<COMMIT
1340         delete subdirectory
1341         COMMIT
1342
1343         M 040000 $empty_tree foo/bar/qux
1344         INPUT_END
1345         git fast-import <input &&
1346         git rev-list N-delete |
1347                 git diff-tree -r --stdin --root --always |
1348                 sed -e "s/$OID_REGEX/OBJID/g" >actual &&
1349         test_cmp expect actual
1350 '
1351
1352 test_expect_success 'N: modify copied tree' '
1353         cat >expect <<-EOF &&
1354         :100644 100644 $f5id $f5id C100 newdir/interesting      file3/file5
1355         :100755 100755 $newf $newf C100 file2/newf      file3/newf
1356         :100644 100644 $oldf $oldf C100 file2/oldf      file3/oldf
1357         EOF
1358         subdir=$(git rev-parse refs/heads/branch^0:file2) &&
1359         cat >input <<-INPUT_END &&
1360         commit refs/heads/N5
1361         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1362         data <<COMMIT
1363         copy by tree hash
1364         COMMIT
1365
1366         from refs/heads/branch^0
1367         M 040000 $subdir file3
1368
1369         commit refs/heads/N5
1370         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1371         data <<COMMIT
1372         modify directory copy
1373         COMMIT
1374
1375         M 644 inline file3/file5
1376         data <<EOF
1377         $file5_data
1378         EOF
1379         INPUT_END
1380         git fast-import <input &&
1381         git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
1382         compare_diff_raw expect actual
1383 '
1384
1385 test_expect_success 'N: reject foo/ syntax' '
1386         subdir=$(git rev-parse refs/heads/branch^0:file2) &&
1387         test_must_fail git fast-import <<-INPUT_END
1388         commit refs/heads/N5B
1389         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1390         data <<COMMIT
1391         copy with invalid syntax
1392         COMMIT
1393
1394         from refs/heads/branch^0
1395         M 040000 $subdir file3/
1396         INPUT_END
1397 '
1398
1399 test_expect_success 'N: reject foo/ syntax in copy source' '
1400         test_must_fail git fast-import <<-INPUT_END
1401         commit refs/heads/N5C
1402         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1403         data <<COMMIT
1404         copy with invalid syntax
1405         COMMIT
1406
1407         from refs/heads/branch^0
1408         C file2/ file3
1409         INPUT_END
1410 '
1411
1412 test_expect_success 'N: reject foo/ syntax in rename source' '
1413         test_must_fail git fast-import <<-INPUT_END
1414         commit refs/heads/N5D
1415         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1416         data <<COMMIT
1417         rename with invalid syntax
1418         COMMIT
1419
1420         from refs/heads/branch^0
1421         R file2/ file3
1422         INPUT_END
1423 '
1424
1425 test_expect_success 'N: reject foo/ syntax in ls argument' '
1426         test_must_fail git fast-import <<-INPUT_END
1427         commit refs/heads/N5E
1428         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1429         data <<COMMIT
1430         copy with invalid syntax
1431         COMMIT
1432
1433         from refs/heads/branch^0
1434         ls "file2/"
1435         INPUT_END
1436 '
1437
1438 test_expect_success 'N: copy to root by id and modify' '
1439         echo "hello, world" >expect.foo &&
1440         echo hello >expect.bar &&
1441         git fast-import <<-SETUP_END &&
1442         commit refs/heads/N7
1443         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1444         data <<COMMIT
1445         hello, tree
1446         COMMIT
1447
1448         deleteall
1449         M 644 inline foo/bar
1450         data <<EOF
1451         hello
1452         EOF
1453         SETUP_END
1454
1455         tree=$(git rev-parse --verify N7:) &&
1456         git fast-import <<-INPUT_END &&
1457         commit refs/heads/N8
1458         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1459         data <<COMMIT
1460         copy to root by id and modify
1461         COMMIT
1462
1463         M 040000 $tree ""
1464         M 644 inline foo/foo
1465         data <<EOF
1466         hello, world
1467         EOF
1468         INPUT_END
1469         git show N8:foo/foo >actual.foo &&
1470         git show N8:foo/bar >actual.bar &&
1471         test_cmp expect.foo actual.foo &&
1472         test_cmp expect.bar actual.bar
1473 '
1474
1475 test_expect_success 'N: extract subtree' '
1476         branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
1477         cat >input <<-INPUT_END &&
1478         commit refs/heads/N9
1479         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1480         data <<COMMIT
1481         extract subtree branch:newdir
1482         COMMIT
1483
1484         M 040000 $branch ""
1485         C "newdir" ""
1486         INPUT_END
1487         git fast-import <input &&
1488         git diff --exit-code branch:newdir N9
1489 '
1490
1491 test_expect_success 'N: modify subtree, extract it, and modify again' '
1492         echo hello >expect.baz &&
1493         echo hello, world >expect.qux &&
1494         git fast-import <<-SETUP_END &&
1495         commit refs/heads/N10
1496         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1497         data <<COMMIT
1498         hello, tree
1499         COMMIT
1500
1501         deleteall
1502         M 644 inline foo/bar/baz
1503         data <<EOF
1504         hello
1505         EOF
1506         SETUP_END
1507
1508         tree=$(git rev-parse --verify N10:) &&
1509         git fast-import <<-INPUT_END &&
1510         commit refs/heads/N11
1511         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1512         data <<COMMIT
1513         copy to root by id and modify
1514         COMMIT
1515
1516         M 040000 $tree ""
1517         M 100644 inline foo/bar/qux
1518         data <<EOF
1519         hello, world
1520         EOF
1521         R "foo" ""
1522         C "bar/qux" "bar/quux"
1523         INPUT_END
1524         git show N11:bar/baz >actual.baz &&
1525         git show N11:bar/qux >actual.qux &&
1526         git show N11:bar/quux >actual.quux &&
1527         test_cmp expect.baz actual.baz &&
1528         test_cmp expect.qux actual.qux &&
1529         test_cmp expect.qux actual.quux'
1530
1531 ###
1532 ### series O
1533 ###
1534
1535 test_expect_success 'O: comments are all skipped' '
1536         cat >input <<-INPUT_END &&
1537         #we will
1538         commit refs/heads/O1
1539         # -- ignore all of this text
1540         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1541         # $GIT_COMMITTER_NAME has inserted here for his benefit.
1542         data <<COMMIT
1543         dirty directory copy
1544         COMMIT
1545
1546         # do not forget the import blank line!
1547         #
1548         # yes, we started from our usual base of branch^0.
1549         # i like branch^0.
1550         from refs/heads/branch^0
1551         # and we need to reuse file2/file5 from N3 above.
1552         M 644 inline file2/file5
1553         # otherwise the tree will be different
1554         data <<EOF
1555         $file5_data
1556         EOF
1557
1558         # do not forget to copy file2 to file3
1559         C file2 file3
1560         #
1561         # or to delete file5 from file2.
1562         D file2/file5
1563         # are we done yet?
1564
1565         INPUT_END
1566
1567         git fast-import <input &&
1568         test $(git rev-parse N3) = $(git rev-parse O1)
1569 '
1570
1571 test_expect_success 'O: blank lines not necessary after data commands' '
1572         cat >input <<-INPUT_END &&
1573         commit refs/heads/O2
1574         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1575         data <<COMMIT
1576         dirty directory copy
1577         COMMIT
1578         from refs/heads/branch^0
1579         M 644 inline file2/file5
1580         data <<EOF
1581         $file5_data
1582         EOF
1583         C file2 file3
1584         D file2/file5
1585
1586         INPUT_END
1587
1588         git fast-import <input &&
1589         test $(git rev-parse N3) = $(git rev-parse O2)
1590 '
1591
1592 test_expect_success 'O: repack before next test' '
1593         git repack -a -d
1594 '
1595
1596 test_expect_success 'O: blank lines not necessary after other commands' '
1597         cat >input <<-INPUT_END &&
1598         commit refs/heads/O3
1599         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1600         data <<COMMIT
1601         zstring
1602         COMMIT
1603         commit refs/heads/O3
1604         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1605         data <<COMMIT
1606         zof
1607         COMMIT
1608         checkpoint
1609         commit refs/heads/O3
1610         mark :5
1611         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1612         data <<COMMIT
1613         zempty
1614         COMMIT
1615         checkpoint
1616         commit refs/heads/O3
1617         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1618         data <<COMMIT
1619         zcommits
1620         COMMIT
1621         reset refs/tags/O3-2nd
1622         from :5
1623         reset refs/tags/O3-3rd
1624         from :5
1625         INPUT_END
1626
1627         cat >expect <<-INPUT_END &&
1628         string
1629         of
1630         empty
1631         commits
1632         INPUT_END
1633
1634         git fast-import <input &&
1635         test 8 = $(find .git/objects/pack -type f | grep -v multi-pack-index | wc -l) &&
1636         test $(git rev-parse refs/tags/O3-2nd) = $(git rev-parse O3^) &&
1637         git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual &&
1638         test_cmp expect actual
1639 '
1640
1641 test_expect_success 'O: progress outputs as requested by input' '
1642         cat >input <<-INPUT_END &&
1643         commit refs/heads/O4
1644         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1645         data <<COMMIT
1646         zstring
1647         COMMIT
1648         commit refs/heads/O4
1649         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1650         data <<COMMIT
1651         zof
1652         COMMIT
1653         progress Two commits down, 2 to go!
1654         commit refs/heads/O4
1655         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1656         data <<COMMIT
1657         zempty
1658         COMMIT
1659         progress Three commits down, 1 to go!
1660         commit refs/heads/O4
1661         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1662         data <<COMMIT
1663         zcommits
1664         COMMIT
1665         progress done!
1666         INPUT_END
1667         git fast-import <input >actual &&
1668         grep "progress " <input >expect &&
1669         test_cmp expect actual
1670 '
1671
1672 ###
1673 ### series P (gitlinks)
1674 ###
1675
1676 test_expect_success 'P: superproject & submodule mix' '
1677         cat >input <<-INPUT_END &&
1678         blob
1679         mark :1
1680         data 10
1681         test file
1682
1683         reset refs/heads/sub
1684         commit refs/heads/sub
1685         mark :2
1686         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1687         data 12
1688         sub_initial
1689         M 100644 :1 file
1690
1691         blob
1692         mark :3
1693         data <<DATAEND
1694         [submodule "sub"]
1695                 path = sub
1696                 url = "$(pwd)/sub"
1697         DATAEND
1698
1699         commit refs/heads/subuse1
1700         mark :4
1701         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1702         data 8
1703         initial
1704         from refs/heads/main
1705         M 100644 :3 .gitmodules
1706         M 160000 :2 sub
1707
1708         blob
1709         mark :5
1710         data 20
1711         test file
1712         more data
1713
1714         commit refs/heads/sub
1715         mark :6
1716         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1717         data 11
1718         sub_second
1719         from :2
1720         M 100644 :5 file
1721
1722         commit refs/heads/subuse1
1723         mark :7
1724         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1725         data 7
1726         second
1727         from :4
1728         M 160000 :6 sub
1729
1730         INPUT_END
1731
1732         git fast-import <input &&
1733         git checkout subuse1 &&
1734         rm -rf sub &&
1735         mkdir sub &&
1736         (
1737                 cd sub &&
1738                 git init &&
1739                 git fetch --update-head-ok .. refs/heads/sub:refs/heads/main &&
1740                 git checkout main
1741         ) &&
1742         git submodule init &&
1743         git submodule update
1744 '
1745
1746 test_expect_success 'P: verbatim SHA gitlinks' '
1747         SUBLAST=$(git rev-parse --verify sub) &&
1748         SUBPREV=$(git rev-parse --verify sub^) &&
1749
1750         cat >input <<-INPUT_END &&
1751         blob
1752         mark :1
1753         data <<DATAEND
1754         [submodule "sub"]
1755                 path = sub
1756                 url = "$(pwd)/sub"
1757         DATAEND
1758
1759         commit refs/heads/subuse2
1760         mark :2
1761         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1762         data 8
1763         initial
1764         from refs/heads/main
1765         M 100644 :1 .gitmodules
1766         M 160000 $SUBPREV sub
1767
1768         commit refs/heads/subuse2
1769         mark :3
1770         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1771         data 7
1772         second
1773         from :2
1774         M 160000 $SUBLAST sub
1775
1776         INPUT_END
1777
1778         git branch -D sub &&
1779         git gc &&
1780         git prune &&
1781         git fast-import <input &&
1782         test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)
1783 '
1784
1785 test_expect_success 'P: fail on inline gitlink' '
1786         test_tick &&
1787         cat >input <<-INPUT_END &&
1788         commit refs/heads/subuse3
1789         mark :1
1790         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1791         data <<COMMIT
1792         corrupt
1793         COMMIT
1794
1795         from refs/heads/subuse2
1796         M 160000 inline sub
1797         data <<DATA
1798         $SUBPREV
1799         DATA
1800
1801         INPUT_END
1802
1803         test_must_fail git fast-import <input
1804 '
1805
1806 test_expect_success 'P: fail on blob mark in gitlink' '
1807         test_tick &&
1808         cat >input <<-INPUT_END &&
1809         blob
1810         mark :1
1811         data <<DATA
1812         $SUBPREV
1813         DATA
1814
1815         commit refs/heads/subuse3
1816         mark :2
1817         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1818         data <<COMMIT
1819         corrupt
1820         COMMIT
1821
1822         from refs/heads/subuse2
1823         M 160000 :1 sub
1824
1825         INPUT_END
1826
1827         test_must_fail git fast-import <input
1828 '
1829
1830 ###
1831 ### series Q (notes)
1832 ###
1833
1834 test_expect_success 'Q: commit notes' '
1835         note1_data="The first note for the first commit" &&
1836         note2_data="The first note for the second commit" &&
1837         note3_data="The first note for the third commit" &&
1838         note1b_data="The second note for the first commit" &&
1839         note1c_data="The third note for the first commit" &&
1840         note2b_data="The second note for the second commit" &&
1841
1842         test_tick &&
1843         cat >input <<-INPUT_END &&
1844         blob
1845         mark :2
1846         data <<EOF
1847         $file2_data
1848         EOF
1849
1850         commit refs/heads/notes-test
1851         mark :3
1852         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1853         data <<COMMIT
1854         first (:3)
1855         COMMIT
1856
1857         M 644 :2 file2
1858
1859         blob
1860         mark :4
1861         data $file4_len
1862         $file4_data
1863         commit refs/heads/notes-test
1864         mark :5
1865         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1866         data <<COMMIT
1867         second (:5)
1868         COMMIT
1869
1870         M 644 :4 file4
1871
1872         commit refs/heads/notes-test
1873         mark :6
1874         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1875         data <<COMMIT
1876         third (:6)
1877         COMMIT
1878
1879         M 644 inline file5
1880         data <<EOF
1881         $file5_data
1882         EOF
1883
1884         M 755 inline file6
1885         data <<EOF
1886         $file6_data
1887         EOF
1888
1889         blob
1890         mark :7
1891         data <<EOF
1892         $note1_data
1893         EOF
1894
1895         blob
1896         mark :8
1897         data <<EOF
1898         $note2_data
1899         EOF
1900
1901         commit refs/notes/foobar
1902         mark :9
1903         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1904         data <<COMMIT
1905         notes (:9)
1906         COMMIT
1907
1908         N :7 :3
1909         N :8 :5
1910         N inline :6
1911         data <<EOF
1912         $note3_data
1913         EOF
1914
1915         commit refs/notes/foobar
1916         mark :10
1917         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1918         data <<COMMIT
1919         notes (:10)
1920         COMMIT
1921
1922         N inline :3
1923         data <<EOF
1924         $note1b_data
1925         EOF
1926
1927         commit refs/notes/foobar2
1928         mark :11
1929         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1930         data <<COMMIT
1931         notes (:11)
1932         COMMIT
1933
1934         N inline :3
1935         data <<EOF
1936         $note1c_data
1937         EOF
1938
1939         commit refs/notes/foobar
1940         mark :12
1941         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1942         data <<COMMIT
1943         notes (:12)
1944         COMMIT
1945
1946         deleteall
1947         N inline :5
1948         data <<EOF
1949         $note2b_data
1950         EOF
1951
1952         INPUT_END
1953
1954         git fast-import <input &&
1955         git whatchanged notes-test
1956 '
1957
1958 test_expect_success 'Q: verify pack' '
1959         verify_packs
1960 '
1961
1962 test_expect_success 'Q: verify first commit' '
1963         commit1=$(git rev-parse notes-test~2) &&
1964         commit2=$(git rev-parse notes-test^) &&
1965         commit3=$(git rev-parse notes-test) &&
1966
1967         cat >expect <<-EOF &&
1968         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1969         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1970
1971         first (:3)
1972         EOF
1973         git cat-file commit notes-test~2 | sed 1d >actual &&
1974         test_cmp expect actual
1975 '
1976
1977 test_expect_success 'Q: verify second commit' '
1978         cat >expect <<-EOF &&
1979         parent $commit1
1980         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1981         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1982
1983         second (:5)
1984         EOF
1985         git cat-file commit notes-test^ | sed 1d >actual &&
1986         test_cmp expect actual
1987 '
1988
1989 test_expect_success 'Q: verify third commit' '
1990         cat >expect <<-EOF &&
1991         parent $commit2
1992         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1993         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1994
1995         third (:6)
1996         EOF
1997         git cat-file commit notes-test | sed 1d >actual &&
1998         test_cmp expect actual
1999 '
2000
2001 test_expect_success 'Q: verify first notes commit' '
2002         cat >expect <<-EOF &&
2003         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2004         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2005
2006         notes (:9)
2007         EOF
2008         git cat-file commit refs/notes/foobar~2 | sed 1d >actual &&
2009         test_cmp expect actual
2010 '
2011
2012 test_expect_success 'Q: verify first notes tree' '
2013         cat >expect.unsorted <<-EOF &&
2014         100644 blob $commit1
2015         100644 blob $commit2
2016         100644 blob $commit3
2017         EOF
2018         cat expect.unsorted | sort >expect &&
2019         git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]*  / /" >actual &&
2020         test_cmp expect actual
2021 '
2022
2023 test_expect_success 'Q: verify first note for first commit' '
2024         echo "$note1_data" >expect &&
2025         git cat-file blob refs/notes/foobar~2:$commit1 >actual &&
2026         test_cmp expect actual
2027 '
2028
2029 test_expect_success 'Q: verify first note for second commit' '
2030         echo "$note2_data" >expect &&
2031         git cat-file blob refs/notes/foobar~2:$commit2 >actual &&
2032         test_cmp expect actual
2033 '
2034
2035 test_expect_success 'Q: verify first note for third commit' '
2036         echo "$note3_data" >expect &&
2037         git cat-file blob refs/notes/foobar~2:$commit3 >actual &&
2038         test_cmp expect actual
2039 '
2040
2041 test_expect_success 'Q: verify second notes commit' '
2042         cat >expect <<-EOF &&
2043         parent $(git rev-parse --verify refs/notes/foobar~2)
2044         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2045         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2046
2047         notes (:10)
2048         EOF
2049         git cat-file commit refs/notes/foobar^ | sed 1d >actual &&
2050         test_cmp expect actual
2051 '
2052
2053 test_expect_success 'Q: verify second notes tree' '
2054         cat >expect.unsorted <<-EOF &&
2055         100644 blob $commit1
2056         100644 blob $commit2
2057         100644 blob $commit3
2058         EOF
2059         cat expect.unsorted | sort >expect &&
2060         git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]*   / /" >actual &&
2061         test_cmp expect actual
2062 '
2063
2064 test_expect_success 'Q: verify second note for first commit' '
2065         echo "$note1b_data" >expect &&
2066         git cat-file blob refs/notes/foobar^:$commit1 >actual &&
2067         test_cmp expect actual
2068 '
2069
2070 test_expect_success 'Q: verify first note for second commit' '
2071         echo "$note2_data" >expect &&
2072         git cat-file blob refs/notes/foobar^:$commit2 >actual &&
2073         test_cmp expect actual
2074 '
2075
2076 test_expect_success 'Q: verify first note for third commit' '
2077         echo "$note3_data" >expect &&
2078         git cat-file blob refs/notes/foobar^:$commit3 >actual &&
2079         test_cmp expect actual
2080 '
2081
2082 test_expect_success 'Q: verify third notes commit' '
2083         cat >expect <<-EOF &&
2084         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2085         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2086
2087         notes (:11)
2088         EOF
2089         git cat-file commit refs/notes/foobar2 | sed 1d >actual &&
2090         test_cmp expect actual
2091 '
2092
2093 test_expect_success 'Q: verify third notes tree' '
2094         cat >expect.unsorted <<-EOF &&
2095         100644 blob $commit1
2096         EOF
2097         cat expect.unsorted | sort >expect &&
2098         git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]*   / /" >actual &&
2099         test_cmp expect actual
2100 '
2101
2102 test_expect_success 'Q: verify third note for first commit' '
2103         echo "$note1c_data" >expect &&
2104         git cat-file blob refs/notes/foobar2:$commit1 >actual &&
2105         test_cmp expect actual
2106 '
2107
2108 test_expect_success 'Q: verify fourth notes commit' '
2109         cat >expect <<-EOF &&
2110         parent $(git rev-parse --verify refs/notes/foobar^)
2111         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2112         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2113
2114         notes (:12)
2115         EOF
2116         git cat-file commit refs/notes/foobar | sed 1d >actual &&
2117         test_cmp expect actual
2118 '
2119
2120 test_expect_success 'Q: verify fourth notes tree' '
2121         cat >expect.unsorted <<-EOF &&
2122         100644 blob $commit2
2123         EOF
2124         cat expect.unsorted | sort >expect &&
2125         git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]*    / /" >actual &&
2126         test_cmp expect actual
2127 '
2128
2129 test_expect_success 'Q: verify second note for second commit' '
2130         echo "$note2b_data" >expect &&
2131         git cat-file blob refs/notes/foobar:$commit2 >actual &&
2132         test_cmp expect actual
2133 '
2134
2135 test_expect_success 'Q: deny note on empty branch' '
2136         cat >input <<-EOF &&
2137         reset refs/heads/Q0
2138
2139         commit refs/heads/note-Q0
2140         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2141         data <<COMMIT
2142         Note for an empty branch.
2143         COMMIT
2144
2145         N inline refs/heads/Q0
2146         data <<NOTE
2147         some note
2148         NOTE
2149         EOF
2150         test_must_fail git fast-import <input
2151 '
2152 ###
2153 ### series R (feature and option)
2154 ###
2155
2156 test_expect_success 'R: abort on unsupported feature' '
2157         cat >input <<-EOF &&
2158         feature no-such-feature-exists
2159         EOF
2160
2161         test_must_fail git fast-import <input
2162 '
2163
2164 test_expect_success 'R: supported feature is accepted' '
2165         cat >input <<-EOF &&
2166         feature date-format=now
2167         EOF
2168
2169         git fast-import <input
2170 '
2171
2172 test_expect_success 'R: abort on receiving feature after data command' '
2173         cat >input <<-EOF &&
2174         blob
2175         data 3
2176         hi
2177         feature date-format=now
2178         EOF
2179
2180         test_must_fail git fast-import <input
2181 '
2182
2183 test_expect_success 'R: import-marks features forbidden by default' '
2184         >git.marks &&
2185         echo "feature import-marks=git.marks" >input &&
2186         test_must_fail git fast-import <input &&
2187         echo "feature import-marks-if-exists=git.marks" >input &&
2188         test_must_fail git fast-import <input
2189 '
2190
2191 test_expect_success 'R: only one import-marks feature allowed per stream' '
2192         >git.marks &&
2193         >git2.marks &&
2194         cat >input <<-EOF &&
2195         feature import-marks=git.marks
2196         feature import-marks=git2.marks
2197         EOF
2198
2199         test_must_fail git fast-import --allow-unsafe-features <input
2200 '
2201
2202 test_expect_success 'R: export-marks feature forbidden by default' '
2203         echo "feature export-marks=git.marks" >input &&
2204         test_must_fail git fast-import <input
2205 '
2206
2207 test_expect_success 'R: export-marks feature results in a marks file being created' '
2208         cat >input <<-EOF &&
2209         feature export-marks=git.marks
2210         blob
2211         mark :1
2212         data 3
2213         hi
2214
2215         EOF
2216
2217         git fast-import --allow-unsafe-features <input &&
2218         grep :1 git.marks
2219 '
2220
2221 test_expect_success 'R: export-marks options can be overridden by commandline options' '
2222         cat >input <<-\EOF &&
2223         feature export-marks=feature-sub/git.marks
2224         blob
2225         mark :1
2226         data 3
2227         hi
2228
2229         EOF
2230         git fast-import --allow-unsafe-features \
2231                         --export-marks=cmdline-sub/other.marks <input &&
2232         grep :1 cmdline-sub/other.marks &&
2233         test_path_is_missing feature-sub
2234 '
2235
2236 test_expect_success 'R: catch typo in marks file name' '
2237         test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
2238         echo "feature import-marks=nonexistent.marks" |
2239         test_must_fail git fast-import --allow-unsafe-features
2240 '
2241
2242 test_expect_success 'R: import and output marks can be the same file' '
2243         rm -f io.marks &&
2244         blob=$(echo hi | git hash-object --stdin) &&
2245         cat >expect <<-EOF &&
2246         :1 $blob
2247         :2 $blob
2248         EOF
2249         git fast-import --export-marks=io.marks <<-\EOF &&
2250         blob
2251         mark :1
2252         data 3
2253         hi
2254
2255         EOF
2256         git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
2257         blob
2258         mark :2
2259         data 3
2260         hi
2261
2262         EOF
2263         test_cmp expect io.marks
2264 '
2265
2266 test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' '
2267         rm -f io.marks &&
2268         test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF
2269         blob
2270         mark :1
2271         data 3
2272         hi
2273
2274         EOF
2275 '
2276
2277 test_expect_success 'R: --import-marks-if-exists' '
2278         rm -f io.marks &&
2279         blob=$(echo hi | git hash-object --stdin) &&
2280         echo ":1 $blob" >expect &&
2281         git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF &&
2282         blob
2283         mark :1
2284         data 3
2285         hi
2286
2287         EOF
2288         test_cmp expect io.marks
2289 '
2290
2291 test_expect_success 'R: feature import-marks-if-exists' '
2292         rm -f io.marks &&
2293
2294         git fast-import --export-marks=io.marks \
2295                         --allow-unsafe-features <<-\EOF &&
2296         feature import-marks-if-exists=not_io.marks
2297         EOF
2298         test_must_be_empty io.marks &&
2299
2300         blob=$(echo hi | git hash-object --stdin) &&
2301
2302         echo ":1 $blob" >io.marks &&
2303         echo ":1 $blob" >expect &&
2304         echo ":2 $blob" >>expect &&
2305
2306         git fast-import --export-marks=io.marks \
2307                         --allow-unsafe-features <<-\EOF &&
2308         feature import-marks-if-exists=io.marks
2309         blob
2310         mark :2
2311         data 3
2312         hi
2313
2314         EOF
2315         test_cmp expect io.marks &&
2316
2317         echo ":3 $blob" >>expect &&
2318
2319         git fast-import --import-marks=io.marks \
2320                         --export-marks=io.marks \
2321                         --allow-unsafe-features <<-\EOF &&
2322         feature import-marks-if-exists=not_io.marks
2323         blob
2324         mark :3
2325         data 3
2326         hi
2327
2328         EOF
2329         test_cmp expect io.marks &&
2330
2331         git fast-import --import-marks-if-exists=not_io.marks \
2332                         --export-marks=io.marks \
2333                         --allow-unsafe-features <<-\EOF &&
2334         feature import-marks-if-exists=io.marks
2335         EOF
2336         test_must_be_empty io.marks
2337 '
2338
2339 test_expect_success 'R: import to output marks works without any content' '
2340         cat >input <<-EOF &&
2341         feature import-marks=marks.out
2342         feature export-marks=marks.new
2343         EOF
2344
2345         git fast-import --allow-unsafe-features <input &&
2346         test_cmp marks.out marks.new
2347 '
2348
2349 test_expect_success 'R: import marks prefers commandline marks file over the stream' '
2350         cat >input <<-EOF &&
2351         feature import-marks=nonexistent.marks
2352         feature export-marks=marks.new
2353         EOF
2354
2355         git fast-import --import-marks=marks.out --allow-unsafe-features <input &&
2356         test_cmp marks.out marks.new
2357 '
2358
2359
2360 test_expect_success 'R: multiple --import-marks= should be honoured' '
2361         cat >input <<-EOF &&
2362         feature import-marks=nonexistent.marks
2363         feature export-marks=combined.marks
2364         EOF
2365
2366         head -n2 marks.out > one.marks &&
2367         tail -n +3 marks.out > two.marks &&
2368         git fast-import --import-marks=one.marks --import-marks=two.marks \
2369                 --allow-unsafe-features <input &&
2370         test_cmp marks.out combined.marks
2371 '
2372
2373 test_expect_success 'R: feature relative-marks should be honoured' '
2374         cat >input <<-EOF &&
2375         feature relative-marks
2376         feature import-marks=relative.in
2377         feature export-marks=relative.out
2378         EOF
2379
2380         mkdir -p .git/info/fast-import/ &&
2381         cp marks.new .git/info/fast-import/relative.in &&
2382         git fast-import --allow-unsafe-features <input &&
2383         test_cmp marks.new .git/info/fast-import/relative.out
2384 '
2385
2386 test_expect_success 'R: feature no-relative-marks should be honoured' '
2387         cat >input <<-EOF &&
2388         feature relative-marks
2389         feature import-marks=relative.in
2390         feature no-relative-marks
2391         feature export-marks=non-relative.out
2392         EOF
2393
2394         git fast-import --allow-unsafe-features <input &&
2395         test_cmp marks.new non-relative.out
2396 '
2397
2398 test_expect_success 'R: feature ls supported' '
2399         echo "feature ls" |
2400         git fast-import
2401 '
2402
2403 test_expect_success 'R: feature cat-blob supported' '
2404         echo "feature cat-blob" |
2405         git fast-import
2406 '
2407
2408 test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
2409         test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
2410 '
2411
2412 test_expect_success !MINGW 'R: print old blob' '
2413         blob=$(echo "yes it can" | git hash-object -w --stdin) &&
2414         cat >expect <<-EOF &&
2415         ${blob} blob 11
2416         yes it can
2417
2418         EOF
2419         echo "cat-blob $blob" |
2420         git fast-import --cat-blob-fd=6 6>actual &&
2421         test_cmp expect actual
2422 '
2423
2424 test_expect_success !MINGW 'R: in-stream cat-blob-fd not respected' '
2425         echo hello >greeting &&
2426         blob=$(git hash-object -w greeting) &&
2427         cat >expect <<-EOF &&
2428         ${blob} blob 6
2429         hello
2430
2431         EOF
2432         git fast-import --cat-blob-fd=3 3>actual.3 >actual.1 <<-EOF &&
2433         cat-blob $blob
2434         EOF
2435         test_cmp expect actual.3 &&
2436         test_must_be_empty actual.1 &&
2437         git fast-import 3>actual.3 >actual.1 <<-EOF &&
2438         option cat-blob-fd=3
2439         cat-blob $blob
2440         EOF
2441         test_must_be_empty actual.3 &&
2442         test_cmp expect actual.1
2443 '
2444
2445 test_expect_success !MINGW 'R: print mark for new blob' '
2446         echo "effluentish" | git hash-object --stdin >expect &&
2447         git fast-import --cat-blob-fd=6 6>actual <<-\EOF &&
2448         blob
2449         mark :1
2450         data <<BLOB_END
2451         effluentish
2452         BLOB_END
2453         get-mark :1
2454         EOF
2455         test_cmp expect actual
2456 '
2457
2458 test_expect_success !MINGW 'R: print new blob' '
2459         blob=$(echo "yep yep yep" | git hash-object --stdin) &&
2460         cat >expect <<-EOF &&
2461         ${blob} blob 12
2462         yep yep yep
2463
2464         EOF
2465         git fast-import --cat-blob-fd=6 6>actual <<-\EOF &&
2466         blob
2467         mark :1
2468         data <<BLOB_END
2469         yep yep yep
2470         BLOB_END
2471         cat-blob :1
2472         EOF
2473         test_cmp expect actual
2474 '
2475
2476 test_expect_success !MINGW 'R: print new blob by sha1' '
2477         blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
2478         cat >expect <<-EOF &&
2479         ${blob} blob 25
2480         a new blob named by sha1
2481
2482         EOF
2483         git fast-import --cat-blob-fd=6 6>actual <<-EOF &&
2484         blob
2485         data <<BLOB_END
2486         a new blob named by sha1
2487         BLOB_END
2488         cat-blob $blob
2489         EOF
2490         test_cmp expect actual
2491 '
2492
2493 test_expect_success 'setup: big file' '
2494         (
2495                 echo "the quick brown fox jumps over the lazy dog" >big &&
2496                 for i in 1 2 3
2497                 do
2498                         cat big big big big >bigger &&
2499                         cat bigger bigger bigger bigger >big ||
2500                         exit
2501                 done
2502         )
2503 '
2504
2505 test_expect_success 'R: print two blobs to stdout' '
2506         blob1=$(git hash-object big) &&
2507         blob1_len=$(wc -c <big) &&
2508         blob2=$(echo hello | git hash-object --stdin) &&
2509         {
2510                 echo ${blob1} blob $blob1_len &&
2511                 cat big &&
2512                 cat <<-EOF
2513
2514                 ${blob2} blob 6
2515                 hello
2516
2517                 EOF
2518         } >expect &&
2519         {
2520                 cat <<-\END_PART1 &&
2521                         blob
2522                         mark :1
2523                         data <<data_end
2524                 END_PART1
2525                 cat big &&
2526                 cat <<-\EOF
2527                         data_end
2528                         blob
2529                         mark :2
2530                         data <<data_end
2531                         hello
2532                         data_end
2533                         cat-blob :1
2534                         cat-blob :2
2535                 EOF
2536         } |
2537         git fast-import >actual &&
2538         test_cmp expect actual
2539 '
2540
2541 test_expect_success PIPE 'R: copy using cat-file' '
2542         expect_id=$(git hash-object big) &&
2543         expect_len=$(wc -c <big) &&
2544         echo $expect_id blob $expect_len >expect.response &&
2545
2546         rm -f blobs &&
2547
2548         mkfifo blobs &&
2549         (
2550                 export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE &&
2551                 cat <<-\EOF &&
2552                 feature cat-blob
2553                 blob
2554                 mark :1
2555                 data <<BLOB
2556                 EOF
2557                 cat big &&
2558                 cat <<-\EOF &&
2559                 BLOB
2560                 cat-blob :1
2561                 EOF
2562
2563                 read blob_id type size <&3 &&
2564                 echo "$blob_id $type $size" >response &&
2565                 test_copy_bytes $size >blob <&3 &&
2566                 read newline <&3 &&
2567
2568                 cat <<-EOF &&
2569                 commit refs/heads/copied
2570                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2571                 data <<COMMIT
2572                 copy big file as file3
2573                 COMMIT
2574                 M 644 inline file3
2575                 data <<BLOB
2576                 EOF
2577                 cat blob &&
2578                 echo BLOB
2579         ) 3<blobs |
2580         git fast-import --cat-blob-fd=3 3>blobs &&
2581         git show copied:file3 >actual &&
2582         test_cmp expect.response response &&
2583         test_cmp big actual
2584 '
2585
2586 test_expect_success PIPE 'R: print blob mid-commit' '
2587         rm -f blobs &&
2588         echo "A blob from _before_ the commit." >expect &&
2589         mkfifo blobs &&
2590         (
2591                 exec 3<blobs &&
2592                 cat <<-EOF &&
2593                 feature cat-blob
2594                 blob
2595                 mark :1
2596                 data <<BLOB
2597                 A blob from _before_ the commit.
2598                 BLOB
2599                 commit refs/heads/temporary
2600                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2601                 data <<COMMIT
2602                 Empty commit
2603                 COMMIT
2604                 cat-blob :1
2605                 EOF
2606
2607                 read blob_id type size <&3 &&
2608                 test_copy_bytes $size >actual <&3 &&
2609                 read newline <&3 &&
2610
2611                 echo
2612         ) |
2613         git fast-import --cat-blob-fd=3 3>blobs &&
2614         test_cmp expect actual
2615 '
2616
2617 test_expect_success PIPE 'R: print staged blob within commit' '
2618         rm -f blobs &&
2619         echo "A blob from _within_ the commit." >expect &&
2620         mkfifo blobs &&
2621         (
2622                 exec 3<blobs &&
2623                 cat <<-EOF &&
2624                 feature cat-blob
2625                 commit refs/heads/within
2626                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2627                 data <<COMMIT
2628                 Empty commit
2629                 COMMIT
2630                 M 644 inline within
2631                 data <<BLOB
2632                 A blob from _within_ the commit.
2633                 BLOB
2634                 EOF
2635
2636                 to_get=$(
2637                         echo "A blob from _within_ the commit." |
2638                         git hash-object --stdin
2639                 ) &&
2640                 echo "cat-blob $to_get" &&
2641
2642                 read blob_id type size <&3 &&
2643                 test_copy_bytes $size >actual <&3 &&
2644                 read newline <&3 &&
2645
2646                 echo deleteall
2647         ) |
2648         git fast-import --cat-blob-fd=3 3>blobs &&
2649         test_cmp expect actual
2650 '
2651
2652 test_expect_success 'R: quiet option results in no stats being output' '
2653         cat >input <<-EOF &&
2654         option git quiet
2655         blob
2656         data 3
2657         hi
2658
2659         EOF
2660
2661         git fast-import 2>output <input &&
2662         test_must_be_empty output
2663 '
2664
2665 test_expect_success 'R: feature done means terminating "done" is mandatory' '
2666         echo feature done | test_must_fail git fast-import &&
2667         test_must_fail git fast-import --done </dev/null
2668 '
2669
2670 test_expect_success 'R: terminating "done" with trailing gibberish is ok' '
2671         git fast-import <<-\EOF &&
2672         feature done
2673         done
2674         trailing gibberish
2675         EOF
2676         git fast-import <<-\EOF
2677         done
2678         more trailing gibberish
2679         EOF
2680 '
2681
2682 test_expect_success 'R: terminating "done" within commit' '
2683         cat >expect <<-\EOF &&
2684         OBJID
2685         :000000 100644 OBJID OBJID A    hello.c
2686         :000000 100644 OBJID OBJID A    hello2.c
2687         EOF
2688         git fast-import <<-EOF &&
2689         commit refs/heads/done-ends
2690         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2691         data <<EOT
2692         Commit terminated by "done" command
2693         EOT
2694         M 100644 inline hello.c
2695         data <<EOT
2696         Hello, world.
2697         EOT
2698         C hello.c hello2.c
2699         done
2700         EOF
2701         git rev-list done-ends |
2702         git diff-tree -r --stdin --root --always |
2703         sed -e "s/$OID_REGEX/OBJID/g" >actual &&
2704         test_cmp expect actual
2705 '
2706
2707 test_expect_success 'R: die on unknown option' '
2708         cat >input <<-EOF &&
2709         option git non-existing-option
2710         EOF
2711
2712         test_must_fail git fast-import <input
2713 '
2714
2715 test_expect_success 'R: unknown commandline options are rejected' '\
2716         test_must_fail git fast-import --non-existing-option < /dev/null
2717 '
2718
2719 test_expect_success 'R: die on invalid option argument' '
2720         echo "option git active-branches=-5" |
2721         test_must_fail git fast-import &&
2722         echo "option git depth=" |
2723         test_must_fail git fast-import &&
2724         test_must_fail git fast-import --depth="5 elephants" </dev/null
2725 '
2726
2727 test_expect_success 'R: ignore non-git options' '
2728         cat >input <<-EOF &&
2729         option non-existing-vcs non-existing-option
2730         EOF
2731
2732         git fast-import <input
2733 '
2734
2735 test_expect_success 'R: corrupt lines do not mess marks file' '
2736         rm -f io.marks &&
2737         blob=$(echo hi | git hash-object --stdin) &&
2738         cat >expect <<-EOF &&
2739         :3 $ZERO_OID
2740         :1 $blob
2741         :2 $blob
2742         EOF
2743         cp expect io.marks &&
2744         test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
2745
2746         EOF
2747         test_cmp expect io.marks
2748 '
2749
2750 ##
2751 ## R: very large blobs
2752 ##
2753 test_expect_success 'R: blob bigger than threshold' '
2754         blobsize=$((2*1024*1024 + 53)) &&
2755         test-tool genrandom bar $blobsize >expect &&
2756         cat >input <<-INPUT_END &&
2757         commit refs/heads/big-file
2758         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2759         data <<COMMIT
2760         R - big file
2761         COMMIT
2762
2763         M 644 inline big1
2764         data $blobsize
2765         INPUT_END
2766         cat expect >>input &&
2767         cat >>input <<-INPUT_END &&
2768         M 644 inline big2
2769         data $blobsize
2770         INPUT_END
2771         cat expect >>input &&
2772         echo >>input &&
2773
2774         test_create_repo R &&
2775         git --git-dir=R/.git config fastimport.unpackLimit 0 &&
2776         git --git-dir=R/.git fast-import --big-file-threshold=1 <input
2777 '
2778
2779 test_expect_success 'R: verify created pack' '
2780         (
2781                 cd R &&
2782                 verify_packs -v > ../verify
2783         )
2784 '
2785
2786 test_expect_success 'R: verify written objects' '
2787         git --git-dir=R/.git cat-file blob big-file:big1 >actual &&
2788         test_cmp_bin expect actual &&
2789         a=$(git --git-dir=R/.git rev-parse big-file:big1) &&
2790         b=$(git --git-dir=R/.git rev-parse big-file:big2) &&
2791         test $a = $b
2792 '
2793
2794 test_expect_success 'R: blob appears only once' '
2795         n=$(grep $a verify | wc -l) &&
2796         test 1 = $n
2797 '
2798
2799 ###
2800 ### series S
2801 ###
2802 #
2803 # Make sure missing spaces and EOLs after mark references
2804 # cause errors.
2805 #
2806 # Setup:
2807 #
2808 #   1--2--4
2809 #    \   /
2810 #     -3-
2811 #
2812 #   commit marks:  301, 302, 303, 304
2813 #   blob marks:              403, 404, resp.
2814 #   note mark:          202
2815 #
2816 # The error message when a space is missing not at the
2817 # end of the line is:
2818 #
2819 #   Missing space after ..
2820 #
2821 # or when extra characters come after the mark at the end
2822 # of the line:
2823 #
2824 #   Garbage after ..
2825 #
2826 # or when the dataref is neither "inline " or a known SHA1,
2827 #
2828 #   Invalid dataref ..
2829 #
2830 test_expect_success 'S: initialize for S tests' '
2831         test_tick &&
2832
2833         cat >input <<-INPUT_END &&
2834         commit refs/heads/S
2835         mark :301
2836         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2837         data <<COMMIT
2838         commit 1
2839         COMMIT
2840         M 100644 inline hello.c
2841         data <<BLOB
2842         blob 1
2843         BLOB
2844
2845         commit refs/heads/S
2846         mark :302
2847         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2848         data <<COMMIT
2849         commit 2
2850         COMMIT
2851         from :301
2852         M 100644 inline hello.c
2853         data <<BLOB
2854         blob 2
2855         BLOB
2856
2857         blob
2858         mark :403
2859         data <<BLOB
2860         blob 3
2861         BLOB
2862
2863         blob
2864         mark :202
2865         data <<BLOB
2866         note 2
2867         BLOB
2868         INPUT_END
2869
2870         git fast-import --export-marks=marks <input
2871 '
2872
2873 #
2874 # filemodify, three datarefs
2875 #
2876 test_expect_success 'S: filemodify with garbage after mark must fail' '
2877         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2878         commit refs/heads/S
2879         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2880         data <<COMMIT
2881         commit N
2882         COMMIT
2883         M 100644 :403x hello.c
2884         EOF
2885         test_i18ngrep "space after mark" err
2886 '
2887
2888 # inline is misspelled; fast-import thinks it is some unknown dataref
2889 test_expect_success 'S: filemodify with garbage after inline must fail' '
2890         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2891         commit refs/heads/S
2892         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2893         data <<COMMIT
2894         commit N
2895         COMMIT
2896         M 100644 inlineX hello.c
2897         data <<BLOB
2898         inline
2899         BLOB
2900         EOF
2901         test_i18ngrep "nvalid dataref" err
2902 '
2903
2904 test_expect_success 'S: filemodify with garbage after sha1 must fail' '
2905         sha1=$(grep :403 marks | cut -d\  -f2) &&
2906         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2907         commit refs/heads/S
2908         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2909         data <<COMMIT
2910         commit N
2911         COMMIT
2912         M 100644 ${sha1}x hello.c
2913         EOF
2914         test_i18ngrep "space after SHA1" err
2915 '
2916
2917 #
2918 # notemodify, three ways to say dataref
2919 #
2920 test_expect_success 'S: notemodify with garbage after mark dataref must fail' '
2921         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2922         commit refs/heads/S
2923         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2924         data <<COMMIT
2925         commit S note dataref markref
2926         COMMIT
2927         N :202x :302
2928         EOF
2929         test_i18ngrep "space after mark" err
2930 '
2931
2932 test_expect_success 'S: notemodify with garbage after inline dataref must fail' '
2933         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2934         commit refs/heads/S
2935         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2936         data <<COMMIT
2937         commit S note dataref inline
2938         COMMIT
2939         N inlineX :302
2940         data <<BLOB
2941         note blob
2942         BLOB
2943         EOF
2944         test_i18ngrep "nvalid dataref" err
2945 '
2946
2947 test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
2948         sha1=$(grep :202 marks | cut -d\  -f2) &&
2949         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2950         commit refs/heads/S
2951         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2952         data <<COMMIT
2953         commit S note dataref sha1
2954         COMMIT
2955         N ${sha1}x :302
2956         EOF
2957         test_i18ngrep "space after SHA1" err
2958 '
2959
2960 #
2961 # notemodify, mark in commit-ish
2962 #
2963 test_expect_success 'S: notemodify with garbage after mark commit-ish must fail' '
2964         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2965         commit refs/heads/Snotes
2966         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2967         data <<COMMIT
2968         commit S note commit-ish
2969         COMMIT
2970         N :202 :302x
2971         EOF
2972         test_i18ngrep "after mark" err
2973 '
2974
2975 #
2976 # from
2977 #
2978 test_expect_success 'S: from with garbage after mark must fail' '
2979         test_must_fail \
2980         git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err &&
2981         commit refs/heads/S2
2982         mark :303
2983         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2984         data <<COMMIT
2985         commit 3
2986         COMMIT
2987         from :301x
2988         M 100644 :403 hello.c
2989         EOF
2990
2991
2992         # go create the commit, need it for merge test
2993         git fast-import --import-marks=marks --export-marks=marks <<-EOF &&
2994         commit refs/heads/S2
2995         mark :303
2996         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2997         data <<COMMIT
2998         commit 3
2999         COMMIT
3000         from :301
3001         M 100644 :403 hello.c
3002         EOF
3003
3004         # now evaluate the error
3005         test_i18ngrep "after mark" err
3006 '
3007
3008
3009 #
3010 # merge
3011 #
3012 test_expect_success 'S: merge with garbage after mark must fail' '
3013         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3014         commit refs/heads/S
3015         mark :304
3016         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3017         data <<COMMIT
3018         merge 4
3019         COMMIT
3020         from :302
3021         merge :303x
3022         M 100644 :403 hello.c
3023         EOF
3024         test_i18ngrep "after mark" err
3025 '
3026
3027 #
3028 # tag, from markref
3029 #
3030 test_expect_success 'S: tag with garbage after mark must fail' '
3031         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3032         tag refs/tags/Stag
3033         from :302x
3034         tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3035         data <<TAG
3036         tag S
3037         TAG
3038         EOF
3039         test_i18ngrep "after mark" err
3040 '
3041
3042 #
3043 # cat-blob markref
3044 #
3045 test_expect_success 'S: cat-blob with garbage after mark must fail' '
3046         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3047         cat-blob :403x
3048         EOF
3049         test_i18ngrep "after mark" err
3050 '
3051
3052 #
3053 # ls markref
3054 #
3055 test_expect_success 'S: ls with garbage after mark must fail' '
3056         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3057         ls :302x hello.c
3058         EOF
3059         test_i18ngrep "space after mark" err
3060 '
3061
3062 test_expect_success 'S: ls with garbage after sha1 must fail' '
3063         sha1=$(grep :302 marks | cut -d\  -f2) &&
3064         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3065         ls ${sha1}x hello.c
3066         EOF
3067         test_i18ngrep "space after tree-ish" err
3068 '
3069
3070 ###
3071 ### series T (ls)
3072 ###
3073 # Setup is carried over from series S.
3074
3075 test_expect_success 'T: ls root tree' '
3076         sed -e "s/Z\$//" >expect <<-EOF &&
3077         040000 tree $(git rev-parse S^{tree})   Z
3078         EOF
3079         sha1=$(git rev-parse --verify S) &&
3080         git fast-import --import-marks=marks <<-EOF >actual &&
3081         ls $sha1 ""
3082         EOF
3083         test_cmp expect actual
3084 '
3085
3086 test_expect_success 'T: delete branch' '
3087         git branch to-delete &&
3088         git fast-import <<-EOF &&
3089         reset refs/heads/to-delete
3090         from $ZERO_OID
3091         EOF
3092         test_must_fail git rev-parse --verify refs/heads/to-delete
3093 '
3094
3095 test_expect_success 'T: empty reset doesnt delete branch' '
3096         git branch not-to-delete &&
3097         git fast-import <<-EOF &&
3098         reset refs/heads/not-to-delete
3099         EOF
3100         git show-ref &&
3101         git rev-parse --verify refs/heads/not-to-delete
3102 '
3103
3104 ###
3105 ### series U (filedelete)
3106 ###
3107
3108 test_expect_success 'U: initialize for U tests' '
3109         cat >input <<-INPUT_END &&
3110         commit refs/heads/U
3111         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3112         data <<COMMIT
3113         test setup
3114         COMMIT
3115         M 100644 inline hello.c
3116         data <<BLOB
3117         blob 1
3118         BLOB
3119         M 100644 inline good/night.txt
3120         data <<BLOB
3121         sleep well
3122         BLOB
3123         M 100644 inline good/bye.txt
3124         data <<BLOB
3125         au revoir
3126         BLOB
3127
3128         INPUT_END
3129
3130         f7id=$(echo "blob 1" | git hash-object --stdin) &&
3131         f8id=$(echo "sleep well" | git hash-object --stdin) &&
3132         f9id=$(echo "au revoir" | git hash-object --stdin) &&
3133         git fast-import <input
3134 '
3135
3136 test_expect_success 'U: filedelete file succeeds' '
3137         cat >input <<-INPUT_END &&
3138         commit refs/heads/U
3139         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3140         data <<COMMIT
3141         delete good/night.txt
3142         COMMIT
3143         from refs/heads/U^0
3144         D good/night.txt
3145
3146         INPUT_END
3147
3148         git fast-import <input
3149 '
3150
3151 test_expect_success 'U: validate file delete result' '
3152         cat >expect <<-EOF &&
3153         :100644 000000 $f8id $ZERO_OID D        good/night.txt
3154         EOF
3155
3156         git diff-tree -M -r U^1 U >actual &&
3157
3158         compare_diff_raw expect actual
3159 '
3160
3161 test_expect_success 'U: filedelete directory succeeds' '
3162         cat >input <<-INPUT_END &&
3163         commit refs/heads/U
3164         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3165         data <<COMMIT
3166         delete good dir
3167         COMMIT
3168         from refs/heads/U^0
3169         D good
3170
3171         INPUT_END
3172
3173         git fast-import <input
3174 '
3175
3176 test_expect_success 'U: validate directory delete result' '
3177         cat >expect <<-EOF &&
3178         :100644 000000 $f9id $ZERO_OID D        good/bye.txt
3179         EOF
3180
3181         git diff-tree -M -r U^1 U >actual &&
3182
3183         compare_diff_raw expect actual
3184 '
3185
3186 test_expect_success 'U: filedelete root succeeds' '
3187         cat >input <<-INPUT_END &&
3188         commit refs/heads/U
3189         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3190         data <<COMMIT
3191         must succeed
3192         COMMIT
3193         from refs/heads/U^0
3194         D ""
3195
3196         INPUT_END
3197
3198         git fast-import <input
3199 '
3200
3201 test_expect_success 'U: validate root delete result' '
3202         cat >expect <<-EOF &&
3203         :100644 000000 $f7id $ZERO_OID D        hello.c
3204         EOF
3205
3206         git diff-tree -M -r U^1 U >actual &&
3207
3208         compare_diff_raw expect actual
3209 '
3210
3211 ###
3212 ### series V (checkpoint)
3213 ###
3214
3215 # The commands in input_file should not produce any output on the file
3216 # descriptor set with --cat-blob-fd (or stdout if unspecified).
3217 #
3218 # To make sure you're observing the side effects of checkpoint *before*
3219 # fast-import terminates (and thus writes out its state), check that the
3220 # fast-import process is still running using background_import_still_running
3221 # *after* evaluating the test conditions.
3222 background_import_then_checkpoint () {
3223         options=$1
3224         input_file=$2
3225
3226         mkfifo V.input
3227         exec 8<>V.input
3228         rm V.input
3229
3230         mkfifo V.output
3231         exec 9<>V.output
3232         rm V.output
3233
3234         (
3235                 git fast-import $options <&8 >&9 &
3236                 echo $! >&9
3237                 wait $!
3238                 echo >&2 "background fast-import terminated too early with exit code $?"
3239                 # Un-block the read loop in the main shell process.
3240                 echo >&9 UNEXPECTED
3241         ) &
3242         sh_pid=$!
3243         read fi_pid <&9
3244         # We don't mind if fast-import has already died by the time the test
3245         # ends.
3246         test_when_finished "
3247                 exec 8>&-; exec 9>&-;
3248                 kill $sh_pid && wait $sh_pid
3249                 kill $fi_pid && wait $fi_pid
3250                 true"
3251
3252         # Start in the background to ensure we adhere strictly to (blocking)
3253         # pipes writing sequence. We want to assume that the write below could
3254         # block, e.g. if fast-import blocks writing its own output to &9
3255         # because there is no reader on &9 yet.
3256         (
3257                 cat "$input_file"
3258                 echo "checkpoint"
3259                 echo "progress checkpoint"
3260         ) >&8 &
3261
3262         error=1 ;# assume the worst
3263         while read output <&9
3264         do
3265                 if test "$output" = "progress checkpoint"
3266                 then
3267                         error=0
3268                         break
3269                 elif test "$output" = "UNEXPECTED"
3270                 then
3271                         break
3272                 fi
3273                 # otherwise ignore cruft
3274                 echo >&2 "cruft: $output"
3275         done
3276
3277         if test $error -eq 1
3278         then
3279                 false
3280         fi
3281 }
3282
3283 background_import_still_running () {
3284         if ! kill -0 "$fi_pid"
3285         then
3286                 echo >&2 "background fast-import terminated too early"
3287                 false
3288         fi
3289 }
3290
3291 test_expect_success PIPE 'V: checkpoint helper does not get stuck with extra output' '
3292         cat >input <<-INPUT_END &&
3293         progress foo
3294         progress bar
3295
3296         INPUT_END
3297
3298         background_import_then_checkpoint "" input &&
3299         background_import_still_running
3300 '
3301
3302 test_expect_success PIPE 'V: checkpoint updates refs after reset' '
3303         cat >input <<-\INPUT_END &&
3304         reset refs/heads/V
3305         from refs/heads/U
3306
3307         INPUT_END
3308
3309         background_import_then_checkpoint "" input &&
3310         test "$(git rev-parse --verify V)" = "$(git rev-parse --verify U)" &&
3311         background_import_still_running
3312 '
3313
3314 test_expect_success PIPE 'V: checkpoint updates refs and marks after commit' '
3315         cat >input <<-INPUT_END &&
3316         commit refs/heads/V
3317         mark :1
3318         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3319         data 0
3320         from refs/heads/U
3321
3322         INPUT_END
3323
3324         background_import_then_checkpoint "--export-marks=marks.actual" input &&
3325
3326         echo ":1 $(git rev-parse --verify V)" >marks.expected &&
3327
3328         test "$(git rev-parse --verify V^)" = "$(git rev-parse --verify U)" &&
3329         test_cmp marks.expected marks.actual &&
3330         background_import_still_running
3331 '
3332
3333 # Re-create the exact same commit, but on a different branch: no new object is
3334 # created in the database, but the refs and marks still need to be updated.
3335 test_expect_success PIPE 'V: checkpoint updates refs and marks after commit (no new objects)' '
3336         cat >input <<-INPUT_END &&
3337         commit refs/heads/V2
3338         mark :2
3339         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3340         data 0
3341         from refs/heads/U
3342
3343         INPUT_END
3344
3345         background_import_then_checkpoint "--export-marks=marks.actual" input &&
3346
3347         echo ":2 $(git rev-parse --verify V2)" >marks.expected &&
3348
3349         test "$(git rev-parse --verify V2)" = "$(git rev-parse --verify V)" &&
3350         test_cmp marks.expected marks.actual &&
3351         background_import_still_running
3352 '
3353
3354 test_expect_success PIPE 'V: checkpoint updates tags after tag' '
3355         cat >input <<-INPUT_END &&
3356         tag Vtag
3357         from refs/heads/V
3358         tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3359         data 0
3360
3361         INPUT_END
3362
3363         background_import_then_checkpoint "" input &&
3364         git show-ref -d Vtag &&
3365         background_import_still_running
3366 '
3367
3368 ###
3369 ### series W (get-mark and empty orphan commits)
3370 ###
3371
3372 cat >>W-input <<-W_INPUT_END
3373         commit refs/heads/W-branch
3374         mark :1
3375         author Full Name <user@company.tld> 1000000000 +0100
3376         committer Full Name <user@company.tld> 1000000000 +0100
3377         data 27
3378         Intentionally empty commit
3379         LFsget-mark :1
3380         W_INPUT_END
3381
3382 test_expect_success !MINGW 'W: get-mark & empty orphan commit with no newlines' '
3383         sed -e s/LFs// W-input | tr L "\n" | git fast-import
3384 '
3385
3386 test_expect_success !MINGW 'W: get-mark & empty orphan commit with one newline' '
3387         sed -e s/LFs/L/ W-input | tr L "\n" | git fast-import
3388 '
3389
3390 test_expect_success !MINGW 'W: get-mark & empty orphan commit with ugly second newline' '
3391         # Technically, this should fail as it has too many linefeeds
3392         # according to the grammar in fast-import.txt.  But, for whatever
3393         # reason, it works.  Since using the correct number of newlines
3394         # does not work with older (pre-2.22) versions of git, allow apps
3395         # that used this second-newline workaround to keep working by
3396         # checking it with this test...
3397         sed -e s/LFs/LL/ W-input | tr L "\n" | git fast-import
3398 '
3399
3400 test_expect_success !MINGW 'W: get-mark & empty orphan commit with erroneous third newline' '
3401         # ...but do NOT allow more empty lines than that (see previous test).
3402         sed -e s/LFs/LLL/ W-input | tr L "\n" | test_must_fail git fast-import
3403 '
3404
3405 ###
3406 ### series X (other new features)
3407 ###
3408
3409 test_expect_success 'X: handling encoding' '
3410         test_tick &&
3411         cat >input <<-INPUT_END &&
3412         commit refs/heads/encoding
3413         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3414         encoding iso-8859-7
3415         data <<COMMIT
3416         INPUT_END
3417
3418         printf "Pi: \360\nCOMMIT\n" >>input &&
3419
3420         git fast-import <input &&
3421         git cat-file -p encoding | grep $(printf "\360") &&
3422         git log -1 --format=%B encoding | grep $(printf "\317\200")
3423 '
3424
3425 ###
3426 ### series Y (submodules and hash algorithms)
3427 ###
3428
3429 cat >Y-sub-input <<\Y_INPUT_END
3430 blob
3431 mark :1
3432 data 4
3433 foo
3434
3435 reset refs/heads/main
3436 commit refs/heads/main
3437 mark :2
3438 author Full Name <user@company.tld> 1000000000 +0100
3439 committer Full Name <user@company.tld> 1000000000 +0100
3440 data 24
3441 Test submodule commit 1
3442 M 100644 :1 file
3443
3444 blob
3445 mark :3
3446 data 8
3447 foo
3448 bar
3449
3450 commit refs/heads/main
3451 mark :4
3452 author Full Name <user@company.tld> 1000000001 +0100
3453 committer Full Name <user@company.tld> 1000000001 +0100
3454 data 24
3455 Test submodule commit 2
3456 from :2
3457 M 100644 :3 file
3458 Y_INPUT_END
3459
3460 # Note that the submodule object IDs are intentionally not translated.
3461 cat >Y-main-input <<\Y_INPUT_END
3462 blob
3463 mark :1
3464 data 4
3465 foo
3466
3467 reset refs/heads/main
3468 commit refs/heads/main
3469 mark :2
3470 author Full Name <user@company.tld> 2000000000 +0100
3471 committer Full Name <user@company.tld> 2000000000 +0100
3472 data 14
3473 Test commit 1
3474 M 100644 :1 file
3475
3476 blob
3477 mark :3
3478 data 73
3479 [submodule "sub1"]
3480         path = sub1
3481         url = https://void.example.com/main.git
3482
3483 commit refs/heads/main
3484 mark :4
3485 author Full Name <user@company.tld> 2000000001 +0100
3486 committer Full Name <user@company.tld> 2000000001 +0100
3487 data 14
3488 Test commit 2
3489 from :2
3490 M 100644 :3 .gitmodules
3491 M 160000 0712c5be7cf681388e355ef47525aaf23aee1a6d sub1
3492
3493 blob
3494 mark :5
3495 data 8
3496 foo
3497 bar
3498
3499 commit refs/heads/main
3500 mark :6
3501 author Full Name <user@company.tld> 2000000002 +0100
3502 committer Full Name <user@company.tld> 2000000002 +0100
3503 data 14
3504 Test commit 3
3505 from :4
3506 M 100644 :5 file
3507 M 160000 ff729f5e62f72c0c3978207d9a80e5f3a65f14d7 sub1
3508 Y_INPUT_END
3509
3510 cat >Y-marks <<\Y_INPUT_END
3511 :2 0712c5be7cf681388e355ef47525aaf23aee1a6d
3512 :4 ff729f5e62f72c0c3978207d9a80e5f3a65f14d7
3513 Y_INPUT_END
3514
3515 test_expect_success 'Y: setup' '
3516         test_oid_cache <<-EOF
3517         Ymain sha1:9afed2f9161ddf416c0a1863b8b0725b00070504
3518         Ymain sha256:c0a1010da1df187b2e287654793df01b464bd6f8e3f17fc1481a7dadf84caee3
3519         EOF
3520 '
3521
3522 test_expect_success 'Y: rewrite submodules' '
3523         git init main1 &&
3524         (
3525                 cd main1 &&
3526                 git init sub2 &&
3527                 git -C sub2 fast-import --export-marks=../sub2-marks <../Y-sub-input &&
3528                 git fast-import --rewrite-submodules-from=sub:../Y-marks \
3529                         --rewrite-submodules-to=sub:sub2-marks <../Y-main-input &&
3530                 test "$(git rev-parse main)" = "$(test_oid Ymain)"
3531         )
3532 '
3533
3534 test_done