]>
Commit | Line | Data |
---|---|---|
0fabafd0 TB |
1 | #!/bin/sh |
2 | ||
3 | test_description='git repack --geometric works correctly' | |
4 | ||
5 | . ./test-lib.sh | |
6 | ||
7 | GIT_TEST_MULTI_PACK_INDEX=0 | |
8 | ||
9 | objdir=.git/objects | |
aab7bea1 | 10 | packdir=$objdir/pack |
0fabafd0 TB |
11 | midx=$objdir/pack/multi-pack-index |
12 | ||
932c16c0 PS |
13 | packed_objects () { |
14 | git show-index <"$1" >tmp-object-list && | |
15 | cut -d' ' -f2 tmp-object-list | sort && | |
16 | rm tmp-object-list | |
17 | } | |
18 | ||
0fabafd0 TB |
19 | test_expect_success '--geometric with no packs' ' |
20 | git init geometric && | |
21 | test_when_finished "rm -fr geometric" && | |
22 | ( | |
23 | cd geometric && | |
24 | ||
1d89d88d | 25 | git repack --write-midx --geometric 2 >out && |
0fabafd0 TB |
26 | test_i18ngrep "Nothing new to pack" out |
27 | ) | |
28 | ' | |
29 | ||
f25e33c1 TB |
30 | test_expect_success '--geometric with one pack' ' |
31 | git init geometric && | |
32 | test_when_finished "rm -fr geometric" && | |
33 | ( | |
34 | cd geometric && | |
35 | ||
36 | test_commit "base" && | |
37 | git repack -d && | |
38 | ||
39 | git repack --geometric 2 >out && | |
40 | ||
41 | test_i18ngrep "Nothing new to pack" out | |
42 | ) | |
43 | ' | |
44 | ||
0fabafd0 TB |
45 | test_expect_success '--geometric with an intact progression' ' |
46 | git init geometric && | |
47 | test_when_finished "rm -fr geometric" && | |
48 | ( | |
49 | cd geometric && | |
50 | ||
51 | # These packs already form a geometric progression. | |
52 | test_commit_bulk --start=1 1 && # 3 objects | |
53 | test_commit_bulk --start=2 2 && # 6 objects | |
54 | test_commit_bulk --start=4 4 && # 12 objects | |
55 | ||
56 | find $objdir/pack -name "*.pack" | sort >expect && | |
57 | git repack --geometric 2 -d && | |
58 | find $objdir/pack -name "*.pack" | sort >actual && | |
59 | ||
60 | test_cmp expect actual | |
61 | ) | |
62 | ' | |
63 | ||
dab32477 TB |
64 | test_expect_success '--geometric with loose objects' ' |
65 | git init geometric && | |
66 | test_when_finished "rm -fr geometric" && | |
67 | ( | |
68 | cd geometric && | |
69 | ||
70 | # These packs already form a geometric progression. | |
71 | test_commit_bulk --start=1 1 && # 3 objects | |
72 | test_commit_bulk --start=2 2 && # 6 objects | |
73 | # The loose objects are packed together, breaking the | |
74 | # progression. | |
75 | test_commit loose && # 3 objects | |
76 | ||
77 | find $objdir/pack -name "*.pack" | sort >before && | |
78 | git repack --geometric 2 -d && | |
79 | find $objdir/pack -name "*.pack" | sort >after && | |
80 | ||
81 | comm -13 before after >new && | |
82 | comm -23 before after >removed && | |
83 | ||
84 | test_line_count = 1 new && | |
85 | test_must_be_empty removed && | |
86 | ||
87 | git repack --geometric 2 -d && | |
88 | find $objdir/pack -name "*.pack" | sort >after && | |
89 | ||
90 | # The progression (3, 3, 6) is combined into one new pack. | |
91 | test_line_count = 1 after | |
92 | ) | |
93 | ' | |
94 | ||
0fabafd0 TB |
95 | test_expect_success '--geometric with small-pack rollup' ' |
96 | git init geometric && | |
97 | test_when_finished "rm -fr geometric" && | |
98 | ( | |
99 | cd geometric && | |
100 | ||
101 | test_commit_bulk --start=1 1 && # 3 objects | |
102 | test_commit_bulk --start=2 1 && # 3 objects | |
103 | find $objdir/pack -name "*.pack" | sort >small && | |
104 | test_commit_bulk --start=3 4 && # 12 objects | |
105 | test_commit_bulk --start=7 8 && # 24 objects | |
106 | find $objdir/pack -name "*.pack" | sort >before && | |
107 | ||
108 | git repack --geometric 2 -d && | |
109 | ||
110 | # Three packs in total; two of the existing large ones, and one | |
111 | # new one. | |
112 | find $objdir/pack -name "*.pack" | sort >after && | |
113 | test_line_count = 3 after && | |
114 | comm -3 small before | tr -d "\t" >large && | |
115 | grep -qFf large after | |
116 | ) | |
117 | ' | |
118 | ||
119 | test_expect_success '--geometric with small- and large-pack rollup' ' | |
120 | git init geometric && | |
121 | test_when_finished "rm -fr geometric" && | |
122 | ( | |
123 | cd geometric && | |
124 | ||
125 | # size(small1) + size(small2) > size(medium) / 2 | |
126 | test_commit_bulk --start=1 1 && # 3 objects | |
127 | test_commit_bulk --start=2 1 && # 3 objects | |
128 | test_commit_bulk --start=2 3 && # 7 objects | |
129 | test_commit_bulk --start=6 9 && # 27 objects && | |
130 | ||
131 | find $objdir/pack -name "*.pack" | sort >before && | |
132 | ||
133 | git repack --geometric 2 -d && | |
134 | ||
135 | find $objdir/pack -name "*.pack" | sort >after && | |
136 | comm -12 before after >untouched && | |
137 | ||
138 | # Two packs in total; the largest pack from before running "git | |
139 | # repack", and one new one. | |
140 | test_line_count = 1 untouched && | |
141 | test_line_count = 2 after | |
142 | ) | |
143 | ' | |
144 | ||
145 | test_expect_success '--geometric ignores kept packs' ' | |
146 | git init geometric && | |
147 | test_when_finished "rm -fr geometric" && | |
148 | ( | |
149 | cd geometric && | |
150 | ||
151 | test_commit kept && # 3 objects | |
152 | test_commit pack && # 3 objects | |
153 | ||
154 | KEPT=$(git pack-objects --revs $objdir/pack/pack <<-EOF | |
155 | refs/tags/kept | |
156 | EOF | |
157 | ) && | |
158 | PACK=$(git pack-objects --revs $objdir/pack/pack <<-EOF | |
159 | refs/tags/pack | |
160 | ^refs/tags/kept | |
161 | EOF | |
162 | ) && | |
163 | ||
164 | # neither pack contains more than twice the number of objects in | |
165 | # the other, so they should be combined. but, marking one as | |
166 | # .kept on disk will "freeze" it, so the pack structure should | |
167 | # remain unchanged. | |
168 | touch $objdir/pack/pack-$KEPT.keep && | |
169 | ||
170 | find $objdir/pack -name "*.pack" | sort >before && | |
171 | git repack --geometric 2 -d && | |
172 | find $objdir/pack -name "*.pack" | sort >after && | |
173 | ||
174 | # both packs should still exist | |
175 | test_path_is_file $objdir/pack/pack-$KEPT.pack && | |
176 | test_path_is_file $objdir/pack/pack-$PACK.pack && | |
177 | ||
178 | # and no new packs should be created | |
179 | test_cmp before after && | |
180 | ||
181 | # Passing --pack-kept-objects causes packs with a .keep file to | |
182 | # be repacked, too. | |
183 | git repack --geometric 2 -d --pack-kept-objects && | |
184 | ||
197443e8 TB |
185 | # After repacking, two packs remain: one new one (containing the |
186 | # objects in both the .keep and non-kept pack), and the .keep | |
187 | # pack (since `--pack-kept-objects -d` does not actually delete | |
188 | # the kept pack). | |
0fabafd0 | 189 | find $objdir/pack -name "*.pack" >after && |
197443e8 | 190 | test_line_count = 2 after |
0fabafd0 TB |
191 | ) |
192 | ' | |
193 | ||
4b5a808b VD |
194 | test_expect_success '--geometric ignores --keep-pack packs' ' |
195 | git init geometric && | |
196 | test_when_finished "rm -fr geometric" && | |
197 | ( | |
198 | cd geometric && | |
199 | ||
200 | # Create two equal-sized packs | |
201 | test_commit kept && # 3 objects | |
202 | git repack -d && | |
203 | test_commit pack && # 3 objects | |
204 | git repack -d && | |
205 | ||
206 | find $objdir/pack -type f -name "*.pack" | sort >packs.before && | |
207 | git repack --geometric 2 -dm \ | |
208 | --keep-pack="$(basename "$(head -n 1 packs.before)")" >out && | |
209 | find $objdir/pack -type f -name "*.pack" | sort >packs.after && | |
210 | ||
211 | # Packs should not have changed (only one non-kept pack, no | |
212 | # loose objects), but $midx should now exist. | |
213 | grep "Nothing new to pack" out && | |
214 | test_path_is_file $midx && | |
215 | ||
216 | test_cmp packs.before packs.after && | |
217 | ||
218 | git fsck | |
219 | ) | |
220 | ' | |
221 | ||
6d08b9d4 TB |
222 | test_expect_success '--geometric chooses largest MIDX preferred pack' ' |
223 | git init geometric && | |
224 | test_when_finished "rm -fr geometric" && | |
225 | ( | |
226 | cd geometric && | |
227 | ||
228 | # These packs already form a geometric progression. | |
229 | test_commit_bulk --start=1 1 && # 3 objects | |
230 | test_commit_bulk --start=2 2 && # 6 objects | |
231 | ls $objdir/pack/pack-*.idx >before && | |
232 | test_commit_bulk --start=4 4 && # 12 objects | |
233 | ls $objdir/pack/pack-*.idx >after && | |
234 | ||
235 | git repack --geometric 2 -dbm && | |
236 | ||
237 | comm -3 before after | xargs -n 1 basename >expect && | |
238 | test-tool read-midx --preferred-pack $objdir >actual && | |
239 | ||
240 | test_cmp expect actual | |
241 | ) | |
242 | ' | |
243 | ||
66731ff9 | 244 | test_expect_success '--geometric with pack.packSizeLimit' ' |
aab7bea1 TB |
245 | git init pack-rewrite && |
246 | test_when_finished "rm -fr pack-rewrite" && | |
247 | ( | |
248 | cd pack-rewrite && | |
249 | ||
250 | test-tool genrandom foo 1048576 >foo && | |
251 | test-tool genrandom bar 1048576 >bar && | |
252 | ||
253 | git add foo bar && | |
254 | test_tick && | |
255 | git commit -m base && | |
256 | ||
257 | git rev-parse HEAD:foo HEAD:bar >p1.objects && | |
258 | git rev-parse HEAD HEAD^{tree} >p2.objects && | |
259 | ||
260 | # These two packs each contain two objects, so the following | |
261 | # `--geometric` repack will try to combine them. | |
262 | p1="$(git pack-objects $packdir/pack <p1.objects)" && | |
263 | p2="$(git pack-objects $packdir/pack <p2.objects)" && | |
264 | ||
265 | # Remove any loose objects in packs, since we do not want extra | |
266 | # copies around (which would mask over potential object | |
267 | # corruption issues). | |
268 | git prune-packed && | |
269 | ||
270 | # Both p1 and p2 will be rolled up, but pack-objects will write | |
271 | # three packs: | |
272 | # | |
273 | # - one containing object "foo", | |
274 | # - another containing object "bar", | |
275 | # - a final pack containing the commit and tree objects | |
276 | # (identical to p2 above) | |
277 | git repack --geometric 2 -d --max-pack-size=1048576 && | |
278 | ||
279 | # Ensure `repack` can detect that the third pack it wrote | |
280 | # (containing just the tree and commit objects) was identical to | |
281 | # one that was below the geometric split, so that we can save it | |
282 | # from deletion. | |
283 | # | |
284 | # If `repack` fails to do that, we will incorrectly delete p2, | |
285 | # causing object corruption. | |
286 | git fsck | |
287 | ) | |
288 | ' | |
289 | ||
3d74a233 PS |
290 | test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' ' |
291 | test_when_finished "rm -fr shared member" && | |
292 | ||
293 | # Create a shared repository that will serve as the alternate object | |
294 | # database for the member linked to it. It has got some objects on its | |
295 | # own that are packed into a single packfile. | |
296 | git init shared && | |
297 | test_commit -C shared common-object && | |
298 | git -C shared repack -ad && | |
299 | ||
300 | # We create member so that its alternates file points to the shared | |
301 | # repository. We then create a commit in it so that git-repack(1) has | |
302 | # something to repack. | |
303 | # of the shared object database. | |
304 | git clone --shared shared member && | |
305 | test_commit -C member unique-object && | |
306 | git -C member repack --geometric=2 --write-midx 2>err && | |
307 | test_must_be_empty err && | |
308 | ||
309 | # We should see that a new packfile was generated. | |
310 | find shared/.git/objects/pack -type f -name "*.pack" >packs && | |
311 | test_line_count = 1 packs && | |
312 | ||
313 | # We should also see a multi-pack-index. This multi-pack-index should | |
314 | # never refer to any packfiles in the alternate object database. | |
315 | test_path_is_file member/.git/objects/pack/multi-pack-index && | |
316 | test-tool read-midx member/.git/objects >packs.midx && | |
317 | grep "^pack-.*\.idx$" packs.midx | sort >actual && | |
318 | basename member/.git/objects/pack/pack-*.idx >expect && | |
319 | test_cmp expect actual | |
320 | ' | |
321 | ||
51861340 PS |
322 | test_expect_success '--geometric --with-midx with no local objects' ' |
323 | test_when_finished "rm -fr shared member" && | |
324 | ||
325 | # Create a repository with a single packfile that acts as alternate | |
326 | # object database. | |
327 | git init shared && | |
328 | test_commit -C shared "shared-objects" && | |
329 | git -C shared repack -ad && | |
330 | ||
331 | # Create a second repository linked to the first one and perform a | |
332 | # geometric repack on it. | |
333 | git clone --shared shared member && | |
334 | git -C member repack --geometric 2 --write-midx 2>err && | |
335 | test_must_be_empty err && | |
336 | ||
337 | # Assert that we wrote neither a new packfile nor a multi-pack-index. | |
338 | # We should not have a packfile because the single packfile in the | |
339 | # alternate object database does not invalidate the geometric sequence. | |
340 | # And we should not have a multi-pack-index because these only index | |
341 | # local packfiles, and there are none. | |
342 | test_dir_is_empty member/$packdir | |
343 | ' | |
344 | ||
732194b5 PS |
345 | test_expect_success '--geometric with same pack in main and alternate ODB' ' |
346 | test_when_finished "rm -fr shared member" && | |
347 | ||
348 | # Create a repository with a single packfile that acts as alternate | |
349 | # object database. | |
350 | git init shared && | |
351 | test_commit -C shared "shared-objects" && | |
352 | git -C shared repack -ad && | |
353 | ||
354 | # We create the member repository as an exact copy so that it has the | |
355 | # same packfile. | |
356 | cp -r shared member && | |
357 | test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates && | |
358 | find shared/.git/objects -type f >expected-files && | |
359 | ||
360 | # Verify that we can repack objects as expected without observing any | |
361 | # error. Having the same packfile in both ODBs used to cause an error | |
362 | # in git-pack-objects(1). | |
363 | git -C member repack --geometric 2 2>err && | |
364 | test_must_be_empty err && | |
365 | # Nothing should have changed. | |
366 | find shared/.git/objects -type f >actual-files && | |
367 | test_cmp expected-files actual-files | |
368 | ' | |
369 | ||
932c16c0 PS |
370 | test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' ' |
371 | test_when_finished "rm -fr shared member" && | |
372 | ||
373 | git init shared && | |
374 | test_commit_bulk -C shared --start=1 1 && | |
375 | ||
376 | git clone --shared shared member && | |
377 | test_commit_bulk -C member --start=2 1 && | |
378 | ||
379 | # Verify that our assumptions actually hold: both generated packfiles | |
380 | # should have three objects and should be non-equal. | |
381 | packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects && | |
382 | packed_objects member/.git/objects/pack/pack-*.idx >member-objects && | |
383 | test_line_count = 3 shared-objects && | |
384 | test_line_count = 3 member-objects && | |
385 | ! test_cmp shared-objects member-objects && | |
386 | ||
387 | # Perform the geometric repack. With `-l`, we should only see the local | |
388 | # packfile and thus arrive at the conclusion that the geometric | |
389 | # sequence is intact. We thus expect no changes. | |
390 | # | |
391 | # Note that we are tweaking mtimes of the packfiles so that we can | |
392 | # verify they did not change. This is done in order to detect the case | |
393 | # where we do repack objects, but the resulting packfile is the same. | |
394 | test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs && | |
395 | git -C member repack --geometric=2 -l -d && | |
396 | test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs && | |
397 | test_cmp expected-member-packs actual-member-packs && | |
398 | ||
399 | { | |
400 | packed_objects shared/.git/objects/pack/pack-*.idx && | |
401 | packed_objects member/.git/objects/pack/pack-*.idx | |
402 | } | sort >expected-objects && | |
403 | ||
404 | # On the other hand, when doing a non-local geometric repack we should | |
405 | # see both packfiles and thus repack them. We expect that the shared | |
406 | # object database was not changed. | |
407 | test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs && | |
408 | git -C member repack --geometric=2 -d && | |
409 | test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs && | |
410 | test_cmp expected-shared-packs actual-shared-packs && | |
411 | ||
412 | # Furthermore, we expect that the member repository now has a single | |
413 | # packfile that contains the combined shared and non-shared objects. | |
414 | ls member/.git/objects/pack/pack-*.idx >actual && | |
415 | test_line_count = 1 actual && | |
416 | packed_objects member/.git/objects/pack/pack-*.idx >actual-objects && | |
417 | test_line_count = 6 actual-objects && | |
418 | test_cmp expected-objects actual-objects | |
419 | ' | |
420 | ||
d85cd187 PS |
421 | test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' ' |
422 | test_when_finished "rm -fr shared member" && | |
423 | ||
424 | git init shared && | |
425 | test_commit_bulk -C shared --start=1 1 && | |
426 | ||
427 | git clone --shared shared member && | |
428 | test_commit_bulk -C member --start=2 1 && | |
429 | ||
430 | # When performing a geometric repack with `-l` while connected to an | |
431 | # alternate object database that has a packfile we do not have full | |
432 | # coverage of objects. As a result, we expect that writing the bitmap | |
433 | # will be disabled. | |
434 | git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err && | |
435 | cat >expect <<-EOF && | |
436 | warning: disabling bitmap writing, as some objects are not being packed | |
437 | EOF | |
438 | test_cmp expect err && | |
439 | test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap && | |
440 | ||
441 | # On the other hand, when we repack without `-l`, we should see that | |
442 | # the bitmap gets created. | |
443 | git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err && | |
444 | test_must_be_empty err && | |
445 | test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap | |
446 | ' | |
447 | ||
0fabafd0 | 448 | test_done |