Faster repository maintenance with chained MIDX layers
Multi-pack indexes (MIDXs) have been part of Git since 2.21, solving the problem of slow object lookups in repositories that have accumulated many packfiles. Rather than forcing a full repack to consolidate everything into one pack—an expensive operation—a MIDX records which pack contains each object and where within that pack it lives, allowing Git to answer object lookups quickly without consolidating packs first.
But maintaining a MIDX has its own cost. Every time new packs are added, Git must scan all objects in all packs covered by the MIDX to update the index. If you also use multi-pack reachability bitmaps, the update cost grows further due to the additional traversals those bitmaps require.
Git 2.47 introduces experimental incremental multi-pack indexes to address this. Instead of rewriting a single MIDX from scratch, Git can maintain a chain of MIDX layers. Each new layer only contains packs and objects that weren't in earlier layers, so appending to the chain takes time proportional to the newly added objects alone, not the entire repository size.

This figure illustrates a MIDX with its colored object entries pointing to the source pack and offset for each object.

The second figure shows how an incremental layer fits into the chain: new objects are recorded in the additional layer, even though some source packs in that layer overlap with objects already covered by earlier layers.
The feature is still marked experimental, and it does not yet work with multi-pack reachability bitmaps. Support for that combination is under review and could land in a subsequent release.
To try incremental multi-pack indexes today, you can add new packs to your repository's existing MIDX with:
$ git multi-pack-index write --incremental
Finding a branch’s origin with for-each-ref
Identifying the branch a given commit originally came from has historically been awkward. A practical heuristic is to find the branch that minimizes the number of first-parent commits unique to the target commit—that is, commits reachable only by following merge commits’ first parents. This effectively finds the branch whose mainline history is closest to the commit in question.
A naïve approach using git rev-list --count --first-parent doesn’t work because rev-list strips out commits reachable from the candidate base. Git 2.47 adds a dedicated mechanism through a new %(is-base:<commit>) atom for for-each-ref‘s --format option. Even when a commit has been merged into many branches, this atom can identify the original source branch reliably:
$ needle=fcb2205b77470c60f996a3206b2d4aebf6e951e3
$ git for-each-ref --contains $needle refs/remotes/origin | wc -l
63
$ git for-each-ref --format="%(refname) %(is-base:$needle)" refs/remotes/origin \
| grep '('
refs/remotes/origin/tb/incremental-midx-part-1 (fcb2205b77470c60f996a3206b2d4aebf6e951e3)
Formal platform support policy
Git has long run on a wide range of systems, but until now there was no formal statement of what that support means. The new “Platform Support Policy” document in the repository sets the baseline: platforms must offer C99 or C11, rely on dependency versions that are stable or under long-term support, and maintain an active security support process. The document also gives platform maintainers guidance on which branches to test and how to report or fix compatibility problems. Discussion continues on whether to tighten requirements further—including the possibility of requiring Rust in a future release.
Reference backend progress
The reftable reference backend, first introduced experimentally a few releases ago, received a batch of improvements in 2.47. Unit tests written in reftable’s custom framework were migrated to Git’s standard unit test harness, work done by Google Summer of Code contributor Chandra Pratap. Concurrency handling was also improved, particularly around stack compaction with multiple writers. In addition, reftable now honors the --exclude option in git for-each-ref, a feature that has been available for the traditional backend since Git 2.42.
More thorough unit testing
Beyond reftable, several other subsystems moved from Shell-based integration tests to proper unit tests, including the hashmap API, OID array, and URL-match normalization code. The test framework itself was overhauled to adopt the Clar framework, originally created for libgit2. Much of this conversion work came from Ghanshyam Thakkar, another GSoC contributor.
Integrity checking also expanded. A new git refs verify subcommand, contributed by GSoC student shejialuo, now runs as part of git fsck and checks the reference storage backend for corruption alongside the existing object store checks.
Cleaner code and fewer leaks
Long-running cleanup efforts also came to fruition. Annotating unused function parameters has been an ongoing project since at least 2019, and in this release it reached a milestone: with DEVELOPER=1 builds, -Wunused-parameter is now a compile-time error. Any newly introduced unused parameters will be caught immediately, reducing risk of subtle bugs.
Similarly, the multi-release campaign to eliminate memory leaks continues. The rationale is the same as when it began with Git 2.34: although Git processes are typically short-lived and the OS reclaims memory on exit, the codebase is being reshaped toward use as a callable library, where leaks become far more consequential. This release includes another round of plugging leaks across the project.
Mergetool support for VS Code
git mergetool gains a built-in configuration for Visual Studio Code’s three-way merge resolver. Previously this required manual setup; now a simple command configures the repository:
$ git config set merge.tool vscode
After that, invoking git mergetool will automatically launch VS Code with the correct merge layout.
The rest of Git 2.47
These are only the most notable changes in the release. Full details are available in the 2.47 release notes, and notes for earlier versions live in the same directory in the Git repository.



