Git 2.51 keeps cruft packs out of the MIDX
For repositories that use both multi-pack indexes (MIDXs) and cruft packs, this release changes how the non-cruft portion gets packed. Previously, when creating a new pack, Git would exclude any object that also appeared in a pack that would not be deleted during repack——including cruft packs. Because cruft packs hold unreachable objects, the MIDX never accounted for them. The problem arose when an unreachable object in a cruft pack later became reachable from a bitmapped commit: since that object had no bit position in the MIDX, writing a reachability bitmap became impossible.
Git 2.51 now stores additional copies of objects (and their ancestors) when the only other copy lives in a cruft pack. Repeating this process guarantees that the non-cruft pack set is closed under reachability—no object in those packs points to an object outside them. That makes the new repack.MIDXMustContainCruft configuration possible, which lets cruft packs stay outside the MIDX entirely. In GitHub's primary monorepo, MIDXs shrunk by roughly 38%, got written 35% faster, and read performance improved by about 5%.
Path walk packs objects by path instead of revision
Since Git 2.49, packing has used "name-hash v2" to pick delta-compression pairs: Git hashes each object's filepath, sorts objects by that hash, then slides a window across the sorted list hunting for good delta bases. That was an improvement over the older single hash function from 2006, which over-weighted the last 16 characters of a path and could misfire when unrelated blobs shared similar path suffixes. The new hash in 2.49 took more of the directory tree into account and occasionally produced noticeably smaller packs.
Git 2.51 goes further with a new "path walk" collection mode. Instead of emitting objects in revision order with their names along the way, Git emits all objects belonging to a given path at once. That removes the name-hash heuristic altogether: delta search happens among objects known to share a path. Packs built this way are often significantly smaller than those from even the new name-hash function, while packing time stays competitive with traditional revision-order traversal. The new behavior is available through the --path-walk option to git repack.
Stash entries get an interchange format
Internally, each stash entry is a small graph of commits: one capturing the index state, another for the working directory, and a third commit whose parents are those two, representing the full snapshot. These get stored in the refs/stash ref with the reflog managing multiple entries. Since there is only ever one entry in that ref at a time, moving stashes between machines has been awkward.
Git 2.51 adds a new stash representation that chains entries into an ordinary commit history. Each entry gains an extra parent pointing to the previous stash entry, making a sequence of commits with four parents total. That means a stash collection can live on a single reference and be pushed or pulled like any other branch. Two new git stash subcommands handle import and export:
$ git stash export --to-ref refs/stashes/my-stash
$ git push origin refs/stashes/my-stash
exports your stash to origin from one machine, and
$ git fetch origin '+refs/stashes/*:refs/stashes/*'
$ git stash import refs/stashes/my-stash
brings it back on another, preserving stash contents across machines.
Stability, deprecation, and the path to Git 3.0
After six years of service, git switch and git restore have officially shed their experimental label. Introduced back in Git 2.23 as more purpose-built replacements for the multi-role git checkout, both commands now have a stable, backwards-compatible command-line interface that will be preserved across future releases.
On the flip side, one legacy command is now formally headed for retirement. git whatchanged—a historical alias for what git log --raw does today—has been marked as deprecated, with removal planned for Git 3.0. Users who still depend on it can continue to do so behind the aptly named --i-still-use-this flag in the meantime.
Improved object inspection for submodules
Scripting around repository objects often means reaching for git cat-file, particularly its --batch and --batch-check modes, which accept a sequence of object identifiers on stdin and return information about each one. Querying a tree or commit yields the expected metadata—object ID, type, and size—as shown here for the README.md blob in Git's own repository:
$ echo HEAD:README.md | git.compile cat-file --batch-check
d87bca1b8c3ebf3f32deb557ae9796ddc5b792ca blob 3662
But what happens when you point cat-file at a submodule? Before Git 2.51, the answer was an unhelpful missing. Git 2.51 changes that behavior, making the tool far more useful for scripts that need to understand the contents of a repository including its nested components:
[ pre-2.51 git ]
$ echo HEAD:sha1collisiondetection | git cat-file --batch-check
HEAD:sha1collisiondetection missing
[ git 2.51 ]
$ echo HEAD:sha1collisiondetection | git cat-file --batch-check 855827c583bc30645ba427885caa40c5b81764d2 submodule
Bloom filters widen their net
Git's commit-graph uses changed-path Bloom filters as a probabilistic way to represent which paths a commit touched relative to its first parent. The filter can say with certainty that a path was not modified, which lets history traversals like git log origin -- path/to/my/file skip over irrelevant commits quickly. However, the full expressiveness of pathspec syntax has limited where the filters can help.
Git 2.51 closes one gap by enabling Bloom filter optimization for pathspec queries that specify multiple paths, as in git log -- path/to/a path/to/b. Previously, such queries had to fall back to slower, exhaustive traversal. Work on further special cases is still underway on the mailing list.
More defaults take shape for Git 3.0
This release added two more items to Git's BreakingChanges list. When Git 3.0 eventually ships, the reftable backend—introduced experimentally in Git 2.45—will become the default format for repositories created with that version. Git 3.0 will also make SHA-256 the default object hash for new repositories.
No release date has been announced, but curious users can preview these upcoming defaults by building Git from source with the WITH_BREAKING_CHANGES flag.
Smaller tweaks, bigger shifts
Several other changes touch the project's underlying policies. On the C99 front, Git has officially adopted the bool keyword across its codebase after a successful experiment that began in late 2023. The project has also begun documenting which C99 features it considers experimental and which it avoids entirely in its coding guidelines.
Finally, the patch submission process is more flexible. Historically, contributions had to be submitted under a contributor's legal name. Aligning now with the Linux kernel's approach, Git allows patches to be submitted under an identity other than the contributor's legal name.



