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