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