diff options
-rw-r--r-- | Documentation/git-fast-import.txt | 3 | ||||
-rw-r--r-- | builtin-fast-export.c | 19 | ||||
-rw-r--r-- | fast-import.c | 16 | ||||
-rwxr-xr-x | t/t9300-fast-import.sh | 152 | ||||
-rwxr-xr-x | t/t9301-fast-export.sh | 42 |
5 files changed, 227 insertions, 5 deletions
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 2d01d0d10..c2f483a8d 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -481,6 +481,9 @@ in octal. Git only supports the following modes: what you want. * `100755` or `755`: A normal, but executable, file. * `120000`: A symlink, the content of the file will be the link target. +* `160000`: A gitlink, SHA-1 of the object refers to a commit in + another repository. Git links can only be specified by SHA or through + a commit mark. They are used to implement submodules. In both formats `<path>` is the complete path of the file to be added (if not already existing) or modified (if already existing). diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 76f316727..a443d5946 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -136,9 +136,18 @@ static void show_filemodify(struct diff_queue_struct *q, if (is_null_sha1(spec->sha1)) printf("D %s\n", spec->path); else { - struct object *object = lookup_object(spec->sha1); - printf("M %06o :%d %s\n", spec->mode, - get_object_mark(object), spec->path); + /* + * Links refer to objects in another repositories; + * output the SHA-1 verbatim. + */ + if (S_ISGITLINK(spec->mode)) + printf("M %06o %s %s\n", spec->mode, + sha1_to_hex(spec->sha1), spec->path); + else { + struct object *object = lookup_object(spec->sha1); + printf("M %06o :%d %s\n", spec->mode, + get_object_mark(object), spec->path); + } } } } @@ -196,8 +205,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) diff_root_tree_sha1(commit->tree->object.sha1, "", &rev->diffopt); + /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) - handle_object(diff_queued_diff.queue[i]->two->sha1); + if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode)) + handle_object(diff_queued_diff.queue[i]->two->sha1); mark_next_object(&commit->object); if (!is_encoding_utf8(encoding)) diff --git a/fast-import.c b/fast-import.c index c4d054ecc..7089e6f9e 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1868,6 +1868,7 @@ static void file_change_m(struct branch *b) case S_IFREG | 0644: case S_IFREG | 0755: case S_IFLNK: + case S_IFGITLINK: case 0644: case 0755: /* ok */ @@ -1900,7 +1901,20 @@ static void file_change_m(struct branch *b) p = uq.buf; } - if (inline_data) { + if (S_ISGITLINK(mode)) { + if (inline_data) + die("Git links cannot be specified 'inline': %s", + command_buf.buf); + else if (oe) { + if (oe->type != OBJ_COMMIT) + die("Not a commit (actually a %s): %s", + typename(oe->type), command_buf.buf); + } + /* + * Accept the sha1 without checking; it expected to be in + * another repository. + */ + } else if (inline_data) { static struct strbuf buf = STRBUF_INIT; if (p != uq.buf) { diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index e17afa8c3..1fc06c5a2 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -918,4 +918,156 @@ test_expect_success \ grep "progress " <input >expect && test_cmp expect actual' +### +### series P (gitlinks) +### + +cat >input <<INPUT_END +blob +mark :1 +data 10 +test file + +reset refs/heads/sub +commit refs/heads/sub +mark :2 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 12 +sub_initial +M 100644 :1 file + +blob +mark :3 +data <<DATAEND +[submodule "sub"] + path = sub + url = "`pwd`/sub" +DATAEND + +commit refs/heads/subuse1 +mark :4 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 8 +initial +from refs/heads/master +M 100644 :3 .gitmodules +M 160000 :2 sub + +blob +mark :5 +data 20 +test file +more data + +commit refs/heads/sub +mark :6 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 11 +sub_second +from :2 +M 100644 :5 file + +commit refs/heads/subuse1 +mark :7 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 7 +second +from :4 +M 160000 :6 sub + +INPUT_END + +test_expect_success \ + 'P: supermodule & submodule mix' \ + 'git-fast-import <input && + git checkout subuse1 && + rm -rf sub && mkdir sub && cd sub && + git init && + git fetch .. refs/heads/sub:refs/heads/master && + git checkout master && + cd .. && + git submodule init && + git submodule update' + +SUBLAST=$(git-rev-parse --verify sub) +SUBPREV=$(git-rev-parse --verify sub^) + +cat >input <<INPUT_END +blob +mark :1 +data <<DATAEND +[submodule "sub"] + path = sub + url = "`pwd`/sub" +DATAEND + +commit refs/heads/subuse2 +mark :2 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 8 +initial +from refs/heads/master +M 100644 :1 .gitmodules +M 160000 $SUBPREV sub + +commit refs/heads/subuse2 +mark :3 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 7 +second +from :2 +M 160000 $SUBLAST sub + +INPUT_END + +test_expect_success \ + 'P: verbatim SHA gitlinks' \ + 'git branch -D sub && + git gc && git prune && + git-fast-import <input && + test $(git-rev-parse --verify subuse2) = $(git-rev-parse --verify subuse1)' + +test_tick +cat >input <<INPUT_END +commit refs/heads/subuse3 +mark :1 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +corrupt +COMMIT + +from refs/heads/subuse2 +M 160000 inline sub +data <<DATA +$SUBPREV +DATA + +INPUT_END + +test_expect_success 'P: fail on inline gitlink' ' + ! git-fast-import <input' + +test_tick +cat >input <<INPUT_END +blob +mark :1 +data <<DATA +$SUBPREV +DATA + +commit refs/heads/subuse3 +mark :2 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +corrupt +COMMIT + +from refs/heads/subuse2 +M 160000 :1 sub + +INPUT_END + +test_expect_success 'P: fail on blob mark in gitlink' ' + ! git-fast-import <input' + test_done diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 0959f2f81..8324f6e3b 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -143,4 +143,46 @@ test_expect_success 'signed-tags=strip' ' ' +test_expect_success 'setup submodule' ' + + git checkout -f master && + mkdir sub && + cd sub && + git init && + echo test file > file && + git add file && + git commit -m sub_initial && + cd .. && + git submodule add "`pwd`/sub" sub && + git commit -m initial && + test_tick && + cd sub && + echo more data >> file && + git add file && + git commit -m sub_second && + cd .. && + git add sub && + git commit -m second + +' + +test_expect_success 'submodule fast-export | fast-import' ' + + SUBENT1=$(git ls-tree master^ sub) && + SUBENT2=$(git ls-tree master sub) && + rm -rf new && + mkdir new && + git --git-dir=new/.git init && + git fast-export --signed-tags=strip --all | + (cd new && + git fast-import && + test "$SUBENT1" = "$(git ls-tree refs/heads/master^ sub)" && + test "$SUBENT2" = "$(git ls-tree refs/heads/master sub)" && + git checkout master && + git submodule init && + git submodule update && + cmp sub/file ../sub/file) + +' + test_done |