Skip to content

Commit 3d74a23

Browse files
pks-tgitster
authored andcommitted
repack: fix trying to use preferred pack in alternates
When doing a geometric repack with multi-pack-indices, then we ask git-multi-pack-index(1) to use the largest packfile as the preferred pack. It can happen though that the largest packfile is not part of the main object database, but instead part of an alternate object database. The result is that git-multi-pack-index(1) will not be able to find the preferred pack and print a warning. It then falls back to use the first packfile that the multi-pack-index shall reference. Fix this bug by only considering packfiles as preferred pack that are local. This is the right thing to do given that a multi-pack-index should never reference packfiles borrowed from an alternate. While at it, rename the function `get_largest_active_packfile()` to `get_preferred_pack()` to better document its intent. Helped-by: Taylor Blau <[email protected]> Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ceb96a1 commit 3d74a23

File tree

2 files changed

+53
-5
lines changed

2 files changed

+53
-5
lines changed

builtin/repack.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
444444
geometry->split = split;
445445
}
446446

447-
static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry)
447+
static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
448448
{
449+
uint32_t i;
450+
449451
if (!geometry) {
450452
/*
451453
* No geometry means either an all-into-one repack (in which
@@ -460,7 +462,21 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry
460462
}
461463
if (geometry->split == geometry->pack_nr)
462464
return NULL;
463-
return geometry->pack[geometry->pack_nr - 1];
465+
466+
/*
467+
* The preferred pack is the largest pack above the split line. In
468+
* other words, it is the largest pack that does not get rolled up in
469+
* the geometric repack.
470+
*/
471+
for (i = geometry->pack_nr; i > geometry->split; i--)
472+
/*
473+
* A pack that is not local would never be included in a
474+
* multi-pack index. We thus skip over any non-local packs.
475+
*/
476+
if (geometry->pack[i - 1]->pack_local)
477+
return geometry->pack[i - 1];
478+
479+
return NULL;
464480
}
465481

466482
static void clear_pack_geometry(struct pack_geometry *geometry)
@@ -587,7 +603,7 @@ static int write_midx_included_packs(struct string_list *include,
587603
{
588604
struct child_process cmd = CHILD_PROCESS_INIT;
589605
struct string_list_item *item;
590-
struct packed_git *largest = get_largest_active_pack(geometry);
606+
struct packed_git *preferred = get_preferred_pack(geometry);
591607
FILE *in;
592608
int ret;
593609

@@ -608,9 +624,9 @@ static int write_midx_included_packs(struct string_list *include,
608624
if (write_bitmaps)
609625
strvec_push(&cmd.args, "--bitmap");
610626

611-
if (largest)
627+
if (preferred)
612628
strvec_pushf(&cmd.args, "--preferred-pack=%s",
613-
pack_basename(largest));
629+
pack_basename(preferred));
614630

615631
if (refs_snapshot)
616632
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);

t/t7703-repack-geometric.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,36 @@ test_expect_success '--geometric with pack.packSizeLimit' '
281281
)
282282
'
283283

284+
test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' '
285+
test_when_finished "rm -fr shared member" &&
286+
287+
# Create a shared repository that will serve as the alternate object
288+
# database for the member linked to it. It has got some objects on its
289+
# own that are packed into a single packfile.
290+
git init shared &&
291+
test_commit -C shared common-object &&
292+
git -C shared repack -ad &&
293+
294+
# We create member so that its alternates file points to the shared
295+
# repository. We then create a commit in it so that git-repack(1) has
296+
# something to repack.
297+
# of the shared object database.
298+
git clone --shared shared member &&
299+
test_commit -C member unique-object &&
300+
git -C member repack --geometric=2 --write-midx 2>err &&
301+
test_must_be_empty err &&
302+
303+
# We should see that a new packfile was generated.
304+
find shared/.git/objects/pack -type f -name "*.pack" >packs &&
305+
test_line_count = 1 packs &&
306+
307+
# We should also see a multi-pack-index. This multi-pack-index should
308+
# never refer to any packfiles in the alternate object database.
309+
test_path_is_file member/.git/objects/pack/multi-pack-index &&
310+
test-tool read-midx member/.git/objects >packs.midx &&
311+
grep "^pack-.*\.idx$" packs.midx | sort >actual &&
312+
basename member/.git/objects/pack/pack-*.idx >expect &&
313+
test_cmp expect actual
314+
'
315+
284316
test_done

0 commit comments

Comments
 (0)