@matheusbsbs / matheus-bagliano / commits / 03db4525d3
Fork 0

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>

Alexander Gavrilov committed Jul 19, 2008 at 16:21 UTC 03db4525d38119f7778d6e9117f27c47db8466d4
5 files changed +227 -5
Documentation/git-fast-import.txt
+3
@@ -481,6 +481,9 @@ in octal. Git only supports the following modes:
481 what you want.
482 * `100755` or `755`: A normal, but executable, file.
483 * `120000`: A symlink, the content of the file will be the link target.
484 +* `160000`: A gitlink, SHA-1 of the object refers to a commit in
485 + another repository. Git links can only be specified by SHA or through
486 + a commit mark. They are used to implement submodules.
487
488 In both formats `<path>` is the complete path of the file to be added
489 (if not already existing) or modified (if already existing).
builtin-fast-export.c
+15 -4
@@ -136,9 +136,18 @@ static void show_filemodify(struct diff_queue_struct *q,
136 if (is_null_sha1(spec->sha1))
137 printf("D %s\n", spec->path);
138 else {
139 - struct object *object = lookup_object(spec->sha1);
140 - printf("M %06o :%d %s\n", spec->mode,
141 - get_object_mark(object), spec->path);
139 + /*
140 + * Links refer to objects in another repositories;
141 + * output the SHA-1 verbatim.
142 + */
143 + if (S_ISGITLINK(spec->mode))
144 + printf("M %06o %s %s\n", spec->mode,
145 + sha1_to_hex(spec->sha1), spec->path);
146 + else {
147 + struct object *object = lookup_object(spec->sha1);
148 + printf("M %06o :%d %s\n", spec->mode,
149 + get_object_mark(object), spec->path);
150 + }
151 }
152 }
153 }
@@ -196,8 +205,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
205 diff_root_tree_sha1(commit->tree->object.sha1,
206 "", &rev->diffopt);
207
208 + /* Export the referenced blobs, and remember the marks. */
209 for (i = 0; i < diff_queued_diff.nr; i++)
200 - handle_object(diff_queued_diff.queue[i]->two->sha1);
210 + if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
211 + handle_object(diff_queued_diff.queue[i]->two->sha1);
212
213 mark_next_object(&commit->object);
214 if (!is_encoding_utf8(encoding))
fast-import.c
+15 -1
@@ -1868,6 +1868,7 @@ static void file_change_m(struct branch *b)
1868 case S_IFREG | 0644:
1869 case S_IFREG | 0755:
1870 case S_IFLNK:
1871 + case S_IFGITLINK:
1872 case 0644:
1873 case 0755:
1874 /* ok */
@@ -1900,7 +1901,20 @@ static void file_change_m(struct branch *b)
1901 p = uq.buf;
1902 }
1903
1903 - if (inline_data) {
1904 + if (S_ISGITLINK(mode)) {
1905 + if (inline_data)
1906 + die("Git links cannot be specified 'inline': %s",
1907 + command_buf.buf);
1908 + else if (oe) {
1909 + if (oe->type != OBJ_COMMIT)
1910 + die("Not a commit (actually a %s): %s",
1911 + typename(oe->type), command_buf.buf);
1912 + }
1913 + /*
1914 + * Accept the sha1 without checking; it expected to be in
1915 + * another repository.
1916 + */
1917 + } else if (inline_data) {
1918 static struct strbuf buf = STRBUF_INIT;
1919
1920 if (p != uq.buf) {
t/t9300-fast-import.sh
+152
@@ -918,4 +918,156 @@ test_expect_success \
918 grep "progress " <input >expect &&
919 test_cmp expect actual'
920
921 +###
922 +### series P (gitlinks)
923 +###
924 +
925 +cat >input <<INPUT_END
926 +blob
927 +mark :1
928 +data 10
929 +test file
930 +
931 +reset refs/heads/sub
932 +commit refs/heads/sub
933 +mark :2
934 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
935 +data 12
936 +sub_initial
937 +M 100644 :1 file
938 +
939 +blob
940 +mark :3
941 +data <<DATAEND
942 +[submodule "sub"]
943 + path = sub
944 + url = "`pwd`/sub"
945 +DATAEND
946 +
947 +commit refs/heads/subuse1
948 +mark :4
949 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
950 +data 8
951 +initial
952 +from refs/heads/master
953 +M 100644 :3 .gitmodules
954 +M 160000 :2 sub
955 +
956 +blob
957 +mark :5
958 +data 20
959 +test file
960 +more data
961 +
962 +commit refs/heads/sub
963 +mark :6
964 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
965 +data 11
966 +sub_second
967 +from :2
968 +M 100644 :5 file
969 +
970 +commit refs/heads/subuse1
971 +mark :7
972 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
973 +data 7
974 +second
975 +from :4
976 +M 160000 :6 sub
977 +
978 +INPUT_END
979 +
980 +test_expect_success \
981 + 'P: supermodule & submodule mix' \
982 + 'git-fast-import <input &&
983 + git checkout subuse1 &&
984 + rm -rf sub && mkdir sub && cd sub &&
985 + git init &&
986 + git fetch .. refs/heads/sub:refs/heads/master &&
987 + git checkout master &&
988 + cd .. &&
989 + git submodule init &&
990 + git submodule update'
991 +
992 +SUBLAST=$(git-rev-parse --verify sub)
993 +SUBPREV=$(git-rev-parse --verify sub^)
994 +
995 +cat >input <<INPUT_END
996 +blob
997 +mark :1
998 +data <<DATAEND
999 +[submodule "sub"]
1000 + path = sub
1001 + url = "`pwd`/sub"
1002 +DATAEND
1003 +
1004 +commit refs/heads/subuse2
1005 +mark :2
1006 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1007 +data 8
1008 +initial
1009 +from refs/heads/master
1010 +M 100644 :1 .gitmodules
1011 +M 160000 $SUBPREV sub
1012 +
1013 +commit refs/heads/subuse2
1014 +mark :3
1015 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1016 +data 7
1017 +second
1018 +from :2
1019 +M 160000 $SUBLAST sub
1020 +
1021 +INPUT_END
1022 +
1023 +test_expect_success \
1024 + 'P: verbatim SHA gitlinks' \
1025 + 'git branch -D sub &&
1026 + git gc && git prune &&
1027 + git-fast-import <input &&
1028 + test $(git-rev-parse --verify subuse2) = $(git-rev-parse --verify subuse1)'
1029 +
1030 +test_tick
1031 +cat >input <<INPUT_END
1032 +commit refs/heads/subuse3
1033 +mark :1
1034 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1035 +data <<COMMIT
1036 +corrupt
1037 +COMMIT
1038 +
1039 +from refs/heads/subuse2
1040 +M 160000 inline sub
1041 +data <<DATA
1042 +$SUBPREV
1043 +DATA
1044 +
1045 +INPUT_END
1046 +
1047 +test_expect_success 'P: fail on inline gitlink' '
1048 + ! git-fast-import <input'
1049 +
1050 +test_tick
1051 +cat >input <<INPUT_END
1052 +blob
1053 +mark :1
1054 +data <<DATA
1055 +$SUBPREV
1056 +DATA
1057 +
1058 +commit refs/heads/subuse3
1059 +mark :2
1060 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
1061 +data <<COMMIT
1062 +corrupt
1063 +COMMIT
1064 +
1065 +from refs/heads/subuse2
1066 +M 160000 :1 sub
1067 +
1068 +INPUT_END
1069 +
1070 +test_expect_success 'P: fail on blob mark in gitlink' '
1071 + ! git-fast-import <input'
1072 +
1073 test_done
t/t9301-fast-export.sh
+42
@@ -143,4 +143,46 @@ test_expect_success 'signed-tags=strip' '
143
144 '
145
146 +test_expect_success 'setup submodule' '
147 +
148 + git checkout -f master &&
149 + mkdir sub &&
150 + cd sub &&
151 + git init &&
152 + echo test file > file &&
153 + git add file &&
154 + git commit -m sub_initial &&
155 + cd .. &&
156 + git submodule add "`pwd`/sub" sub &&
157 + git commit -m initial &&
158 + test_tick &&
159 + cd sub &&
160 + echo more data >> file &&
161 + git add file &&
162 + git commit -m sub_second &&
163 + cd .. &&
164 + git add sub &&
165 + git commit -m second
166 +
167 +'
168 +
169 +test_expect_success 'submodule fast-export | fast-import' '
170 +
171 + SUBENT1=$(git ls-tree master^ sub) &&
172 + SUBENT2=$(git ls-tree master sub) &&
173 + rm -rf new &&
174 + mkdir new &&
175 + git --git-dir=new/.git init &&
176 + git fast-export --signed-tags=strip --all |
177 + (cd new &&
178 + git fast-import &&
179 + test "$SUBENT1" = "$(git ls-tree refs/heads/master^ sub)" &&
180 + test "$SUBENT2" = "$(git ls-tree refs/heads/master sub)" &&
181 + git checkout master &&
182 + git submodule init &&
183 + git submodule update &&
184 + cmp sub/file ../sub/file)
185 +
186 +'
187 +
188 test_done