Merge branch 'bc/utf16-portability-fix'
[git] / t / t9350-fast-export.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Johannes E. Schindelin
4 #
5
6 test_description='git fast-export'
7 . ./test-lib.sh
8
9 test_expect_success 'setup' '
10
11         echo break it > file0 &&
12         git add file0 &&
13         test_tick &&
14         echo Wohlauf > file &&
15         git add file &&
16         test_tick &&
17         git commit -m initial &&
18         echo die Luft > file &&
19         echo geht frisch > file2 &&
20         git add file file2 &&
21         test_tick &&
22         git commit -m second &&
23         echo und > file2 &&
24         test_tick &&
25         git commit -m third file2 &&
26         test_tick &&
27         git tag rein &&
28         git checkout -b wer HEAD^ &&
29         echo lange > file2 &&
30         test_tick &&
31         git commit -m sitzt file2 &&
32         test_tick &&
33         git tag -a -m valentin muss &&
34         git merge -s ours master
35
36 '
37
38 test_expect_success 'fast-export | fast-import' '
39
40         MASTER=$(git rev-parse --verify master) &&
41         REIN=$(git rev-parse --verify rein) &&
42         WER=$(git rev-parse --verify wer) &&
43         MUSS=$(git rev-parse --verify muss) &&
44         mkdir new &&
45         git --git-dir=new/.git init &&
46         git fast-export --all >actual &&
47         (cd new &&
48          git fast-import &&
49          test $MASTER = $(git rev-parse --verify refs/heads/master) &&
50          test $REIN = $(git rev-parse --verify refs/tags/rein) &&
51          test $WER = $(git rev-parse --verify refs/heads/wer) &&
52          test $MUSS = $(git rev-parse --verify refs/tags/muss)) <actual
53
54 '
55
56 test_expect_success 'fast-export master~2..master' '
57
58         git fast-export master~2..master >actual &&
59         sed "s/master/partial/" actual |
60                 (cd new &&
61                  git fast-import &&
62                  test $MASTER != $(git rev-parse --verify refs/heads/partial) &&
63                  git diff --exit-code master partial &&
64                  git diff --exit-code master^ partial^ &&
65                  test_must_fail git rev-parse partial~2)
66
67 '
68
69 test_expect_success 'fast-export --reference-excluded-parents master~2..master' '
70
71         git fast-export --reference-excluded-parents master~2..master >actual &&
72         grep commit.refs/heads/master actual >commit-count &&
73         test_line_count = 2 commit-count &&
74         sed "s/master/rewrite/" actual |
75                 (cd new &&
76                  git fast-import &&
77                  test $MASTER = $(git rev-parse --verify refs/heads/rewrite))
78 '
79
80 test_expect_success 'fast-export --show-original-ids' '
81
82         git fast-export --show-original-ids master >output &&
83         grep ^original-oid output| sed -e s/^original-oid.// | sort >actual &&
84         git rev-list --objects master muss >objects-and-names &&
85         awk "{print \$1}" objects-and-names | sort >commits-trees-blobs &&
86         comm -23 actual commits-trees-blobs >unfound &&
87         test_must_be_empty unfound
88 '
89
90 test_expect_success 'fast-export --show-original-ids | git fast-import' '
91
92         git fast-export --show-original-ids master muss | git fast-import --quiet &&
93         test $MASTER = $(git rev-parse --verify refs/heads/master) &&
94         test $MUSS = $(git rev-parse --verify refs/tags/muss)
95 '
96
97 test_expect_success 'iso-8859-1' '
98
99         git config i18n.commitencoding ISO8859-1 &&
100         # use author and committer name in ISO-8859-1 to match it.
101         . "$TEST_DIRECTORY"/t3901/8859-1.txt &&
102         test_tick &&
103         echo rosten >file &&
104         git commit -s -m den file &&
105         git fast-export wer^..wer >iso8859-1.fi &&
106         sed "s/wer/i18n/" iso8859-1.fi |
107                 (cd new &&
108                  git fast-import &&
109                  git cat-file commit i18n >actual &&
110                  grep "Áéí óú" actual)
111
112 '
113 test_expect_success 'import/export-marks' '
114
115         git checkout -b marks master &&
116         git fast-export --export-marks=tmp-marks HEAD &&
117         test -s tmp-marks &&
118         test_line_count = 3 tmp-marks &&
119         git fast-export --import-marks=tmp-marks \
120                 --export-marks=tmp-marks HEAD >actual &&
121         test $(grep ^commit actual | wc -l) -eq 0 &&
122         echo change > file &&
123         git commit -m "last commit" file &&
124         git fast-export --import-marks=tmp-marks \
125                 --export-marks=tmp-marks HEAD >actual &&
126         test $(grep ^commit\  actual | wc -l) -eq 1 &&
127         test_line_count = 4 tmp-marks
128
129 '
130
131 cat > signed-tag-import << EOF
132 tag sign-your-name
133 from $(git rev-parse HEAD)
134 tagger C O Mitter <committer@example.com> 1112911993 -0700
135 data 210
136 A message for a sign
137 -----BEGIN PGP SIGNATURE-----
138 Version: GnuPG v1.4.5 (GNU/Linux)
139
140 fakedsignaturefakedsignaturefakedsignaturefakedsignaturfakedsign
141 aturefakedsignaturefake=
142 =/59v
143 -----END PGP SIGNATURE-----
144 EOF
145
146 test_expect_success 'set up faked signed tag' '
147
148         cat signed-tag-import | git fast-import
149
150 '
151
152 test_expect_success 'signed-tags=abort' '
153
154         test_must_fail git fast-export --signed-tags=abort sign-your-name
155
156 '
157
158 test_expect_success 'signed-tags=verbatim' '
159
160         git fast-export --signed-tags=verbatim sign-your-name > output &&
161         grep PGP output
162
163 '
164
165 test_expect_success 'signed-tags=strip' '
166
167         git fast-export --signed-tags=strip sign-your-name > output &&
168         ! grep PGP output
169
170 '
171
172 test_expect_success 'signed-tags=warn-strip' '
173         git fast-export --signed-tags=warn-strip sign-your-name >output 2>err &&
174         ! grep PGP output &&
175         test -s err
176 '
177
178 test_expect_success 'setup submodule' '
179
180         git checkout -f master &&
181         mkdir sub &&
182         (
183                 cd sub &&
184                 git init  &&
185                 echo test file > file &&
186                 git add file &&
187                 git commit -m sub_initial
188         ) &&
189         git submodule add "$(pwd)/sub" sub &&
190         git commit -m initial &&
191         test_tick &&
192         (
193                 cd sub &&
194                 echo more data >> file &&
195                 git add file &&
196                 git commit -m sub_second
197         ) &&
198         git add sub &&
199         git commit -m second
200
201 '
202
203 test_expect_success 'submodule fast-export | fast-import' '
204
205         SUBENT1=$(git ls-tree master^ sub) &&
206         SUBENT2=$(git ls-tree master sub) &&
207         rm -rf new &&
208         mkdir new &&
209         git --git-dir=new/.git init &&
210         git fast-export --signed-tags=strip --all >actual &&
211         (cd new &&
212          git fast-import &&
213          test "$SUBENT1" = "$(git ls-tree refs/heads/master^ sub)" &&
214          test "$SUBENT2" = "$(git ls-tree refs/heads/master sub)" &&
215          git checkout master &&
216          git submodule init &&
217          git submodule update &&
218          cmp sub/file ../sub/file) <actual
219
220 '
221
222 GIT_AUTHOR_NAME='A U Thor'; export GIT_AUTHOR_NAME
223 GIT_COMMITTER_NAME='C O Mitter'; export GIT_COMMITTER_NAME
224
225 test_expect_success 'setup copies' '
226
227         git config --unset i18n.commitencoding &&
228         git checkout -b copy rein &&
229         git mv file file3 &&
230         git commit -m move1 &&
231         test_tick &&
232         cp file2 file4 &&
233         git add file4 &&
234         git mv file2 file5 &&
235         git commit -m copy1 &&
236         test_tick &&
237         cp file3 file6 &&
238         git add file6 &&
239         git commit -m copy2 &&
240         test_tick &&
241         echo more text >> file6 &&
242         echo even more text >> file6 &&
243         git add file6 &&
244         git commit -m modify &&
245         test_tick &&
246         cp file6 file7 &&
247         echo test >> file7 &&
248         git add file7 &&
249         git commit -m copy_modify
250
251 '
252
253 test_expect_success 'fast-export -C -C | fast-import' '
254
255         ENTRY=$(git rev-parse --verify copy) &&
256         rm -rf new &&
257         mkdir new &&
258         git --git-dir=new/.git init &&
259         git fast-export -C -C --signed-tags=strip --all > output &&
260         grep "^C file2 file4\$" output &&
261         cat output |
262         (cd new &&
263          git fast-import &&
264          test $ENTRY = $(git rev-parse --verify refs/heads/copy))
265
266 '
267
268 test_expect_success 'fast-export | fast-import when master is tagged' '
269
270         git tag -m msg last &&
271         git fast-export -C -C --signed-tags=strip --all > output &&
272         test $(grep -c "^tag " output) = 3
273
274 '
275
276 cat > tag-content << EOF
277 object $(git rev-parse HEAD)
278 type commit
279 tag rosten
280 EOF
281
282 test_expect_success 'cope with tagger-less tags' '
283
284         TAG=$(git hash-object -t tag -w tag-content) &&
285         git update-ref refs/tags/sonnenschein $TAG &&
286         git fast-export -C -C --signed-tags=strip --all > output &&
287         test $(grep -c "^tag " output) = 4 &&
288         ! grep "Unspecified Tagger" output &&
289         git fast-export -C -C --signed-tags=strip --all \
290                 --fake-missing-tagger > output &&
291         test $(grep -c "^tag " output) = 4 &&
292         grep "Unspecified Tagger" output
293
294 '
295
296 test_expect_success 'setup for limiting exports by PATH' '
297         mkdir limit-by-paths &&
298         (
299                 cd limit-by-paths &&
300                 git init &&
301                 echo hi > there &&
302                 git add there &&
303                 git commit -m "First file" &&
304                 echo foo > bar &&
305                 git add bar &&
306                 git commit -m "Second file" &&
307                 git tag -a -m msg mytag &&
308                 echo morefoo >> bar &&
309                 git add bar &&
310                 git commit -m "Change to second file"
311         )
312 '
313
314 cat > limit-by-paths/expected << EOF
315 blob
316 mark :1
317 data 3
318 hi
319
320 reset refs/tags/mytag
321 commit refs/tags/mytag
322 mark :2
323 author A U Thor <author@example.com> 1112912713 -0700
324 committer C O Mitter <committer@example.com> 1112912713 -0700
325 data 11
326 First file
327 M 100644 :1 there
328
329 EOF
330
331 test_expect_success 'dropping tag of filtered out object' '
332 (
333         cd limit-by-paths &&
334         git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
335         test_cmp expected output
336 )
337 '
338
339 cat >> limit-by-paths/expected << EOF
340 tag mytag
341 from :2
342 tagger C O Mitter <committer@example.com> 1112912713 -0700
343 data 4
344 msg
345
346 EOF
347
348 test_expect_success 'rewriting tag of filtered out object' '
349 (
350         cd limit-by-paths &&
351         git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
352         test_cmp expected output
353 )
354 '
355
356 test_expect_success 'rewrite tag predating pathspecs to nothing' '
357         test_create_repo rewrite_tag_predating_pathspecs &&
358         (
359                 cd rewrite_tag_predating_pathspecs &&
360
361                 test_commit initial &&
362
363                 git tag -a -m "Some old tag" v0.0.0.0.0.0.1 &&
364
365                 test_commit bar &&
366
367                 git fast-export --tag-of-filtered-object=rewrite --all -- bar.t >output &&
368                 grep from.$ZERO_OID output
369         )
370 '
371
372 cat > limit-by-paths/expected << EOF
373 blob
374 mark :1
375 data 4
376 foo
377
378 blob
379 mark :2
380 data 3
381 hi
382
383 reset refs/heads/master
384 commit refs/heads/master
385 mark :3
386 author A U Thor <author@example.com> 1112912713 -0700
387 committer C O Mitter <committer@example.com> 1112912713 -0700
388 data 12
389 Second file
390 M 100644 :1 bar
391 M 100644 :2 there
392
393 EOF
394
395 test_expect_failure 'no exact-ref revisions included' '
396         (
397                 cd limit-by-paths &&
398                 git fast-export master~2..master~1 > output &&
399                 test_cmp expected output
400         )
401 '
402
403 test_expect_success 'path limiting with import-marks does not lose unmodified files'        '
404         git checkout -b simple marks~2 &&
405         git fast-export --export-marks=marks simple -- file > /dev/null &&
406         echo more content >> file &&
407         test_tick &&
408         git commit -mnext file &&
409         git fast-export --import-marks=marks simple -- file file0 >actual &&
410         grep file0 actual
411 '
412
413 test_expect_success 'avoid corrupt stream with non-existent mark' '
414         test_create_repo avoid_non_existent_mark &&
415         (
416                 cd avoid_non_existent_mark &&
417
418                 test_commit important-path &&
419
420                 test_commit ignored &&
421
422                 git branch A &&
423                 git branch B &&
424
425                 echo foo >>important-path.t &&
426                 git add important-path.t &&
427                 test_commit more changes &&
428
429                 git fast-export --all -- important-path.t | git fast-import --force
430         )
431 '
432
433 test_expect_success 'full-tree re-shows unmodified files'        '
434         git checkout -f simple &&
435         git fast-export --full-tree simple >actual &&
436         test $(grep -c file0 actual) -eq 3
437 '
438
439 test_expect_success 'set-up a few more tags for tag export tests' '
440         git checkout -f master &&
441         HEAD_TREE=$(git show -s --pretty=raw HEAD | grep tree | sed "s/tree //") &&
442         git tag    tree_tag        -m "tagging a tree" $HEAD_TREE &&
443         git tag -a tree_tag-obj    -m "tagging a tree" $HEAD_TREE &&
444         git tag    tag-obj_tag     -m "tagging a tag" tree_tag-obj &&
445         git tag -a tag-obj_tag-obj -m "tagging a tag" tree_tag-obj
446 '
447
448 test_expect_success 'tree_tag'        '
449         mkdir result &&
450         (cd result && git init) &&
451         git fast-export tree_tag > fe-stream &&
452         (cd result && git fast-import < ../fe-stream)
453 '
454
455 # NEEDSWORK: not just check return status, but validate the output
456 test_expect_success 'tree_tag-obj'    'git fast-export tree_tag-obj'
457 test_expect_success 'tag-obj_tag'     'git fast-export tag-obj_tag'
458 test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj'
459
460 test_expect_success 'directory becomes symlink'        '
461         git init dirtosymlink &&
462         git init result &&
463         (
464                 cd dirtosymlink &&
465                 mkdir foo &&
466                 mkdir bar &&
467                 echo hello > foo/world &&
468                 echo hello > bar/world &&
469                 git add foo/world bar/world &&
470                 git commit -q -mone &&
471                 git rm -r foo &&
472                 test_ln_s_add bar foo &&
473                 git commit -q -mtwo
474         ) &&
475         (
476                 cd dirtosymlink &&
477                 git fast-export master -- foo |
478                 (cd ../result && git fast-import --quiet)
479         ) &&
480         (cd result && git show master:foo)
481 '
482
483 test_expect_success 'fast-export quotes pathnames' '
484         git init crazy-paths &&
485         (cd crazy-paths &&
486          blob=$(echo foo | git hash-object -w --stdin) &&
487          git update-index --add \
488                 --cacheinfo 100644 $blob "$(printf "path with\\nnewline")" \
489                 --cacheinfo 100644 $blob "path with \"quote\"" \
490                 --cacheinfo 100644 $blob "path with \\backslash" \
491                 --cacheinfo 100644 $blob "path with space" &&
492          git commit -m addition &&
493          git ls-files -z -s | perl -0pe "s{\\t}{$&subdir/}" >index &&
494          git read-tree --empty &&
495          git update-index -z --index-info <index &&
496          git commit -m rename &&
497          git read-tree --empty &&
498          git commit -m deletion &&
499          git fast-export -M HEAD >export.out &&
500          git rev-list HEAD >expect &&
501          git init result &&
502          cd result &&
503          git fast-import <../export.out &&
504          git rev-list HEAD >actual &&
505          test_cmp ../expect actual
506         )
507 '
508
509 test_expect_success 'test bidirectionality' '
510         >marks-cur &&
511         >marks-new &&
512         git init marks-test &&
513         git fast-export --export-marks=marks-cur --import-marks=marks-cur --branches | \
514         git --git-dir=marks-test/.git fast-import --export-marks=marks-new --import-marks=marks-new &&
515         (cd marks-test &&
516         git reset --hard &&
517         echo Wohlauf > file &&
518         git commit -a -m "back in time") &&
519         git --git-dir=marks-test/.git fast-export --export-marks=marks-new --import-marks=marks-new --branches | \
520         git fast-import --export-marks=marks-cur --import-marks=marks-cur
521 '
522
523 cat > expected << EOF
524 blob
525 mark :13
526 data 5
527 bump
528
529 commit refs/heads/master
530 mark :14
531 author A U Thor <author@example.com> 1112912773 -0700
532 committer C O Mitter <committer@example.com> 1112912773 -0700
533 data 5
534 bump
535 from :12
536 M 100644 :13 file
537
538 EOF
539
540 test_expect_success 'avoid uninteresting refs' '
541         > tmp-marks &&
542         git fast-export --import-marks=tmp-marks \
543                 --export-marks=tmp-marks master > /dev/null &&
544         git tag v1.0 &&
545         git branch uninteresting &&
546         echo bump > file &&
547         git commit -a -m bump &&
548         git fast-export --import-marks=tmp-marks \
549                 --export-marks=tmp-marks ^uninteresting ^v1.0 master > actual &&
550         test_cmp expected actual
551 '
552
553 cat > expected << EOF
554 reset refs/heads/master
555 from :14
556
557 EOF
558
559 test_expect_success 'refs are updated even if no commits need to be exported' '
560         > tmp-marks &&
561         git fast-export --import-marks=tmp-marks \
562                 --export-marks=tmp-marks master > /dev/null &&
563         git fast-export --import-marks=tmp-marks \
564                 --export-marks=tmp-marks master > actual &&
565         test_cmp expected actual
566 '
567
568 test_expect_success 'use refspec' '
569         git fast-export --refspec refs/heads/master:refs/heads/foobar master >actual2 &&
570         grep "^commit " actual2 | sort | uniq >actual &&
571         echo "commit refs/heads/foobar" > expected &&
572         test_cmp expected actual
573 '
574
575 test_expect_success 'delete ref because entire history excluded' '
576         git branch to-delete &&
577         git fast-export to-delete ^to-delete >actual &&
578         cat >expected <<-EOF &&
579         reset refs/heads/to-delete
580         from 0000000000000000000000000000000000000000
581
582         EOF
583         test_cmp expected actual
584 '
585
586 test_expect_success 'delete refspec' '
587         git fast-export --refspec :refs/heads/to-delete >actual &&
588         cat >expected <<-EOF &&
589         reset refs/heads/to-delete
590         from 0000000000000000000000000000000000000000
591
592         EOF
593         test_cmp expected actual
594 '
595
596 test_expect_success 'when using -C, do not declare copy when source of copy is also modified' '
597         test_create_repo src &&
598         echo a_line >src/file.txt &&
599         git -C src add file.txt &&
600         git -C src commit -m 1st_commit &&
601
602         cp src/file.txt src/file2.txt &&
603         echo another_line >>src/file.txt &&
604         git -C src add file.txt file2.txt &&
605         git -C src commit -m 2nd_commit &&
606
607         test_create_repo dst &&
608         git -C src fast-export --all -C >actual &&
609         git -C dst fast-import <actual &&
610         git -C src show >expected &&
611         git -C dst show >actual &&
612         test_cmp expected actual
613 '
614
615 test_expect_success 'merge commit gets exported with --import-marks' '
616         test_create_repo merging &&
617         (
618                 cd merging &&
619                 test_commit initial &&
620                 git checkout -b topic &&
621                 test_commit on-topic &&
622                 git checkout master &&
623                 test_commit on-master &&
624                 test_tick &&
625                 git merge --no-ff -m Yeah topic &&
626
627                 echo ":1 $(git rev-parse HEAD^^)" >marks &&
628                 git fast-export --import-marks=marks master >out &&
629                 grep Yeah out
630         )
631 '
632
633 test_done