]> git.ipfire.org Git - thirdparty/git.git/blob - t/t7703-repack-geometric.sh
The third batch
[thirdparty/git.git] / t / t7703-repack-geometric.sh
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
10 packdir=$objdir/pack
11 midx=$objdir/pack/multi-pack-index
12
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
19 test_expect_success '--geometric with no packs' '
20 git init geometric &&
21 test_when_finished "rm -fr geometric" &&
22 (
23 cd geometric &&
24
25 git repack --write-midx --geometric 2 >out &&
26 test_grep "Nothing new to pack" out
27 )
28 '
29
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_grep "Nothing new to pack" out
42 )
43 '
44
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
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
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
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).
189 find $objdir/pack -name "*.pack" >after &&
190 test_line_count = 2 after
191 )
192 '
193
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
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
244 test_expect_success '--geometric with pack.packSizeLimit' '
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
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
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
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
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
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
448 test_done