mirror of
https://github.com/git/git.git
synced 2024-11-27 12:03:55 +08:00
Support gitlinks in fast-import.
Currently fast-import/export cannot be used for repositories with submodules. This patch extends the relevant programs to make them correctly process gitlinks. Links can be represented by two forms of the Modify command: M 160000 SHA1 some/path which sets the link target explicitly, or M 160000 :mark some/path where the mark refers to a commit. The latter form can be used by importing tools to build all submodules simultaneously in one physical repository, and then simply fetch them apart. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
4a3fedd597
commit
03db4525d3
@ -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).
|
||||
|
@ -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))
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user