send-pack: support push negotiation
[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"/lib-diff.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         ls -la .git/objects/pack/pack-*.pack >packlist &&
1636         ls -la .git/objects/pack/pack-*.pack >idxlist &&
1637         test_line_count = 4 idxlist &&
1638         test_line_count = 4 packlist &&
1639         test $(git rev-parse refs/tags/O3-2nd) = $(git rev-parse O3^) &&
1640         git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual &&
1641         test_cmp expect actual
1642 '
1643
1644 test_expect_success 'O: progress outputs as requested by input' '
1645         cat >input <<-INPUT_END &&
1646         commit refs/heads/O4
1647         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1648         data <<COMMIT
1649         zstring
1650         COMMIT
1651         commit refs/heads/O4
1652         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1653         data <<COMMIT
1654         zof
1655         COMMIT
1656         progress Two commits down, 2 to go!
1657         commit refs/heads/O4
1658         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1659         data <<COMMIT
1660         zempty
1661         COMMIT
1662         progress Three commits down, 1 to go!
1663         commit refs/heads/O4
1664         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1665         data <<COMMIT
1666         zcommits
1667         COMMIT
1668         progress done!
1669         INPUT_END
1670         git fast-import <input >actual &&
1671         grep "progress " <input >expect &&
1672         test_cmp expect actual
1673 '
1674
1675 ###
1676 ### series P (gitlinks)
1677 ###
1678
1679 test_expect_success 'P: superproject & submodule mix' '
1680         cat >input <<-INPUT_END &&
1681         blob
1682         mark :1
1683         data 10
1684         test file
1685
1686         reset refs/heads/sub
1687         commit refs/heads/sub
1688         mark :2
1689         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1690         data 12
1691         sub_initial
1692         M 100644 :1 file
1693
1694         blob
1695         mark :3
1696         data <<DATAEND
1697         [submodule "sub"]
1698                 path = sub
1699                 url = "$(pwd)/sub"
1700         DATAEND
1701
1702         commit refs/heads/subuse1
1703         mark :4
1704         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1705         data 8
1706         initial
1707         from refs/heads/main
1708         M 100644 :3 .gitmodules
1709         M 160000 :2 sub
1710
1711         blob
1712         mark :5
1713         data 20
1714         test file
1715         more data
1716
1717         commit refs/heads/sub
1718         mark :6
1719         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1720         data 11
1721         sub_second
1722         from :2
1723         M 100644 :5 file
1724
1725         commit refs/heads/subuse1
1726         mark :7
1727         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1728         data 7
1729         second
1730         from :4
1731         M 160000 :6 sub
1732
1733         INPUT_END
1734
1735         git fast-import <input &&
1736         git checkout subuse1 &&
1737         rm -rf sub &&
1738         mkdir sub &&
1739         (
1740                 cd sub &&
1741                 git init &&
1742                 git fetch --update-head-ok .. refs/heads/sub:refs/heads/main &&
1743                 git checkout main
1744         ) &&
1745         git submodule init &&
1746         git submodule update
1747 '
1748
1749 test_expect_success 'P: verbatim SHA gitlinks' '
1750         SUBLAST=$(git rev-parse --verify sub) &&
1751         SUBPREV=$(git rev-parse --verify sub^) &&
1752
1753         cat >input <<-INPUT_END &&
1754         blob
1755         mark :1
1756         data <<DATAEND
1757         [submodule "sub"]
1758                 path = sub
1759                 url = "$(pwd)/sub"
1760         DATAEND
1761
1762         commit refs/heads/subuse2
1763         mark :2
1764         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1765         data 8
1766         initial
1767         from refs/heads/main
1768         M 100644 :1 .gitmodules
1769         M 160000 $SUBPREV sub
1770
1771         commit refs/heads/subuse2
1772         mark :3
1773         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1774         data 7
1775         second
1776         from :2
1777         M 160000 $SUBLAST sub
1778
1779         INPUT_END
1780
1781         git branch -D sub &&
1782         git gc &&
1783         git prune &&
1784         git fast-import <input &&
1785         test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)
1786 '
1787
1788 test_expect_success 'P: fail on inline gitlink' '
1789         test_tick &&
1790         cat >input <<-INPUT_END &&
1791         commit refs/heads/subuse3
1792         mark :1
1793         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1794         data <<COMMIT
1795         corrupt
1796         COMMIT
1797
1798         from refs/heads/subuse2
1799         M 160000 inline sub
1800         data <<DATA
1801         $SUBPREV
1802         DATA
1803
1804         INPUT_END
1805
1806         test_must_fail git fast-import <input
1807 '
1808
1809 test_expect_success 'P: fail on blob mark in gitlink' '
1810         test_tick &&
1811         cat >input <<-INPUT_END &&
1812         blob
1813         mark :1
1814         data <<DATA
1815         $SUBPREV
1816         DATA
1817
1818         commit refs/heads/subuse3
1819         mark :2
1820         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1821         data <<COMMIT
1822         corrupt
1823         COMMIT
1824
1825         from refs/heads/subuse2
1826         M 160000 :1 sub
1827
1828         INPUT_END
1829
1830         test_must_fail git fast-import <input
1831 '
1832
1833 ###
1834 ### series Q (notes)
1835 ###
1836
1837 test_expect_success 'Q: commit notes' '
1838         note1_data="The first note for the first commit" &&
1839         note2_data="The first note for the second commit" &&
1840         note3_data="The first note for the third commit" &&
1841         note1b_data="The second note for the first commit" &&
1842         note1c_data="The third note for the first commit" &&
1843         note2b_data="The second note for the second commit" &&
1844
1845         test_tick &&
1846         cat >input <<-INPUT_END &&
1847         blob
1848         mark :2
1849         data <<EOF
1850         $file2_data
1851         EOF
1852
1853         commit refs/heads/notes-test
1854         mark :3
1855         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1856         data <<COMMIT
1857         first (:3)
1858         COMMIT
1859
1860         M 644 :2 file2
1861
1862         blob
1863         mark :4
1864         data $file4_len
1865         $file4_data
1866         commit refs/heads/notes-test
1867         mark :5
1868         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1869         data <<COMMIT
1870         second (:5)
1871         COMMIT
1872
1873         M 644 :4 file4
1874
1875         commit refs/heads/notes-test
1876         mark :6
1877         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1878         data <<COMMIT
1879         third (:6)
1880         COMMIT
1881
1882         M 644 inline file5
1883         data <<EOF
1884         $file5_data
1885         EOF
1886
1887         M 755 inline file6
1888         data <<EOF
1889         $file6_data
1890         EOF
1891
1892         blob
1893         mark :7
1894         data <<EOF
1895         $note1_data
1896         EOF
1897
1898         blob
1899         mark :8
1900         data <<EOF
1901         $note2_data
1902         EOF
1903
1904         commit refs/notes/foobar
1905         mark :9
1906         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1907         data <<COMMIT
1908         notes (:9)
1909         COMMIT
1910
1911         N :7 :3
1912         N :8 :5
1913         N inline :6
1914         data <<EOF
1915         $note3_data
1916         EOF
1917
1918         commit refs/notes/foobar
1919         mark :10
1920         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1921         data <<COMMIT
1922         notes (:10)
1923         COMMIT
1924
1925         N inline :3
1926         data <<EOF
1927         $note1b_data
1928         EOF
1929
1930         commit refs/notes/foobar2
1931         mark :11
1932         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1933         data <<COMMIT
1934         notes (:11)
1935         COMMIT
1936
1937         N inline :3
1938         data <<EOF
1939         $note1c_data
1940         EOF
1941
1942         commit refs/notes/foobar
1943         mark :12
1944         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1945         data <<COMMIT
1946         notes (:12)
1947         COMMIT
1948
1949         deleteall
1950         N inline :5
1951         data <<EOF
1952         $note2b_data
1953         EOF
1954
1955         INPUT_END
1956
1957         git fast-import <input &&
1958         git whatchanged notes-test
1959 '
1960
1961 test_expect_success 'Q: verify pack' '
1962         verify_packs
1963 '
1964
1965 test_expect_success 'Q: verify first commit' '
1966         commit1=$(git rev-parse notes-test~2) &&
1967         commit2=$(git rev-parse notes-test^) &&
1968         commit3=$(git rev-parse notes-test) &&
1969
1970         cat >expect <<-EOF &&
1971         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1972         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1973
1974         first (:3)
1975         EOF
1976         git cat-file commit notes-test~2 | sed 1d >actual &&
1977         test_cmp expect actual
1978 '
1979
1980 test_expect_success 'Q: verify second commit' '
1981         cat >expect <<-EOF &&
1982         parent $commit1
1983         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1984         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1985
1986         second (:5)
1987         EOF
1988         git cat-file commit notes-test^ | sed 1d >actual &&
1989         test_cmp expect actual
1990 '
1991
1992 test_expect_success 'Q: verify third commit' '
1993         cat >expect <<-EOF &&
1994         parent $commit2
1995         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1996         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1997
1998         third (:6)
1999         EOF
2000         git cat-file commit notes-test | sed 1d >actual &&
2001         test_cmp expect actual
2002 '
2003
2004 test_expect_success 'Q: verify first notes commit' '
2005         cat >expect <<-EOF &&
2006         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2007         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2008
2009         notes (:9)
2010         EOF
2011         git cat-file commit refs/notes/foobar~2 | sed 1d >actual &&
2012         test_cmp expect actual
2013 '
2014
2015 test_expect_success 'Q: verify first notes tree' '
2016         cat >expect.unsorted <<-EOF &&
2017         100644 blob $commit1
2018         100644 blob $commit2
2019         100644 blob $commit3
2020         EOF
2021         cat expect.unsorted | sort >expect &&
2022         git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]*  / /" >actual &&
2023         test_cmp expect actual
2024 '
2025
2026 test_expect_success 'Q: verify first note for first commit' '
2027         echo "$note1_data" >expect &&
2028         git cat-file blob refs/notes/foobar~2:$commit1 >actual &&
2029         test_cmp expect actual
2030 '
2031
2032 test_expect_success 'Q: verify first note for second commit' '
2033         echo "$note2_data" >expect &&
2034         git cat-file blob refs/notes/foobar~2:$commit2 >actual &&
2035         test_cmp expect actual
2036 '
2037
2038 test_expect_success 'Q: verify first note for third commit' '
2039         echo "$note3_data" >expect &&
2040         git cat-file blob refs/notes/foobar~2:$commit3 >actual &&
2041         test_cmp expect actual
2042 '
2043
2044 test_expect_success 'Q: verify second notes commit' '
2045         cat >expect <<-EOF &&
2046         parent $(git rev-parse --verify refs/notes/foobar~2)
2047         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2048         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2049
2050         notes (:10)
2051         EOF
2052         git cat-file commit refs/notes/foobar^ | sed 1d >actual &&
2053         test_cmp expect actual
2054 '
2055
2056 test_expect_success 'Q: verify second notes tree' '
2057         cat >expect.unsorted <<-EOF &&
2058         100644 blob $commit1
2059         100644 blob $commit2
2060         100644 blob $commit3
2061         EOF
2062         cat expect.unsorted | sort >expect &&
2063         git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]*   / /" >actual &&
2064         test_cmp expect actual
2065 '
2066
2067 test_expect_success 'Q: verify second note for first commit' '
2068         echo "$note1b_data" >expect &&
2069         git cat-file blob refs/notes/foobar^:$commit1 >actual &&
2070         test_cmp expect actual
2071 '
2072
2073 test_expect_success 'Q: verify first note for second commit' '
2074         echo "$note2_data" >expect &&
2075         git cat-file blob refs/notes/foobar^:$commit2 >actual &&
2076         test_cmp expect actual
2077 '
2078
2079 test_expect_success 'Q: verify first note for third commit' '
2080         echo "$note3_data" >expect &&
2081         git cat-file blob refs/notes/foobar^:$commit3 >actual &&
2082         test_cmp expect actual
2083 '
2084
2085 test_expect_success 'Q: verify third notes commit' '
2086         cat >expect <<-EOF &&
2087         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2088         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2089
2090         notes (:11)
2091         EOF
2092         git cat-file commit refs/notes/foobar2 | sed 1d >actual &&
2093         test_cmp expect actual
2094 '
2095
2096 test_expect_success 'Q: verify third notes tree' '
2097         cat >expect.unsorted <<-EOF &&
2098         100644 blob $commit1
2099         EOF
2100         cat expect.unsorted | sort >expect &&
2101         git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]*   / /" >actual &&
2102         test_cmp expect actual
2103 '
2104
2105 test_expect_success 'Q: verify third note for first commit' '
2106         echo "$note1c_data" >expect &&
2107         git cat-file blob refs/notes/foobar2:$commit1 >actual &&
2108         test_cmp expect actual
2109 '
2110
2111 test_expect_success 'Q: verify fourth notes commit' '
2112         cat >expect <<-EOF &&
2113         parent $(git rev-parse --verify refs/notes/foobar^)
2114         author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2115         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2116
2117         notes (:12)
2118         EOF
2119         git cat-file commit refs/notes/foobar | sed 1d >actual &&
2120         test_cmp expect actual
2121 '
2122
2123 test_expect_success 'Q: verify fourth notes tree' '
2124         cat >expect.unsorted <<-EOF &&
2125         100644 blob $commit2
2126         EOF
2127         cat expect.unsorted | sort >expect &&
2128         git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]*    / /" >actual &&
2129         test_cmp expect actual
2130 '
2131
2132 test_expect_success 'Q: verify second note for second commit' '
2133         echo "$note2b_data" >expect &&
2134         git cat-file blob refs/notes/foobar:$commit2 >actual &&
2135         test_cmp expect actual
2136 '
2137
2138 test_expect_success 'Q: deny note on empty branch' '
2139         cat >input <<-EOF &&
2140         reset refs/heads/Q0
2141
2142         commit refs/heads/note-Q0
2143         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2144         data <<COMMIT
2145         Note for an empty branch.
2146         COMMIT
2147
2148         N inline refs/heads/Q0
2149         data <<NOTE
2150         some note
2151         NOTE
2152         EOF
2153         test_must_fail git fast-import <input
2154 '
2155 ###
2156 ### series R (feature and option)
2157 ###
2158
2159 test_expect_success 'R: abort on unsupported feature' '
2160         cat >input <<-EOF &&
2161         feature no-such-feature-exists
2162         EOF
2163
2164         test_must_fail git fast-import <input
2165 '
2166
2167 test_expect_success 'R: supported feature is accepted' '
2168         cat >input <<-EOF &&
2169         feature date-format=now
2170         EOF
2171
2172         git fast-import <input
2173 '
2174
2175 test_expect_success 'R: abort on receiving feature after data command' '
2176         cat >input <<-EOF &&
2177         blob
2178         data 3
2179         hi
2180         feature date-format=now
2181         EOF
2182
2183         test_must_fail git fast-import <input
2184 '
2185
2186 test_expect_success 'R: import-marks features forbidden by default' '
2187         >git.marks &&
2188         echo "feature import-marks=git.marks" >input &&
2189         test_must_fail git fast-import <input &&
2190         echo "feature import-marks-if-exists=git.marks" >input &&
2191         test_must_fail git fast-import <input
2192 '
2193
2194 test_expect_success 'R: only one import-marks feature allowed per stream' '
2195         >git.marks &&
2196         >git2.marks &&
2197         cat >input <<-EOF &&
2198         feature import-marks=git.marks
2199         feature import-marks=git2.marks
2200         EOF
2201
2202         test_must_fail git fast-import --allow-unsafe-features <input
2203 '
2204
2205 test_expect_success 'R: export-marks feature forbidden by default' '
2206         echo "feature export-marks=git.marks" >input &&
2207         test_must_fail git fast-import <input
2208 '
2209
2210 test_expect_success 'R: export-marks feature results in a marks file being created' '
2211         cat >input <<-EOF &&
2212         feature export-marks=git.marks
2213         blob
2214         mark :1
2215         data 3
2216         hi
2217
2218         EOF
2219
2220         git fast-import --allow-unsafe-features <input &&
2221         grep :1 git.marks
2222 '
2223
2224 test_expect_success 'R: export-marks options can be overridden by commandline options' '
2225         cat >input <<-\EOF &&
2226         feature export-marks=feature-sub/git.marks
2227         blob
2228         mark :1
2229         data 3
2230         hi
2231
2232         EOF
2233         git fast-import --allow-unsafe-features \
2234                         --export-marks=cmdline-sub/other.marks <input &&
2235         grep :1 cmdline-sub/other.marks &&
2236         test_path_is_missing feature-sub
2237 '
2238
2239 test_expect_success 'R: catch typo in marks file name' '
2240         test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
2241         echo "feature import-marks=nonexistent.marks" |
2242         test_must_fail git fast-import --allow-unsafe-features
2243 '
2244
2245 test_expect_success 'R: import and output marks can be the same file' '
2246         rm -f io.marks &&
2247         blob=$(echo hi | git hash-object --stdin) &&
2248         cat >expect <<-EOF &&
2249         :1 $blob
2250         :2 $blob
2251         EOF
2252         git fast-import --export-marks=io.marks <<-\EOF &&
2253         blob
2254         mark :1
2255         data 3
2256         hi
2257
2258         EOF
2259         git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
2260         blob
2261         mark :2
2262         data 3
2263         hi
2264
2265         EOF
2266         test_cmp expect io.marks
2267 '
2268
2269 test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' '
2270         rm -f io.marks &&
2271         test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF
2272         blob
2273         mark :1
2274         data 3
2275         hi
2276
2277         EOF
2278 '
2279
2280 test_expect_success 'R: --import-marks-if-exists' '
2281         rm -f io.marks &&
2282         blob=$(echo hi | git hash-object --stdin) &&
2283         echo ":1 $blob" >expect &&
2284         git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF &&
2285         blob
2286         mark :1
2287         data 3
2288         hi
2289
2290         EOF
2291         test_cmp expect io.marks
2292 '
2293
2294 test_expect_success 'R: feature import-marks-if-exists' '
2295         rm -f io.marks &&
2296
2297         git fast-import --export-marks=io.marks \
2298                         --allow-unsafe-features <<-\EOF &&
2299         feature import-marks-if-exists=not_io.marks
2300         EOF
2301         test_must_be_empty io.marks &&
2302
2303         blob=$(echo hi | git hash-object --stdin) &&
2304
2305         echo ":1 $blob" >io.marks &&
2306         echo ":1 $blob" >expect &&
2307         echo ":2 $blob" >>expect &&
2308
2309         git fast-import --export-marks=io.marks \
2310                         --allow-unsafe-features <<-\EOF &&
2311         feature import-marks-if-exists=io.marks
2312         blob
2313         mark :2
2314         data 3
2315         hi
2316
2317         EOF
2318         test_cmp expect io.marks &&
2319
2320         echo ":3 $blob" >>expect &&
2321
2322         git fast-import --import-marks=io.marks \
2323                         --export-marks=io.marks \
2324                         --allow-unsafe-features <<-\EOF &&
2325         feature import-marks-if-exists=not_io.marks
2326         blob
2327         mark :3
2328         data 3
2329         hi
2330
2331         EOF
2332         test_cmp expect io.marks &&
2333
2334         git fast-import --import-marks-if-exists=not_io.marks \
2335                         --export-marks=io.marks \
2336                         --allow-unsafe-features <<-\EOF &&
2337         feature import-marks-if-exists=io.marks
2338         EOF
2339         test_must_be_empty io.marks
2340 '
2341
2342 test_expect_success 'R: import to output marks works without any content' '
2343         cat >input <<-EOF &&
2344         feature import-marks=marks.out
2345         feature export-marks=marks.new
2346         EOF
2347
2348         git fast-import --allow-unsafe-features <input &&
2349         test_cmp marks.out marks.new
2350 '
2351
2352 test_expect_success 'R: import marks prefers commandline marks file over the stream' '
2353         cat >input <<-EOF &&
2354         feature import-marks=nonexistent.marks
2355         feature export-marks=marks.new
2356         EOF
2357
2358         git fast-import --import-marks=marks.out --allow-unsafe-features <input &&
2359         test_cmp marks.out marks.new
2360 '
2361
2362
2363 test_expect_success 'R: multiple --import-marks= should be honoured' '
2364         cat >input <<-EOF &&
2365         feature import-marks=nonexistent.marks
2366         feature export-marks=combined.marks
2367         EOF
2368
2369         head -n2 marks.out > one.marks &&
2370         tail -n +3 marks.out > two.marks &&
2371         git fast-import --import-marks=one.marks --import-marks=two.marks \
2372                 --allow-unsafe-features <input &&
2373         test_cmp marks.out combined.marks
2374 '
2375
2376 test_expect_success 'R: feature relative-marks should be honoured' '
2377         cat >input <<-EOF &&
2378         feature relative-marks
2379         feature import-marks=relative.in
2380         feature export-marks=relative.out
2381         EOF
2382
2383         mkdir -p .git/info/fast-import/ &&
2384         cp marks.new .git/info/fast-import/relative.in &&
2385         git fast-import --allow-unsafe-features <input &&
2386         test_cmp marks.new .git/info/fast-import/relative.out
2387 '
2388
2389 test_expect_success 'R: feature no-relative-marks should be honoured' '
2390         cat >input <<-EOF &&
2391         feature relative-marks
2392         feature import-marks=relative.in
2393         feature no-relative-marks
2394         feature export-marks=non-relative.out
2395         EOF
2396
2397         git fast-import --allow-unsafe-features <input &&
2398         test_cmp marks.new non-relative.out
2399 '
2400
2401 test_expect_success 'R: feature ls supported' '
2402         echo "feature ls" |
2403         git fast-import
2404 '
2405
2406 test_expect_success 'R: feature cat-blob supported' '
2407         echo "feature cat-blob" |
2408         git fast-import
2409 '
2410
2411 test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
2412         test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
2413 '
2414
2415 test_expect_success !MINGW 'R: print old blob' '
2416         blob=$(echo "yes it can" | git hash-object -w --stdin) &&
2417         cat >expect <<-EOF &&
2418         ${blob} blob 11
2419         yes it can
2420
2421         EOF
2422         echo "cat-blob $blob" |
2423         git fast-import --cat-blob-fd=6 6>actual &&
2424         test_cmp expect actual
2425 '
2426
2427 test_expect_success !MINGW 'R: in-stream cat-blob-fd not respected' '
2428         echo hello >greeting &&
2429         blob=$(git hash-object -w greeting) &&
2430         cat >expect <<-EOF &&
2431         ${blob} blob 6
2432         hello
2433
2434         EOF
2435         git fast-import --cat-blob-fd=3 3>actual.3 >actual.1 <<-EOF &&
2436         cat-blob $blob
2437         EOF
2438         test_cmp expect actual.3 &&
2439         test_must_be_empty actual.1 &&
2440         git fast-import 3>actual.3 >actual.1 <<-EOF &&
2441         option cat-blob-fd=3
2442         cat-blob $blob
2443         EOF
2444         test_must_be_empty actual.3 &&
2445         test_cmp expect actual.1
2446 '
2447
2448 test_expect_success !MINGW 'R: print mark for new blob' '
2449         echo "effluentish" | git hash-object --stdin >expect &&
2450         git fast-import --cat-blob-fd=6 6>actual <<-\EOF &&
2451         blob
2452         mark :1
2453         data <<BLOB_END
2454         effluentish
2455         BLOB_END
2456         get-mark :1
2457         EOF
2458         test_cmp expect actual
2459 '
2460
2461 test_expect_success !MINGW 'R: print new blob' '
2462         blob=$(echo "yep yep yep" | git hash-object --stdin) &&
2463         cat >expect <<-EOF &&
2464         ${blob} blob 12
2465         yep yep yep
2466
2467         EOF
2468         git fast-import --cat-blob-fd=6 6>actual <<-\EOF &&
2469         blob
2470         mark :1
2471         data <<BLOB_END
2472         yep yep yep
2473         BLOB_END
2474         cat-blob :1
2475         EOF
2476         test_cmp expect actual
2477 '
2478
2479 test_expect_success !MINGW 'R: print new blob by sha1' '
2480         blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
2481         cat >expect <<-EOF &&
2482         ${blob} blob 25
2483         a new blob named by sha1
2484
2485         EOF
2486         git fast-import --cat-blob-fd=6 6>actual <<-EOF &&
2487         blob
2488         data <<BLOB_END
2489         a new blob named by sha1
2490         BLOB_END
2491         cat-blob $blob
2492         EOF
2493         test_cmp expect actual
2494 '
2495
2496 test_expect_success 'setup: big file' '
2497         (
2498                 echo "the quick brown fox jumps over the lazy dog" >big &&
2499                 for i in 1 2 3
2500                 do
2501                         cat big big big big >bigger &&
2502                         cat bigger bigger bigger bigger >big ||
2503                         exit
2504                 done
2505         )
2506 '
2507
2508 test_expect_success 'R: print two blobs to stdout' '
2509         blob1=$(git hash-object big) &&
2510         blob1_len=$(wc -c <big) &&
2511         blob2=$(echo hello | git hash-object --stdin) &&
2512         {
2513                 echo ${blob1} blob $blob1_len &&
2514                 cat big &&
2515                 cat <<-EOF
2516
2517                 ${blob2} blob 6
2518                 hello
2519
2520                 EOF
2521         } >expect &&
2522         {
2523                 cat <<-\END_PART1 &&
2524                         blob
2525                         mark :1
2526                         data <<data_end
2527                 END_PART1
2528                 cat big &&
2529                 cat <<-\EOF
2530                         data_end
2531                         blob
2532                         mark :2
2533                         data <<data_end
2534                         hello
2535                         data_end
2536                         cat-blob :1
2537                         cat-blob :2
2538                 EOF
2539         } |
2540         git fast-import >actual &&
2541         test_cmp expect actual
2542 '
2543
2544 test_expect_success PIPE 'R: copy using cat-file' '
2545         expect_id=$(git hash-object big) &&
2546         expect_len=$(wc -c <big) &&
2547         echo $expect_id blob $expect_len >expect.response &&
2548
2549         rm -f blobs &&
2550
2551         mkfifo blobs &&
2552         (
2553                 export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE &&
2554                 cat <<-\EOF &&
2555                 feature cat-blob
2556                 blob
2557                 mark :1
2558                 data <<BLOB
2559                 EOF
2560                 cat big &&
2561                 cat <<-\EOF &&
2562                 BLOB
2563                 cat-blob :1
2564                 EOF
2565
2566                 read blob_id type size <&3 &&
2567                 echo "$blob_id $type $size" >response &&
2568                 test_copy_bytes $size >blob <&3 &&
2569                 read newline <&3 &&
2570
2571                 cat <<-EOF &&
2572                 commit refs/heads/copied
2573                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2574                 data <<COMMIT
2575                 copy big file as file3
2576                 COMMIT
2577                 M 644 inline file3
2578                 data <<BLOB
2579                 EOF
2580                 cat blob &&
2581                 echo BLOB
2582         ) 3<blobs |
2583         git fast-import --cat-blob-fd=3 3>blobs &&
2584         git show copied:file3 >actual &&
2585         test_cmp expect.response response &&
2586         test_cmp big actual
2587 '
2588
2589 test_expect_success PIPE 'R: print blob mid-commit' '
2590         rm -f blobs &&
2591         echo "A blob from _before_ the commit." >expect &&
2592         mkfifo blobs &&
2593         (
2594                 exec 3<blobs &&
2595                 cat <<-EOF &&
2596                 feature cat-blob
2597                 blob
2598                 mark :1
2599                 data <<BLOB
2600                 A blob from _before_ the commit.
2601                 BLOB
2602                 commit refs/heads/temporary
2603                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2604                 data <<COMMIT
2605                 Empty commit
2606                 COMMIT
2607                 cat-blob :1
2608                 EOF
2609
2610                 read blob_id type size <&3 &&
2611                 test_copy_bytes $size >actual <&3 &&
2612                 read newline <&3 &&
2613
2614                 echo
2615         ) |
2616         git fast-import --cat-blob-fd=3 3>blobs &&
2617         test_cmp expect actual
2618 '
2619
2620 test_expect_success PIPE 'R: print staged blob within commit' '
2621         rm -f blobs &&
2622         echo "A blob from _within_ the commit." >expect &&
2623         mkfifo blobs &&
2624         (
2625                 exec 3<blobs &&
2626                 cat <<-EOF &&
2627                 feature cat-blob
2628                 commit refs/heads/within
2629                 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2630                 data <<COMMIT
2631                 Empty commit
2632                 COMMIT
2633                 M 644 inline within
2634                 data <<BLOB
2635                 A blob from _within_ the commit.
2636                 BLOB
2637                 EOF
2638
2639                 to_get=$(
2640                         echo "A blob from _within_ the commit." |
2641                         git hash-object --stdin
2642                 ) &&
2643                 echo "cat-blob $to_get" &&
2644
2645                 read blob_id type size <&3 &&
2646                 test_copy_bytes $size >actual <&3 &&
2647                 read newline <&3 &&
2648
2649                 echo deleteall
2650         ) |
2651         git fast-import --cat-blob-fd=3 3>blobs &&
2652         test_cmp expect actual
2653 '
2654
2655 test_expect_success 'R: quiet option results in no stats being output' '
2656         cat >input <<-EOF &&
2657         option git quiet
2658         blob
2659         data 3
2660         hi
2661
2662         EOF
2663
2664         git fast-import 2>output <input &&
2665         test_must_be_empty output
2666 '
2667
2668 test_expect_success 'R: feature done means terminating "done" is mandatory' '
2669         echo feature done | test_must_fail git fast-import &&
2670         test_must_fail git fast-import --done </dev/null
2671 '
2672
2673 test_expect_success 'R: terminating "done" with trailing gibberish is ok' '
2674         git fast-import <<-\EOF &&
2675         feature done
2676         done
2677         trailing gibberish
2678         EOF
2679         git fast-import <<-\EOF
2680         done
2681         more trailing gibberish
2682         EOF
2683 '
2684
2685 test_expect_success 'R: terminating "done" within commit' '
2686         cat >expect <<-\EOF &&
2687         OBJID
2688         :000000 100644 OBJID OBJID A    hello.c
2689         :000000 100644 OBJID OBJID A    hello2.c
2690         EOF
2691         git fast-import <<-EOF &&
2692         commit refs/heads/done-ends
2693         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2694         data <<EOT
2695         Commit terminated by "done" command
2696         EOT
2697         M 100644 inline hello.c
2698         data <<EOT
2699         Hello, world.
2700         EOT
2701         C hello.c hello2.c
2702         done
2703         EOF
2704         git rev-list done-ends |
2705         git diff-tree -r --stdin --root --always |
2706         sed -e "s/$OID_REGEX/OBJID/g" >actual &&
2707         test_cmp expect actual
2708 '
2709
2710 test_expect_success 'R: die on unknown option' '
2711         cat >input <<-EOF &&
2712         option git non-existing-option
2713         EOF
2714
2715         test_must_fail git fast-import <input
2716 '
2717
2718 test_expect_success 'R: unknown commandline options are rejected' '\
2719         test_must_fail git fast-import --non-existing-option < /dev/null
2720 '
2721
2722 test_expect_success 'R: die on invalid option argument' '
2723         echo "option git active-branches=-5" |
2724         test_must_fail git fast-import &&
2725         echo "option git depth=" |
2726         test_must_fail git fast-import &&
2727         test_must_fail git fast-import --depth="5 elephants" </dev/null
2728 '
2729
2730 test_expect_success 'R: ignore non-git options' '
2731         cat >input <<-EOF &&
2732         option non-existing-vcs non-existing-option
2733         EOF
2734
2735         git fast-import <input
2736 '
2737
2738 test_expect_success 'R: corrupt lines do not mess marks file' '
2739         rm -f io.marks &&
2740         blob=$(echo hi | git hash-object --stdin) &&
2741         cat >expect <<-EOF &&
2742         :3 $ZERO_OID
2743         :1 $blob
2744         :2 $blob
2745         EOF
2746         cp expect io.marks &&
2747         test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
2748
2749         EOF
2750         test_cmp expect io.marks
2751 '
2752
2753 ##
2754 ## R: very large blobs
2755 ##
2756 test_expect_success 'R: blob bigger than threshold' '
2757         blobsize=$((2*1024*1024 + 53)) &&
2758         test-tool genrandom bar $blobsize >expect &&
2759         cat >input <<-INPUT_END &&
2760         commit refs/heads/big-file
2761         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2762         data <<COMMIT
2763         R - big file
2764         COMMIT
2765
2766         M 644 inline big1
2767         data $blobsize
2768         INPUT_END
2769         cat expect >>input &&
2770         cat >>input <<-INPUT_END &&
2771         M 644 inline big2
2772         data $blobsize
2773         INPUT_END
2774         cat expect >>input &&
2775         echo >>input &&
2776
2777         test_create_repo R &&
2778         git --git-dir=R/.git config fastimport.unpackLimit 0 &&
2779         git --git-dir=R/.git fast-import --big-file-threshold=1 <input
2780 '
2781
2782 test_expect_success 'R: verify created pack' '
2783         (
2784                 cd R &&
2785                 verify_packs -v > ../verify
2786         )
2787 '
2788
2789 test_expect_success 'R: verify written objects' '
2790         git --git-dir=R/.git cat-file blob big-file:big1 >actual &&
2791         test_cmp_bin expect actual &&
2792         a=$(git --git-dir=R/.git rev-parse big-file:big1) &&
2793         b=$(git --git-dir=R/.git rev-parse big-file:big2) &&
2794         test $a = $b
2795 '
2796
2797 test_expect_success 'R: blob appears only once' '
2798         n=$(grep $a verify | wc -l) &&
2799         test 1 = $n
2800 '
2801
2802 ###
2803 ### series S
2804 ###
2805 #
2806 # Make sure missing spaces and EOLs after mark references
2807 # cause errors.
2808 #
2809 # Setup:
2810 #
2811 #   1--2--4
2812 #    \   /
2813 #     -3-
2814 #
2815 #   commit marks:  301, 302, 303, 304
2816 #   blob marks:              403, 404, resp.
2817 #   note mark:          202
2818 #
2819 # The error message when a space is missing not at the
2820 # end of the line is:
2821 #
2822 #   Missing space after ..
2823 #
2824 # or when extra characters come after the mark at the end
2825 # of the line:
2826 #
2827 #   Garbage after ..
2828 #
2829 # or when the dataref is neither "inline " or a known SHA1,
2830 #
2831 #   Invalid dataref ..
2832 #
2833 test_expect_success 'S: initialize for S tests' '
2834         test_tick &&
2835
2836         cat >input <<-INPUT_END &&
2837         commit refs/heads/S
2838         mark :301
2839         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2840         data <<COMMIT
2841         commit 1
2842         COMMIT
2843         M 100644 inline hello.c
2844         data <<BLOB
2845         blob 1
2846         BLOB
2847
2848         commit refs/heads/S
2849         mark :302
2850         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2851         data <<COMMIT
2852         commit 2
2853         COMMIT
2854         from :301
2855         M 100644 inline hello.c
2856         data <<BLOB
2857         blob 2
2858         BLOB
2859
2860         blob
2861         mark :403
2862         data <<BLOB
2863         blob 3
2864         BLOB
2865
2866         blob
2867         mark :202
2868         data <<BLOB
2869         note 2
2870         BLOB
2871         INPUT_END
2872
2873         git fast-import --export-marks=marks <input
2874 '
2875
2876 #
2877 # filemodify, three datarefs
2878 #
2879 test_expect_success 'S: filemodify with garbage after mark must fail' '
2880         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2881         commit refs/heads/S
2882         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2883         data <<COMMIT
2884         commit N
2885         COMMIT
2886         M 100644 :403x hello.c
2887         EOF
2888         test_i18ngrep "space after mark" err
2889 '
2890
2891 # inline is misspelled; fast-import thinks it is some unknown dataref
2892 test_expect_success 'S: filemodify with garbage after inline must fail' '
2893         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2894         commit refs/heads/S
2895         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2896         data <<COMMIT
2897         commit N
2898         COMMIT
2899         M 100644 inlineX hello.c
2900         data <<BLOB
2901         inline
2902         BLOB
2903         EOF
2904         test_i18ngrep "nvalid dataref" err
2905 '
2906
2907 test_expect_success 'S: filemodify with garbage after sha1 must fail' '
2908         sha1=$(grep :403 marks | cut -d\  -f2) &&
2909         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2910         commit refs/heads/S
2911         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2912         data <<COMMIT
2913         commit N
2914         COMMIT
2915         M 100644 ${sha1}x hello.c
2916         EOF
2917         test_i18ngrep "space after SHA1" err
2918 '
2919
2920 #
2921 # notemodify, three ways to say dataref
2922 #
2923 test_expect_success 'S: notemodify with garbage after mark dataref must fail' '
2924         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2925         commit refs/heads/S
2926         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2927         data <<COMMIT
2928         commit S note dataref markref
2929         COMMIT
2930         N :202x :302
2931         EOF
2932         test_i18ngrep "space after mark" err
2933 '
2934
2935 test_expect_success 'S: notemodify with garbage after inline dataref must fail' '
2936         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2937         commit refs/heads/S
2938         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2939         data <<COMMIT
2940         commit S note dataref inline
2941         COMMIT
2942         N inlineX :302
2943         data <<BLOB
2944         note blob
2945         BLOB
2946         EOF
2947         test_i18ngrep "nvalid dataref" err
2948 '
2949
2950 test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
2951         sha1=$(grep :202 marks | cut -d\  -f2) &&
2952         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2953         commit refs/heads/S
2954         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2955         data <<COMMIT
2956         commit S note dataref sha1
2957         COMMIT
2958         N ${sha1}x :302
2959         EOF
2960         test_i18ngrep "space after SHA1" err
2961 '
2962
2963 #
2964 # notemodify, mark in commit-ish
2965 #
2966 test_expect_success 'S: notemodify with garbage after mark commit-ish must fail' '
2967         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
2968         commit refs/heads/Snotes
2969         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2970         data <<COMMIT
2971         commit S note commit-ish
2972         COMMIT
2973         N :202 :302x
2974         EOF
2975         test_i18ngrep "after mark" err
2976 '
2977
2978 #
2979 # from
2980 #
2981 test_expect_success 'S: from with garbage after mark must fail' '
2982         test_must_fail \
2983         git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err &&
2984         commit refs/heads/S2
2985         mark :303
2986         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2987         data <<COMMIT
2988         commit 3
2989         COMMIT
2990         from :301x
2991         M 100644 :403 hello.c
2992         EOF
2993
2994
2995         # go create the commit, need it for merge test
2996         git fast-import --import-marks=marks --export-marks=marks <<-EOF &&
2997         commit refs/heads/S2
2998         mark :303
2999         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3000         data <<COMMIT
3001         commit 3
3002         COMMIT
3003         from :301
3004         M 100644 :403 hello.c
3005         EOF
3006
3007         # now evaluate the error
3008         test_i18ngrep "after mark" err
3009 '
3010
3011
3012 #
3013 # merge
3014 #
3015 test_expect_success 'S: merge with garbage after mark must fail' '
3016         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3017         commit refs/heads/S
3018         mark :304
3019         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3020         data <<COMMIT
3021         merge 4
3022         COMMIT
3023         from :302
3024         merge :303x
3025         M 100644 :403 hello.c
3026         EOF
3027         test_i18ngrep "after mark" err
3028 '
3029
3030 #
3031 # tag, from markref
3032 #
3033 test_expect_success 'S: tag with garbage after mark must fail' '
3034         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3035         tag refs/tags/Stag
3036         from :302x
3037         tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3038         data <<TAG
3039         tag S
3040         TAG
3041         EOF
3042         test_i18ngrep "after mark" err
3043 '
3044
3045 #
3046 # cat-blob markref
3047 #
3048 test_expect_success 'S: cat-blob with garbage after mark must fail' '
3049         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3050         cat-blob :403x
3051         EOF
3052         test_i18ngrep "after mark" err
3053 '
3054
3055 #
3056 # ls markref
3057 #
3058 test_expect_success 'S: ls with garbage after mark must fail' '
3059         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3060         ls :302x hello.c
3061         EOF
3062         test_i18ngrep "space after mark" err
3063 '
3064
3065 test_expect_success 'S: ls with garbage after sha1 must fail' '
3066         sha1=$(grep :302 marks | cut -d\  -f2) &&
3067         test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
3068         ls ${sha1}x hello.c
3069         EOF
3070         test_i18ngrep "space after tree-ish" err
3071 '
3072
3073 ###
3074 ### series T (ls)
3075 ###
3076 # Setup is carried over from series S.
3077
3078 test_expect_success 'T: ls root tree' '
3079         sed -e "s/Z\$//" >expect <<-EOF &&
3080         040000 tree $(git rev-parse S^{tree})   Z
3081         EOF
3082         sha1=$(git rev-parse --verify S) &&
3083         git fast-import --import-marks=marks <<-EOF >actual &&
3084         ls $sha1 ""
3085         EOF
3086         test_cmp expect actual
3087 '
3088
3089 test_expect_success 'T: delete branch' '
3090         git branch to-delete &&
3091         git fast-import <<-EOF &&
3092         reset refs/heads/to-delete
3093         from $ZERO_OID
3094         EOF
3095         test_must_fail git rev-parse --verify refs/heads/to-delete
3096 '
3097
3098 test_expect_success 'T: empty reset doesnt delete branch' '
3099         git branch not-to-delete &&
3100         git fast-import <<-EOF &&
3101         reset refs/heads/not-to-delete
3102         EOF
3103         git show-ref &&
3104         git rev-parse --verify refs/heads/not-to-delete
3105 '
3106
3107 ###
3108 ### series U (filedelete)
3109 ###
3110
3111 test_expect_success 'U: initialize for U tests' '
3112         cat >input <<-INPUT_END &&
3113         commit refs/heads/U
3114         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3115         data <<COMMIT
3116         test setup
3117         COMMIT
3118         M 100644 inline hello.c
3119         data <<BLOB
3120         blob 1
3121         BLOB
3122         M 100644 inline good/night.txt
3123         data <<BLOB
3124         sleep well
3125         BLOB
3126         M 100644 inline good/bye.txt
3127         data <<BLOB
3128         au revoir
3129         BLOB
3130
3131         INPUT_END
3132
3133         f7id=$(echo "blob 1" | git hash-object --stdin) &&
3134         f8id=$(echo "sleep well" | git hash-object --stdin) &&
3135         f9id=$(echo "au revoir" | git hash-object --stdin) &&
3136         git fast-import <input
3137 '
3138
3139 test_expect_success 'U: filedelete file succeeds' '
3140         cat >input <<-INPUT_END &&
3141         commit refs/heads/U
3142         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3143         data <<COMMIT
3144         delete good/night.txt
3145         COMMIT
3146         from refs/heads/U^0
3147         D good/night.txt
3148
3149         INPUT_END
3150
3151         git fast-import <input
3152 '
3153
3154 test_expect_success 'U: validate file delete result' '
3155         cat >expect <<-EOF &&
3156         :100644 000000 $f8id $ZERO_OID D        good/night.txt
3157         EOF
3158
3159         git diff-tree -M -r U^1 U >actual &&
3160
3161         compare_diff_raw expect actual
3162 '
3163
3164 test_expect_success 'U: filedelete directory succeeds' '
3165         cat >input <<-INPUT_END &&
3166         commit refs/heads/U
3167         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3168         data <<COMMIT
3169         delete good dir
3170         COMMIT
3171         from refs/heads/U^0
3172         D good
3173
3174         INPUT_END
3175
3176         git fast-import <input
3177 '
3178
3179 test_expect_success 'U: validate directory delete result' '
3180         cat >expect <<-EOF &&
3181         :100644 000000 $f9id $ZERO_OID D        good/bye.txt
3182         EOF
3183
3184         git diff-tree -M -r U^1 U >actual &&
3185
3186         compare_diff_raw expect actual
3187 '
3188
3189 test_expect_success 'U: filedelete root succeeds' '
3190         cat >input <<-INPUT_END &&
3191         commit refs/heads/U
3192         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3193         data <<COMMIT
3194         must succeed
3195         COMMIT
3196         from refs/heads/U^0
3197         D ""
3198
3199         INPUT_END
3200
3201         git fast-import <input
3202 '
3203
3204 test_expect_success 'U: validate root delete result' '
3205         cat >expect <<-EOF &&
3206         :100644 000000 $f7id $ZERO_OID D        hello.c
3207         EOF
3208
3209         git diff-tree -M -r U^1 U >actual &&
3210
3211         compare_diff_raw expect actual
3212 '
3213
3214 ###
3215 ### series V (checkpoint)
3216 ###
3217
3218 # The commands in input_file should not produce any output on the file
3219 # descriptor set with --cat-blob-fd (or stdout if unspecified).
3220 #
3221 # To make sure you're observing the side effects of checkpoint *before*
3222 # fast-import terminates (and thus writes out its state), check that the
3223 # fast-import process is still running using background_import_still_running
3224 # *after* evaluating the test conditions.
3225 background_import_then_checkpoint () {
3226         options=$1
3227         input_file=$2
3228
3229         mkfifo V.input
3230         exec 8<>V.input
3231         rm V.input
3232
3233         mkfifo V.output
3234         exec 9<>V.output
3235         rm V.output
3236
3237         (
3238                 git fast-import $options <&8 >&9 &
3239                 echo $! >&9
3240                 wait $!
3241                 echo >&2 "background fast-import terminated too early with exit code $?"
3242                 # Un-block the read loop in the main shell process.
3243                 echo >&9 UNEXPECTED
3244         ) &
3245         sh_pid=$!
3246         read fi_pid <&9
3247         # We don't mind if fast-import has already died by the time the test
3248         # ends.
3249         test_when_finished "
3250                 exec 8>&-; exec 9>&-;
3251                 kill $sh_pid && wait $sh_pid
3252                 kill $fi_pid && wait $fi_pid
3253                 true"
3254
3255         # Start in the background to ensure we adhere strictly to (blocking)
3256         # pipes writing sequence. We want to assume that the write below could
3257         # block, e.g. if fast-import blocks writing its own output to &9
3258         # because there is no reader on &9 yet.
3259         (
3260                 cat "$input_file"
3261                 echo "checkpoint"
3262                 echo "progress checkpoint"
3263         ) >&8 &
3264
3265         error=1 ;# assume the worst
3266         while read output <&9
3267         do
3268                 if test "$output" = "progress checkpoint"
3269                 then
3270                         error=0
3271                         break
3272                 elif test "$output" = "UNEXPECTED"
3273                 then
3274                         break
3275                 fi
3276                 # otherwise ignore cruft
3277                 echo >&2 "cruft: $output"
3278         done
3279
3280         if test $error -eq 1
3281         then
3282                 false
3283         fi
3284 }
3285
3286 background_import_still_running () {
3287         if ! kill -0 "$fi_pid"
3288         then
3289                 echo >&2 "background fast-import terminated too early"
3290                 false
3291         fi
3292 }
3293
3294 test_expect_success PIPE 'V: checkpoint helper does not get stuck with extra output' '
3295         cat >input <<-INPUT_END &&
3296         progress foo
3297         progress bar
3298
3299         INPUT_END
3300
3301         background_import_then_checkpoint "" input &&
3302         background_import_still_running
3303 '
3304
3305 test_expect_success PIPE 'V: checkpoint updates refs after reset' '
3306         cat >input <<-\INPUT_END &&
3307         reset refs/heads/V
3308         from refs/heads/U
3309
3310         INPUT_END
3311
3312         background_import_then_checkpoint "" input &&
3313         test "$(git rev-parse --verify V)" = "$(git rev-parse --verify U)" &&
3314         background_import_still_running
3315 '
3316
3317 test_expect_success PIPE 'V: checkpoint updates refs and marks after commit' '
3318         cat >input <<-INPUT_END &&
3319         commit refs/heads/V
3320         mark :1
3321         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3322         data 0
3323         from refs/heads/U
3324
3325         INPUT_END
3326
3327         background_import_then_checkpoint "--export-marks=marks.actual" input &&
3328
3329         echo ":1 $(git rev-parse --verify V)" >marks.expected &&
3330
3331         test "$(git rev-parse --verify V^)" = "$(git rev-parse --verify U)" &&
3332         test_cmp marks.expected marks.actual &&
3333         background_import_still_running
3334 '
3335
3336 # Re-create the exact same commit, but on a different branch: no new object is
3337 # created in the database, but the refs and marks still need to be updated.
3338 test_expect_success PIPE 'V: checkpoint updates refs and marks after commit (no new objects)' '
3339         cat >input <<-INPUT_END &&
3340         commit refs/heads/V2
3341         mark :2
3342         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3343         data 0
3344         from refs/heads/U
3345
3346         INPUT_END
3347
3348         background_import_then_checkpoint "--export-marks=marks.actual" input &&
3349
3350         echo ":2 $(git rev-parse --verify V2)" >marks.expected &&
3351
3352         test "$(git rev-parse --verify V2)" = "$(git rev-parse --verify V)" &&
3353         test_cmp marks.expected marks.actual &&
3354         background_import_still_running
3355 '
3356
3357 test_expect_success PIPE 'V: checkpoint updates tags after tag' '
3358         cat >input <<-INPUT_END &&
3359         tag Vtag
3360         from refs/heads/V
3361         tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3362         data 0
3363
3364         INPUT_END
3365
3366         background_import_then_checkpoint "" input &&
3367         git show-ref -d Vtag &&
3368         background_import_still_running
3369 '
3370
3371 ###
3372 ### series W (get-mark and empty orphan commits)
3373 ###
3374
3375 cat >>W-input <<-W_INPUT_END
3376         commit refs/heads/W-branch
3377         mark :1
3378         author Full Name <user@company.tld> 1000000000 +0100
3379         committer Full Name <user@company.tld> 1000000000 +0100
3380         data 27
3381         Intentionally empty commit
3382         LFsget-mark :1
3383         W_INPUT_END
3384
3385 test_expect_success !MINGW 'W: get-mark & empty orphan commit with no newlines' '
3386         sed -e s/LFs// W-input | tr L "\n" | git fast-import
3387 '
3388
3389 test_expect_success !MINGW 'W: get-mark & empty orphan commit with one newline' '
3390         sed -e s/LFs/L/ W-input | tr L "\n" | git fast-import
3391 '
3392
3393 test_expect_success !MINGW 'W: get-mark & empty orphan commit with ugly second newline' '
3394         # Technically, this should fail as it has too many linefeeds
3395         # according to the grammar in fast-import.txt.  But, for whatever
3396         # reason, it works.  Since using the correct number of newlines
3397         # does not work with older (pre-2.22) versions of git, allow apps
3398         # that used this second-newline workaround to keep working by
3399         # checking it with this test...
3400         sed -e s/LFs/LL/ W-input | tr L "\n" | git fast-import
3401 '
3402
3403 test_expect_success !MINGW 'W: get-mark & empty orphan commit with erroneous third newline' '
3404         # ...but do NOT allow more empty lines than that (see previous test).
3405         sed -e s/LFs/LLL/ W-input | tr L "\n" | test_must_fail git fast-import
3406 '
3407
3408 ###
3409 ### series X (other new features)
3410 ###
3411
3412 test_expect_success 'X: handling encoding' '
3413         test_tick &&
3414         cat >input <<-INPUT_END &&
3415         commit refs/heads/encoding
3416         committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
3417         encoding iso-8859-7
3418         data <<COMMIT
3419         INPUT_END
3420
3421         printf "Pi: \360\nCOMMIT\n" >>input &&
3422
3423         git fast-import <input &&
3424         git cat-file -p encoding | grep $(printf "\360") &&
3425         git log -1 --format=%B encoding | grep $(printf "\317\200")
3426 '
3427
3428 ###
3429 ### series Y (submodules and hash algorithms)
3430 ###
3431
3432 cat >Y-sub-input <<\Y_INPUT_END
3433 blob
3434 mark :1
3435 data 4
3436 foo
3437
3438 reset refs/heads/main
3439 commit refs/heads/main
3440 mark :2
3441 author Full Name <user@company.tld> 1000000000 +0100
3442 committer Full Name <user@company.tld> 1000000000 +0100
3443 data 24
3444 Test submodule commit 1
3445 M 100644 :1 file
3446
3447 blob
3448 mark :3
3449 data 8
3450 foo
3451 bar
3452
3453 commit refs/heads/main
3454 mark :4
3455 author Full Name <user@company.tld> 1000000001 +0100
3456 committer Full Name <user@company.tld> 1000000001 +0100
3457 data 24
3458 Test submodule commit 2
3459 from :2
3460 M 100644 :3 file
3461 Y_INPUT_END
3462
3463 # Note that the submodule object IDs are intentionally not translated.
3464 cat >Y-main-input <<\Y_INPUT_END
3465 blob
3466 mark :1
3467 data 4
3468 foo
3469
3470 reset refs/heads/main
3471 commit refs/heads/main
3472 mark :2
3473 author Full Name <user@company.tld> 2000000000 +0100
3474 committer Full Name <user@company.tld> 2000000000 +0100
3475 data 14
3476 Test commit 1
3477 M 100644 :1 file
3478
3479 blob
3480 mark :3
3481 data 73
3482 [submodule "sub1"]
3483         path = sub1
3484         url = https://void.example.com/main.git
3485
3486 commit refs/heads/main
3487 mark :4
3488 author Full Name <user@company.tld> 2000000001 +0100
3489 committer Full Name <user@company.tld> 2000000001 +0100
3490 data 14
3491 Test commit 2
3492 from :2
3493 M 100644 :3 .gitmodules
3494 M 160000 0712c5be7cf681388e355ef47525aaf23aee1a6d sub1
3495
3496 blob
3497 mark :5
3498 data 8
3499 foo
3500 bar
3501
3502 commit refs/heads/main
3503 mark :6
3504 author Full Name <user@company.tld> 2000000002 +0100
3505 committer Full Name <user@company.tld> 2000000002 +0100
3506 data 14
3507 Test commit 3
3508 from :4
3509 M 100644 :5 file
3510 M 160000 ff729f5e62f72c0c3978207d9a80e5f3a65f14d7 sub1
3511 Y_INPUT_END
3512
3513 cat >Y-marks <<\Y_INPUT_END
3514 :2 0712c5be7cf681388e355ef47525aaf23aee1a6d
3515 :4 ff729f5e62f72c0c3978207d9a80e5f3a65f14d7
3516 Y_INPUT_END
3517
3518 test_expect_success 'Y: setup' '
3519         test_oid_cache <<-EOF
3520         Ymain sha1:9afed2f9161ddf416c0a1863b8b0725b00070504
3521         Ymain sha256:c0a1010da1df187b2e287654793df01b464bd6f8e3f17fc1481a7dadf84caee3
3522         EOF
3523 '
3524
3525 test_expect_success 'Y: rewrite submodules' '
3526         git init main1 &&
3527         (
3528                 cd main1 &&
3529                 git init sub2 &&
3530                 git -C sub2 fast-import --export-marks=../sub2-marks <../Y-sub-input &&
3531                 git fast-import --rewrite-submodules-from=sub:../Y-marks \
3532                         --rewrite-submodules-to=sub:sub2-marks <../Y-main-input &&
3533                 test "$(git rev-parse main)" = "$(test_oid Ymain)"
3534         )
3535 '
3536
3537 test_done