Git 2.45
[git/gitster.git] / t / t7703-repack-geometric.sh
blob9fc1626fbfde8989348537903a266eb6cae8600d
1 #!/bin/sh
3 test_description='git repack --geometric works correctly'
5 . ./test-lib.sh
7 GIT_TEST_MULTI_PACK_INDEX=0
9 objdir=.git/objects
10 packdir=$objdir/pack
11 midx=$objdir/pack/multi-pack-index
13 packed_objects () {
14 git show-index <"$1" >tmp-object-list &&
15 cut -d' ' -f2 tmp-object-list | sort &&
16 rm tmp-object-list
19 test_expect_success '--geometric with no packs' '
20 git init geometric &&
21 test_when_finished "rm -fr geometric" &&
23 cd geometric &&
25 git repack --write-midx --geometric 2 >out &&
26 test_grep "Nothing new to pack" out
30 test_expect_success '--geometric with one pack' '
31 git init geometric &&
32 test_when_finished "rm -fr geometric" &&
34 cd geometric &&
36 test_commit "base" &&
37 git repack -d &&
39 git repack --geometric 2 >out &&
41 test_grep "Nothing new to pack" out
45 test_expect_success '--geometric with an intact progression' '
46 git init geometric &&
47 test_when_finished "rm -fr geometric" &&
49 cd geometric &&
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
56 find $objdir/pack -name "*.pack" | sort >expect &&
57 git repack --geometric 2 -d &&
58 find $objdir/pack -name "*.pack" | sort >actual &&
60 test_cmp expect actual
64 test_expect_success '--geometric with loose objects' '
65 git init geometric &&
66 test_when_finished "rm -fr geometric" &&
68 cd geometric &&
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
77 find $objdir/pack -name "*.pack" | sort >before &&
78 git repack --geometric 2 -d &&
79 find $objdir/pack -name "*.pack" | sort >after &&
81 comm -13 before after >new &&
82 comm -23 before after >removed &&
84 test_line_count = 1 new &&
85 test_must_be_empty removed &&
87 git repack --geometric 2 -d &&
88 find $objdir/pack -name "*.pack" | sort >after &&
90 # The progression (3, 3, 6) is combined into one new pack.
91 test_line_count = 1 after
95 test_expect_success '--geometric with small-pack rollup' '
96 git init geometric &&
97 test_when_finished "rm -fr geometric" &&
99 cd geometric &&
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 &&
108 git repack --geometric 2 -d &&
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
119 test_expect_success '--geometric with small- and large-pack rollup' '
120 git init geometric &&
121 test_when_finished "rm -fr geometric" &&
123 cd geometric &&
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 &&
131 find $objdir/pack -name "*.pack" | sort >before &&
133 git repack --geometric 2 -d &&
135 find $objdir/pack -name "*.pack" | sort >after &&
136 comm -12 before after >untouched &&
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
145 test_expect_success '--geometric ignores kept packs' '
146 git init geometric &&
147 test_when_finished "rm -fr geometric" &&
149 cd geometric &&
151 test_commit kept && # 3 objects
152 test_commit pack && # 3 objects
154 KEPT=$(git pack-objects --revs $objdir/pack/pack <<-EOF
155 refs/tags/kept
157 ) &&
158 PACK=$(git pack-objects --revs $objdir/pack/pack <<-EOF
159 refs/tags/pack
160 ^refs/tags/kept
162 ) &&
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 &&
170 find $objdir/pack -name "*.pack" | sort >before &&
171 git repack --geometric 2 -d &&
172 find $objdir/pack -name "*.pack" | sort >after &&
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 &&
178 # and no new packs should be created
179 test_cmp before after &&
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 &&
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
194 test_expect_success '--geometric ignores --keep-pack packs' '
195 git init geometric &&
196 test_when_finished "rm -fr geometric" &&
198 cd geometric &&
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 &&
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 &&
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 &&
216 test_cmp packs.before packs.after &&
218 git fsck
222 test_expect_success '--geometric chooses largest MIDX preferred pack' '
223 git init geometric &&
224 test_when_finished "rm -fr geometric" &&
226 cd geometric &&
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 &&
235 git repack --geometric 2 -dbm &&
237 comm -3 before after | xargs -n 1 basename >expect &&
238 test-tool read-midx --preferred-pack $objdir >actual &&
240 test_cmp expect actual
244 test_expect_success '--geometric with pack.packSizeLimit' '
245 git init pack-rewrite &&
246 test_when_finished "rm -fr pack-rewrite" &&
248 cd pack-rewrite &&
250 test-tool genrandom foo 1048576 >foo &&
251 test-tool genrandom bar 1048576 >bar &&
253 git add foo bar &&
254 test_tick &&
255 git commit -m base &&
257 git rev-parse HEAD:foo HEAD:bar >p1.objects &&
258 git rev-parse HEAD HEAD^{tree} >p2.objects &&
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)" &&
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 &&
270 # Both p1 and p2 will be rolled up, but pack-objects will write
271 # three packs:
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 &&
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.
284 # If `repack` fails to do that, we will incorrectly delete p2,
285 # causing object corruption.
286 git fsck
290 test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' '
291 test_when_finished "rm -fr shared member" &&
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 &&
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 &&
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 &&
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
322 test_expect_success '--geometric --with-midx with no local objects' '
323 test_when_finished "rm -fr shared member" &&
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 &&
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 &&
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
345 test_expect_success '--geometric with same pack in main and alternate ODB' '
346 test_when_finished "rm -fr shared member" &&
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 &&
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 &&
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
370 test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' '
371 test_when_finished "rm -fr shared member" &&
373 git init shared &&
374 test_commit_bulk -C shared --start=1 1 &&
376 git clone --shared shared member &&
377 test_commit_bulk -C member --start=2 1 &&
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 &&
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.
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 &&
400 packed_objects shared/.git/objects/pack/pack-*.idx &&
401 packed_objects member/.git/objects/pack/pack-*.idx
402 } | sort >expected-objects &&
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 &&
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
421 test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' '
422 test_when_finished "rm -fr shared member" &&
424 git init shared &&
425 test_commit_bulk -C shared --start=1 1 &&
427 git clone --shared shared member &&
428 test_commit_bulk -C member --start=2 1 &&
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
438 test_cmp expect err &&
439 test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap &&
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
448 test_done