`incremental`;;
Write an incremental MIDX chain instead of a single
- flat MIDX. This mode requires `--geometric`.
+ flat MIDX.
+
-The incremental mode maintains a chain of MIDX layers that is compacted
-over time using a geometric merging strategy. Each repack creates a new
-tip layer containing the newly written pack(s). Adjacent layers are then
-merged whenever the newer layer's object count exceeds
-`1/repack.midxSplitFactor` of the next deeper layer's count. Layers
-that do not meet this condition are retained as-is.
+Without `--geometric`, a new MIDX layer is appended to the existing
+chain (or a new chain is started) containing whatever packs were written
+by the repack. Existing layers are preserved as-is.
++
+When combined with `--geometric`, the incremental mode maintains a chain
+of MIDX layers that is compacted over time using a geometric merging
+strategy. Each repack creates a new tip layer containing the newly
+written pack(s). Adjacent layers are then merged whenever the newer
+layer's object count exceeds `1/repack.midxSplitFactor` of the next
+deeper layer's count. Layers that do not meet this condition are
+retained as-is.
+
The result is that newer (tip) layers tend to contain many small packs
with relatively few objects, while older (deeper) layers contain fewer,
if (pack_everything & PACK_CRUFT)
pack_everything |= ALL_INTO_ONE;
- if (write_midx == REPACK_WRITE_MIDX_INCREMENTAL && !geometry.split_factor)
- die(_("--write-midx=incremental requires --geometric"));
-
if (write_bitmaps < 0) {
if (write_midx == REPACK_WRITE_MIDX_NONE &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
free(step->csum);
}
+/*
+ * Build an append-only MIDX plan: a single WRITE step for the freshly
+ * written packs, plus COPY steps for every existing layer. No
+ * compaction or merging is performed.
+ */
+static void repack_make_midx_append_plan(struct repack_write_midx_opts *opts,
+ struct midx_compaction_step **steps_p,
+ size_t *steps_nr_p)
+{
+ struct multi_pack_index *m;
+ struct midx_compaction_step *steps = NULL;
+ struct midx_compaction_step *step;
+ size_t steps_nr = 0, steps_alloc = 0;
+
+ odb_reprepare(opts->existing->repo->objects);
+ m = get_multi_pack_index(opts->existing->source);
+
+ if (opts->names->nr) {
+ struct strbuf buf = STRBUF_INIT;
+ uint32_t i;
+
+ ALLOC_GROW(steps, st_add(steps_nr, 1), steps_alloc);
+
+ step = &steps[steps_nr++];
+ memset(step, 0, sizeof(*step));
+
+ step->type = MIDX_COMPACTION_STEP_WRITE;
+ string_list_init_dup(&step->u.write);
+
+ for (i = 0; i < opts->names->nr; i++) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "pack-%s.idx",
+ opts->names->items[i].string);
+ string_list_append(&step->u.write, buf.buf);
+ }
+
+ strbuf_release(&buf);
+ }
+
+ for (; m; m = m->base_midx) {
+ ALLOC_GROW(steps, st_add(steps_nr, 1), steps_alloc);
+
+ step = &steps[steps_nr++];
+ memset(step, 0, sizeof(*step));
+
+ step->type = MIDX_COMPACTION_STEP_COPY;
+ step->u.copy = m;
+ step->objects_nr = m->num_objects;
+ }
+
+ *steps_p = steps;
+ *steps_nr_p = steps_nr;
+}
+
static int repack_make_midx_compaction_plan(struct repack_write_midx_opts *opts,
struct midx_compaction_step **steps_p,
size_t *steps_nr_p)
goto done;
}
- if (repack_make_midx_compaction_plan(opts, &steps, &steps_nr) < 0) {
- ret = error(_("unable to generate compaction plan"));
- goto done;
+ if (opts->geometry->split_factor) {
+ if (repack_make_midx_compaction_plan(opts, &steps, &steps_nr) < 0) {
+ ret = error(_("unable to generate compaction plan"));
+ goto done;
+ }
+ } else {
+ repack_make_midx_append_plan(opts, &steps, &steps_nr);
}
for (i = 0; i < steps_nr; i++) {
done
}
-test_expect_success '--write-midx=incremental requires --geometric' '
- test_must_fail git repack --write-midx=incremental 2>err &&
+test_expect_success '--write-midx=incremental without --geometric' '
+ git init incremental-without-geometric &&
+ (
+ cd incremental-without-geometric &&
+
+ git config maintenance.auto false &&
+
+ test_commit first &&
+ git repack -d &&
- test_grep -- "--write-midx=incremental requires --geometric" err
+ test_commit second &&
+ git repack --write-midx=incremental &&
+
+ git multi-pack-index verify &&
+ test_line_count = 1 $midx_chain &&
+ cp $midx_chain $midx_chain.before &&
+
+ # A second repack appends a new layer without
+ # disturbing the existing one.
+ test_commit third &&
+ git repack --write-midx=incremental &&
+
+ git multi-pack-index verify &&
+ test_line_count = 2 $midx_chain &&
+ head -n 1 $midx_chain.before >expect &&
+ head -n 1 $midx_chain >actual &&
+ test_cmp expect actual &&
+
+ git fsck
+ )
'
test_expect_success 'below layer threshold, tip packs excluded' '
# entirely, so no rollup occurs as there is only one
# non-kept pack. A new MIDX layer is written containing
# that pack.
- git repack --geometric=2 -d --write-midx=incremental \
- --write-bitmap-index &&
+ git repack --geometric=2 -d --write-midx=incremental &&
test-tool read-midx $objdir >actual &&
grep "^pack-.*\.idx$" actual >actual.packs &&
)
'
+test_expect_success 'repack -ad --write-midx=incremental is safe' '
+ git init ad-incremental-midx &&
+ (
+ cd ad-incremental-midx &&
+
+ git config maintenance.auto false &&
+
+ # Build a MIDX chain with multiple layers referencing
+ # distinct packs.
+ test_commit first &&
+ git repack -d &&
+
+ test_commit second &&
+ git repack -d --write-midx=incremental &&
+
+ git multi-pack-index verify &&
+ test_line_count = 1 $midx_chain &&
+
+ # Now do a full -ad repack. The new pack contains all
+ # objects, but any retained MIDX layers still reference
+ # the now-deleted packs.
+ test_commit third &&
+ git repack -ad --write-midx=incremental &&
+
+ git multi-pack-index verify &&
+ git fsck &&
+ git rev-list --all --objects >/dev/null
+ )
+'
+
test_expect_success 'repack rejects invalid midxSplitFactor' '
test_when_finished "rm -fr bad-split-factor" &&
git init bad-split-factor &&