]>
Commit | Line | Data |
---|---|---|
cf9dc653 MW |
1 | #!/bin/sh |
2 | # | |
3 | # Copyright (C) 2006 Martin Waitz <tali@admingilde.org> | |
4 | # | |
5 | ||
6 | test_description='test clone --reference' | |
95cf2c01 | 7 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
334afbc7 JS |
8 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
9 | ||
b2e5d75d | 10 | TEST_PASSES_SANITIZE_LEAK=true |
cf9dc653 MW |
11 | . ./test-lib.sh |
12 | ||
46d76d6c | 13 | base_dir=$(pwd) |
cf9dc653 | 14 | |
4ba776c2 DB |
15 | U=$base_dir/UPLOAD_LOG |
16 | ||
bc192300 JK |
17 | # create a commit in repo $1 with name $2 |
18 | commit_in () { | |
19 | ( | |
20 | cd "$1" && | |
21 | echo "$2" >"$2" && | |
22 | git add "$2" && | |
23 | git commit -m "$2" | |
24 | ) | |
25 | } | |
26 | ||
27 | # check that there are $2 loose objects in repo $1 | |
28 | test_objcount () { | |
29 | echo "$2" >expect && | |
30 | git -C "$1" count-objects >actual.raw && | |
31 | cut -d' ' -f1 <actual.raw >actual && | |
32 | test_cmp expect actual | |
33 | } | |
34 | ||
35 | test_expect_success 'preparing first repository' ' | |
36 | test_create_repo A && | |
37 | commit_in A file1 | |
38 | ' | |
cf9dc653 | 39 | |
bc192300 JK |
40 | test_expect_success 'preparing second repository' ' |
41 | git clone A B && | |
42 | commit_in B file2 && | |
43 | git -C B repack -ad && | |
44 | git -C B prune | |
45 | ' | |
cf9dc653 | 46 | |
bc192300 JK |
47 | test_expect_success 'cloning with reference (-l -s)' ' |
48 | git clone -l -s --reference B A C | |
49 | ' | |
cf9dc653 | 50 | |
bc192300 JK |
51 | test_expect_success 'existence of info/alternates' ' |
52 | test_line_count = 2 C/.git/objects/info/alternates | |
53 | ' | |
cf9dc653 | 54 | |
bc192300 | 55 | test_expect_success 'pulling from reference' ' |
95cf2c01 | 56 | git -C C pull ../B main |
bc192300 | 57 | ' |
cf9dc653 | 58 | |
bc192300 JK |
59 | test_expect_success 'that reference gets used' ' |
60 | test_objcount C 0 | |
61 | ' | |
4ba776c2 | 62 | |
2ad23273 JK |
63 | test_expect_success 'cloning with reference (no -l -s)' ' |
64 | GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D | |
65 | ' | |
4ba776c2 | 66 | |
2ad23273 JK |
67 | test_expect_success 'fetched no objects' ' |
68 | test -s "$U.D" && | |
69 | ! grep " want" "$U.D" | |
70 | ' | |
1f7d1a53 | 71 | |
bc192300 JK |
72 | test_expect_success 'existence of info/alternates' ' |
73 | test_line_count = 1 D/.git/objects/info/alternates | |
74 | ' | |
1f7d1a53 | 75 | |
bc192300 | 76 | test_expect_success 'pulling from reference' ' |
95cf2c01 | 77 | git -C D pull ../B main |
bc192300 | 78 | ' |
cf9dc653 | 79 | |
bc192300 JK |
80 | test_expect_success 'that reference gets used' ' |
81 | test_objcount D 0 | |
82 | ' | |
cf9dc653 | 83 | |
bc192300 JK |
84 | test_expect_success 'updating origin' ' |
85 | commit_in A file3 && | |
86 | git -C A repack -ad && | |
87 | git -C A prune | |
88 | ' | |
cf9dc653 | 89 | |
bc192300 | 90 | test_expect_success 'pulling changes from origin' ' |
031e2f7a | 91 | git -C C pull --no-rebase origin |
bc192300 | 92 | ' |
cf9dc653 MW |
93 | |
94 | # the 2 local objects are commit and tree from the merge | |
bc192300 JK |
95 | test_expect_success 'that alternate to origin gets used' ' |
96 | test_objcount C 2 | |
97 | ' | |
1f7d1a53 | 98 | |
bc192300 | 99 | test_expect_success 'pulling changes from origin' ' |
031e2f7a | 100 | git -C D pull --no-rebase origin |
bc192300 | 101 | ' |
1f7d1a53 JH |
102 | |
103 | # the 5 local objects are expected; file3 blob, commit in A to add it | |
104 | # and its tree, and 2 are our tree and the merge commit. | |
bc192300 JK |
105 | test_expect_success 'check objects expected to exist locally' ' |
106 | test_objcount D 5 | |
107 | ' | |
fabb0199 | 108 | |
bc192300 JK |
109 | test_expect_success 'preparing alternate repository #1' ' |
110 | test_create_repo F && | |
111 | commit_in F file1 | |
112 | ' | |
fabb0199 | 113 | |
bc192300 JK |
114 | test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' ' |
115 | git clone F G && | |
116 | commit_in F file2 | |
117 | ' | |
fabb0199 | 118 | |
bc192300 JK |
119 | test_expect_success 'cloning alternate repo #1, using #2 as reference' ' |
120 | git clone --reference G F H | |
121 | ' | |
b50c8469 | 122 | |
bc192300 JK |
123 | test_expect_success 'cloning with reference being subset of source (-l -s)' ' |
124 | git clone -l -s --reference A B E | |
125 | ' | |
b50c8469 | 126 | |
77b9b1d1 JK |
127 | test_expect_success 'cloning with multiple references drops duplicates' ' |
128 | git clone -s --reference B --reference A --reference B A dups && | |
129 | test_line_count = 2 dups/.git/objects/info/alternates | |
130 | ' | |
131 | ||
09116a1c JH |
132 | test_expect_success 'clone with reference from a tagged repository' ' |
133 | ( | |
bc192300 | 134 | cd A && git tag -a -m tagged HEAD |
09116a1c JH |
135 | ) && |
136 | git clone --reference=A A I | |
137 | ' | |
138 | ||
acede2eb MH |
139 | test_expect_success 'prepare branched repository' ' |
140 | git clone A J && | |
141 | ( | |
142 | cd J && | |
95cf2c01 | 143 | git checkout -b other main^ && |
acede2eb MH |
144 | echo other >otherfile && |
145 | git add otherfile && | |
146 | git commit -m other && | |
95cf2c01 | 147 | git checkout main |
acede2eb MH |
148 | ) |
149 | ' | |
150 | ||
f2576591 | 151 | test_expect_success 'fetch with incomplete alternates' ' |
acede2eb MH |
152 | git init K && |
153 | echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && | |
154 | ( | |
155 | cd K && | |
156 | git remote add J "file://$base_dir/J" && | |
2ad23273 | 157 | GIT_TRACE_PACKET=$U.K git fetch J |
acede2eb | 158 | ) && |
95cf2c01 | 159 | main_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/main) && |
2ad23273 | 160 | test -s "$U.K" && |
95cf2c01 | 161 | ! grep " want $main_object" "$U.K" && |
acede2eb | 162 | tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) && |
97a83fa8 | 163 | ! grep " want $tag_object" "$U.K" |
acede2eb MH |
164 | ' |
165 | ||
b552b56d AS |
166 | test_expect_success 'clone using repo with gitfile as a reference' ' |
167 | git clone --separate-git-dir=L A M && | |
168 | git clone --reference=M A N && | |
169 | echo "$base_dir/L/objects" >expected && | |
170 | test_cmp expected "$base_dir/N/.git/objects/info/alternates" | |
171 | ' | |
172 | ||
173 | test_expect_success 'clone using repo pointed at by gitfile as reference' ' | |
174 | git clone --reference=M/.git A O && | |
175 | echo "$base_dir/L/objects" >expected && | |
176 | test_cmp expected "$base_dir/O/.git/objects/info/alternates" | |
177 | ' | |
178 | ||
fb1d6dab JH |
179 | test_expect_success 'clone and dissociate from reference' ' |
180 | git init P && | |
181 | ( | |
64d1022e | 182 | cd P && test_commit one |
fb1d6dab JH |
183 | ) && |
184 | git clone P Q && | |
185 | ( | |
186 | cd Q && test_commit two | |
187 | ) && | |
188 | git clone --no-local --reference=P Q R && | |
189 | git clone --no-local --reference=P --dissociate Q S && | |
190 | # removing the reference P would corrupt R but not S | |
191 | rm -fr P && | |
192 | test_must_fail git -C R fsck && | |
193 | git -C S fsck | |
194 | ' | |
786b150c | 195 | test_expect_success 'clone, dissociate from partial reference and repack' ' |
11911bf7 JS |
196 | rm -fr P Q R && |
197 | git init P && | |
198 | ( | |
199 | cd P && | |
200 | test_commit one && | |
201 | git repack && | |
202 | test_commit two && | |
203 | git repack | |
204 | ) && | |
205 | git clone --bare P Q && | |
206 | ( | |
207 | cd P && | |
208 | git checkout -b second && | |
209 | test_commit three && | |
210 | git repack | |
211 | ) && | |
212 | git clone --bare --dissociate --reference=P Q R && | |
213 | ls R/objects/pack/*.pack >packs.txt && | |
214 | test_line_count = 1 packs.txt | |
215 | ' | |
fb1d6dab | 216 | |
0181681e AR |
217 | test_expect_success 'clone, dissociate from alternates' ' |
218 | rm -fr A B C && | |
219 | test_create_repo A && | |
220 | commit_in A file1 && | |
221 | git clone --reference=A A B && | |
222 | test_line_count = 1 B/.git/objects/info/alternates && | |
223 | git clone --local --dissociate B C && | |
224 | ! test -f C/.git/objects/info/alternates && | |
225 | ( cd C && git fsck ) | |
226 | ' | |
227 | ||
03156169 ÆAB |
228 | test_expect_success 'setup repo with garbage in objects/*' ' |
229 | git init S && | |
230 | ( | |
231 | cd S && | |
232 | test_commit A && | |
233 | ||
234 | cd .git/objects && | |
235 | >.some-hidden-file && | |
236 | >some-file && | |
237 | mkdir .some-hidden-dir && | |
238 | >.some-hidden-dir/some-file && | |
239 | >.some-hidden-dir/.some-dot-file && | |
240 | mkdir some-dir && | |
241 | >some-dir/some-file && | |
242 | >some-dir/.some-dot-file | |
243 | ) | |
244 | ' | |
245 | ||
246 | test_expect_success 'clone a repo with garbage in objects/*' ' | |
247 | for option in --local --no-hardlinks --shared --dissociate | |
248 | do | |
249 | git clone $option S S$option || return 1 && | |
250 | git -C S$option fsck || return 1 | |
251 | done && | |
252 | find S-* -name "*some*" | sort >actual && | |
253 | cat >expected <<-EOF && | |
68c7c59c MT |
254 | S--dissociate/.git/objects/.some-hidden-dir |
255 | S--dissociate/.git/objects/.some-hidden-dir/.some-dot-file | |
256 | S--dissociate/.git/objects/.some-hidden-dir/some-file | |
03156169 ÆAB |
257 | S--dissociate/.git/objects/.some-hidden-file |
258 | S--dissociate/.git/objects/some-dir | |
259 | S--dissociate/.git/objects/some-dir/.some-dot-file | |
260 | S--dissociate/.git/objects/some-dir/some-file | |
261 | S--dissociate/.git/objects/some-file | |
68c7c59c MT |
262 | S--local/.git/objects/.some-hidden-dir |
263 | S--local/.git/objects/.some-hidden-dir/.some-dot-file | |
264 | S--local/.git/objects/.some-hidden-dir/some-file | |
03156169 ÆAB |
265 | S--local/.git/objects/.some-hidden-file |
266 | S--local/.git/objects/some-dir | |
267 | S--local/.git/objects/some-dir/.some-dot-file | |
268 | S--local/.git/objects/some-dir/some-file | |
269 | S--local/.git/objects/some-file | |
68c7c59c MT |
270 | S--no-hardlinks/.git/objects/.some-hidden-dir |
271 | S--no-hardlinks/.git/objects/.some-hidden-dir/.some-dot-file | |
272 | S--no-hardlinks/.git/objects/.some-hidden-dir/some-file | |
03156169 ÆAB |
273 | S--no-hardlinks/.git/objects/.some-hidden-file |
274 | S--no-hardlinks/.git/objects/some-dir | |
275 | S--no-hardlinks/.git/objects/some-dir/.some-dot-file | |
276 | S--no-hardlinks/.git/objects/some-dir/some-file | |
277 | S--no-hardlinks/.git/objects/some-file | |
278 | EOF | |
279 | test_cmp expected actual | |
280 | ' | |
281 | ||
36596fd2 | 282 | test_expect_success SYMLINKS 'setup repo with manually symlinked or unknown files at objects/' ' |
03156169 ÆAB |
283 | git init T && |
284 | ( | |
285 | cd T && | |
286 | git config gc.auto 0 && | |
287 | test_commit A && | |
288 | git gc && | |
289 | test_commit B && | |
290 | ||
291 | cd .git/objects && | |
292 | mv pack packs && | |
293 | ln -s packs pack && | |
294 | find ?? -type d >loose-dirs && | |
295 | last_loose=$(tail -n 1 loose-dirs) && | |
03156169 ÆAB |
296 | mv $last_loose a-loose-dir && |
297 | ln -s a-loose-dir $last_loose && | |
36596fd2 MT |
298 | first_loose=$(head -n 1 loose-dirs) && |
299 | rm -f loose-dirs && | |
300 | ||
301 | cd $first_loose && | |
302 | obj=$(ls *) && | |
303 | mv $obj ../an-object && | |
304 | ln -s ../an-object $obj && | |
305 | ||
306 | cd ../ && | |
03156169 ÆAB |
307 | echo unknown_content >unknown_file |
308 | ) && | |
309 | git -C T fsck && | |
310 | git -C T rev-list --all --objects >T.objects | |
311 | ' | |
312 | ||
313 | ||
36596fd2 | 314 | test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at objects/' ' |
6f054f9f TB |
315 | # None of these options work when cloning locally, since T has |
316 | # symlinks in its `$GIT_DIR/objects` directory | |
317 | for option in --local --no-hardlinks --dissociate | |
03156169 | 318 | do |
6f054f9f | 319 | test_must_fail git clone $option T T$option 2>err || return 1 && |
6789275d | 320 | test_grep "symlink.*exists" err || return 1 |
03156169 ÆAB |
321 | done && |
322 | ||
6f054f9f TB |
323 | # But `--shared` clones should still work, even when specifying |
324 | # a local path *and* that repository has symlinks present in its | |
325 | # `$GIT_DIR/objects` directory. | |
326 | git clone --shared T T--shared && | |
327 | git -C T--shared fsck && | |
328 | git -C T--shared rev-list --all --objects >T--shared.objects && | |
329 | test_cmp T.objects T--shared.objects && | |
330 | ( | |
331 | cd T--shared/.git/objects && | |
332 | find . -type f | sort >../../../T--shared.objects-files.raw && | |
333 | find . -type l | sort >../../../T--shared.objects-symlinks.raw | |
334 | ) && | |
335 | ||
03156169 ÆAB |
336 | for raw in $(ls T*.raw) |
337 | do | |
338 | sed -e "s!/../!/Y/!; s![0-9a-f]\{38,\}!Z!" -e "/commit-graph/d" \ | |
35a8a354 | 339 | -e "/multi-pack-index/d" -e "/rev/d" <$raw >$raw.de-sha-1 && |
277eb5af | 340 | sort $raw.de-sha-1 >$raw.de-sha || return 1 |
03156169 ÆAB |
341 | done && |
342 | ||
03156169 | 343 | echo ./info/alternates >expected-files && |
36596fd2 MT |
344 | test_cmp expected-files T--shared.objects-files.raw && |
345 | test_must_be_empty T--shared.objects-symlinks.raw | |
03156169 ÆAB |
346 | ' |
347 | ||
bffc762f TB |
348 | test_expect_success SYMLINKS 'clone repo with symlinked objects directory' ' |
349 | test_when_finished "rm -fr sensitive malicious" && | |
350 | ||
351 | mkdir -p sensitive && | |
352 | echo "secret" >sensitive/file && | |
353 | ||
354 | git init malicious && | |
355 | rm -fr malicious/.git/objects && | |
356 | ln -s "$(pwd)/sensitive" ./malicious/.git/objects && | |
357 | ||
358 | test_must_fail git clone --local malicious clone 2>err && | |
359 | ||
360 | test_path_is_missing clone && | |
4e33535e | 361 | grep "is a symlink, refusing to clone with --local" err |
bffc762f TB |
362 | ' |
363 | ||
cf9dc653 | 364 | test_done |