Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
00c0d84
midx: mark `get_midx_checksum()` arguments as const
ttaylorr Feb 24, 2026
de811c2
midx: rename `get_midx_checksum()` to `midx_get_checksum_hash()`
ttaylorr Feb 24, 2026
6e86f67
midx: introduce `midx_get_checksum_hex()`
ttaylorr Feb 24, 2026
6b8fb17
builtin/multi-pack-index.c: make '--progress' a common option
ttaylorr Feb 24, 2026
f775d5b
git-multi-pack-index(1): remove non-existent incompatibility
ttaylorr Feb 24, 2026
d0e91c1
git-multi-pack-index(1): align SYNOPSIS with 'git multi-pack-index -h'
ttaylorr Feb 24, 2026
8043782
t/t5319-multi-pack-index.sh: fix copy-and-paste error in t5319.39
ttaylorr Feb 24, 2026
ac10f6a
midx-write.c: don't use `pack_perm` when assigning `bitmap_pos`
ttaylorr Feb 24, 2026
82c905e
midx-write.c: introduce `struct write_midx_opts`
ttaylorr Feb 24, 2026
b2ec8e9
midx: do not require packs to be sorted in lexicographic order
ttaylorr Feb 24, 2026
4f85432
midx-write.c: introduce `midx_pack_perm()` helper
ttaylorr Feb 24, 2026
5f3e7f7
midx-write.c: extract `fill_pack_from_midx()`
ttaylorr Feb 24, 2026
93c67df
midx-write.c: enumerate `pack_int_id` values directly
ttaylorr Feb 24, 2026
9aea84c
midx-write.c: factor fanout layering from `compute_sorted_entries()`
ttaylorr Feb 24, 2026
dedf71f
t/helper/test-read-midx.c: plug memory leak when selecting layer
ttaylorr Feb 24, 2026
9df44a9
midx: implement MIDX compaction
ttaylorr Feb 24, 2026
d54da84
midx: enable reachability bitmaps during MIDX compaction
ttaylorr Feb 24, 2026
6cdef94
Merge branch 'ps/odb-sources' into ps/object-counting
gitster Mar 10, 2026
6daeb66
odb: stop including "odb/source.h"
pks-t Mar 12, 2026
dd587cd
packfile: extract logic to count number of objects
pks-t Mar 12, 2026
222fdde
object-file: extract logic to approximate object count
pks-t Mar 12, 2026
2b24db1
object-file: generalize counting objects
pks-t Mar 12, 2026
b259f21
odb/source: introduce generic object counting
pks-t Mar 12, 2026
6801ffd
odb: introduce generic object counting
pks-t Mar 12, 2026
105a22c
Merge branch 'tb/incremental-midx-part-3.2'
gitster Mar 25, 2026
8e2964d
Merge branch 'ps/object-counting'
gitster Mar 25, 2026
41688c1
The 21st batch
gitster Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Documentation/RelNotes/2.54.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ Performance, Internal Implementation, Development Support etc.
* Add a coccinelle rule to break the build when "struct strbuf" gets
passed by value.
* Further work on incremental repacking using MIDX/bitmap
* The logic to count objects has been cleaned up.
Fixes since v2.53
-----------------
Expand Down
27 changes: 25 additions & 2 deletions Documentation/git-multi-pack-index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ git-multi-pack-index - Write and verify multi-pack-indexes
SYNOPSIS
--------
[verse]
'git multi-pack-index' [--object-dir=<dir>] [--[no-]bitmap] <sub-command>
'git multi-pack-index' [<options>] write [--preferred-pack=<pack>]
[--[no-]bitmap] [--[no-]incremental] [--[no-]stdin-packs]
[--refs-snapshot=<path>]
'git multi-pack-index' [<options>] compact [--[no-]incremental]
[--[no-]bitmap] <from> <to>
'git multi-pack-index' [<options>] verify
'git multi-pack-index' [<options>] expire
'git multi-pack-index' [<options>] repack [--batch-size=<size>]

DESCRIPTION
-----------
Expand All @@ -18,6 +25,8 @@ Write or verify a multi-pack-index (MIDX) file.
OPTIONS
-------

The following command-line options are applicable to all sub-commands:

--object-dir=<dir>::
Use given directory for the location of Git objects. We check
`<dir>/packs/multi-pack-index` for the current MIDX file, and
Expand Down Expand Up @@ -73,7 +82,21 @@ marker).
Write an incremental MIDX file containing only objects
and packs not present in an existing MIDX layer.
Migrates non-incremental MIDXs to incremental ones when
necessary. Incompatible with `--bitmap`.
necessary.
--

compact::
Write a new MIDX layer containing only objects and packs present
in the range `<from>` to `<to>`, where both arguments are
checksums of existing layers in the MIDX chain.
+
--
--incremental::
Write the result to a MIDX chain instead of writing a
stand-alone MIDX.

--[no-]bitmap::
Control whether or not a multi-pack bitmap is written.
--

verify::
Expand Down
8 changes: 6 additions & 2 deletions Documentation/gitformat-pack.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ HEADER:
The signature is: {'M', 'I', 'D', 'X'}

1-byte version number:
Git only writes or recognizes version 1.
Git writes the version specified by the "midx.version"
configuration option, which defaults to 2. It recognizes
both versions 1 and 2.

1-byte Object Id Version
We infer the length of object IDs (OIDs) from this value:
Expand Down Expand Up @@ -413,7 +415,9 @@ CHUNK DATA:
strings. There is no extra padding between the filenames,
and they are listed in lexicographic order. The chunk itself
is padded at the end with between 0 and 3 NUL bytes to make the
chunk size a multiple of 4 bytes.
chunk size a multiple of 4 bytes. Version 1 MIDXs are required to
list their packs in lexicographic order, but version 2 MIDXs may
list their packs in any arbitrary order.

Bitmapped Packfiles (ID: {'B', 'T', 'M', 'P'})
Stores a table of two 4-byte unsigned integers in network order.
Expand Down
44 changes: 15 additions & 29 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,37 +467,19 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
static int too_many_loose_objects(int limit)
{
/*
* Quickly check if a "gc" is needed, by estimating how
* many loose objects there are. Because SHA-1 is evenly
* distributed, we can check only one and get a reasonable
* estimate.
* This is weird, but stems from legacy behaviour: the GC auto
* threshold was always essentially interpreted as if it was rounded up
* to the next multiple 256 of, so we retain this behaviour for now.
*/
DIR *dir;
struct dirent *ent;
int auto_threshold;
int num_loose = 0;
int needed = 0;
const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
char *path;

path = repo_git_path(the_repository, "objects/17");
dir = opendir(path);
free(path);
if (!dir)
int auto_threshold = DIV_ROUND_UP(limit, 256) * 256;
unsigned long loose_count;

if (odb_source_loose_count_objects(the_repository->objects->sources,
ODB_COUNT_OBJECTS_APPROXIMATE,
&loose_count) < 0)
return 0;

auto_threshold = DIV_ROUND_UP(limit, 256);
while ((ent = readdir(dir)) != NULL) {
if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
ent->d_name[hexsz_loose] != '\0')
continue;
if (++num_loose > auto_threshold) {
needed = 1;
break;
}
}
closedir(dir);
return needed;
return loose_count > auto_threshold;
}

static struct packed_git *find_base_packs(struct string_list *packs,
Expand Down Expand Up @@ -592,9 +574,13 @@ static uint64_t total_ram(void)
static uint64_t estimate_repack_memory(struct gc_config *cfg,
struct packed_git *pack)
{
unsigned long nr_objects = repo_approximate_object_count(the_repository);
unsigned long nr_objects;
size_t os_cache, heap;

if (odb_count_objects(the_repository->objects,
ODB_COUNT_OBJECTS_APPROXIMATE, &nr_objects) < 0)
return 0;

if (!pack || !nr_objects)
return 0;

Expand Down
92 changes: 82 additions & 10 deletions builtin/multi-pack-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
#include "strbuf.h"
#include "trace2.h"
#include "odb.h"
#include "odb/source.h"
#include "replace-object.h"
#include "repository.h"

#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
"[--refs-snapshot=<path>]")
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]\n" \
" [--[no-]bitmap] [--[no-]incremental] [--[no-]stdin-packs]\n" \
" [--refs-snapshot=<path>]")

#define BUILTIN_MIDX_COMPACT_USAGE \
N_("git multi-pack-index [<options>] compact [--[no-]incremental]\n" \
" [--[no-]bitmap] <from> <to>")

#define BUILTIN_MIDX_VERIFY_USAGE \
N_("git multi-pack-index [<options>] verify")
Expand All @@ -29,6 +35,10 @@ static char const * const builtin_multi_pack_index_write_usage[] = {
BUILTIN_MIDX_WRITE_USAGE,
NULL
};
static char const * const builtin_multi_pack_index_compact_usage[] = {
BUILTIN_MIDX_COMPACT_USAGE,
NULL
};
static char const * const builtin_multi_pack_index_verify_usage[] = {
BUILTIN_MIDX_VERIFY_USAGE,
NULL
Expand All @@ -43,6 +53,7 @@ static char const * const builtin_multi_pack_index_repack_usage[] = {
};
static char const * const builtin_multi_pack_index_usage[] = {
BUILTIN_MIDX_WRITE_USAGE,
BUILTIN_MIDX_COMPACT_USAGE,
BUILTIN_MIDX_VERIFY_USAGE,
BUILTIN_MIDX_EXPIRE_USAGE,
BUILTIN_MIDX_REPACK_USAGE,
Expand Down Expand Up @@ -84,6 +95,8 @@ static struct option common_opts[] = {
N_("directory"),
N_("object directory containing set of packfile and pack-index pairs"),
parse_object_dir),
OPT_BIT(0, "progress", &opts.flags, N_("force progress reporting"),
MIDX_PROGRESS),
OPT_END(),
};

Expand Down Expand Up @@ -138,8 +151,6 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
N_("pack for reuse when computing a multi-pack bitmap")),
OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_BIT(0, "incremental", &opts.flags,
N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
Expand Down Expand Up @@ -194,14 +205,78 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
return ret;
}

static int cmd_multi_pack_index_compact(int argc, const char **argv,
const char *prefix,
struct repository *repo)
{
struct multi_pack_index *m, *cur;
struct multi_pack_index *from_midx = NULL;
struct multi_pack_index *to_midx = NULL;
struct odb_source *source;
int ret;

struct option *options;
static struct option builtin_multi_pack_index_compact_options[] = {
OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BIT(0, "incremental", &opts.flags,
N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_END(),
};

repo_config(repo, git_multi_pack_index_write_config, NULL);

options = add_common_options(builtin_multi_pack_index_compact_options);

trace2_cmd_mode(argv[0]);

if (isatty(2))
opts.flags |= MIDX_PROGRESS;
argc = parse_options(argc, argv, prefix,
options, builtin_multi_pack_index_compact_usage,
0);

if (argc != 2)
usage_with_options(builtin_multi_pack_index_compact_usage,
options);
source = handle_object_dir_option(the_repository);

FREE_AND_NULL(options);

m = get_multi_pack_index(source);

for (cur = m; cur && !(from_midx && to_midx); cur = cur->base_midx) {
const char *midx_csum = midx_get_checksum_hex(cur);

if (!from_midx && !strcmp(midx_csum, argv[0]))
from_midx = cur;
if (!to_midx && !strcmp(midx_csum, argv[1]))
to_midx = cur;
}

if (!from_midx)
die(_("could not find MIDX: %s"), argv[0]);
if (!to_midx)
die(_("could not find MIDX: %s"), argv[1]);
if (from_midx == to_midx)
die(_("MIDX compaction endpoints must be unique"));

for (m = from_midx; m; m = m->base_midx) {
if (m == to_midx)
die(_("MIDX %s must be an ancestor of %s"), argv[0], argv[1]);
}

ret = write_midx_file_compact(source, from_midx, to_midx, opts.flags);

return ret;
}

static int cmd_multi_pack_index_verify(int argc, const char **argv,
const char *prefix,
struct repository *repo UNUSED)
{
struct option *options;
static struct option builtin_multi_pack_index_verify_options[] = {
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
struct odb_source *source;
Expand Down Expand Up @@ -231,8 +306,6 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv,
{
struct option *options;
static struct option builtin_multi_pack_index_expire_options[] = {
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
struct odb_source *source;
Expand Down Expand Up @@ -264,8 +337,6 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
static struct option builtin_multi_pack_index_repack_options[] = {
OPT_UNSIGNED(0, "batch-size", &opts.batch_size,
N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
struct odb_source *source;
Expand Down Expand Up @@ -300,6 +371,7 @@ int cmd_multi_pack_index(int argc,
struct option builtin_multi_pack_index_options[] = {
OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
OPT_SUBCOMMAND("compact", &fn, cmd_multi_pack_index_compact),
OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
OPT_END(),
Expand Down
1 change: 1 addition & 0 deletions builtin/submodule--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
#include "odb/source.h"
#include "advice.h"
#include "branch.h"
#include "list-objects-filter-options.h"
Expand Down
3 changes: 2 additions & 1 deletion commit-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -2607,7 +2607,8 @@ int write_commit_graph(struct odb_source *source,
replace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
}

ctx.approx_nr_objects = repo_approximate_object_count(r);
if (odb_count_objects(r->objects, ODB_COUNT_OBJECTS_APPROXIMATE, &ctx.approx_nr_objects) < 0)
ctx.approx_nr_objects = 0;

if (ctx.append && g) {
for (i = 0; i < g->num_commits; i++) {
Expand Down
Loading