Checksums get a security-safe performance path

Git 2.48 arrives with contributions from more than 93 developers, 35 of them first-time contributors. Among the notable changes is a refinement to work that actually landed late in the 2.47 cycle, addressing a bug in that earlier work.

Git’s default object hashing uses a collision-detecting SHA-1 implementation, which guards against known attacks like SHAttered and Shambles. That protection costs extra CPU cycles. While negligible for most operations, the overhead becomes meaningful when computing checksums for large packs—during a clone of torvalds/linux, roughly 78% of CPU time can go toward checksumming.

The key insight is that the trailing SHA-1 checksum in the pack format serves data integrity, not security. It validates that pack contents haven’t been corrupted in transit, but it doesn’t need collision resistance. Git 2.47 introduced build-time options to specify a separate, faster SHA-1 implementation specifically for those trailing checksums. GitHub adopted this and measured a 10–13% improvement in serving fetches and clones. You can enable it by building with make OPENSSL_SHA1_UNSAFE=1 or using other _UNSAFE variants defined in the Makefile.

Merging --remerge-diff into range-diff

Two previously separate features now work together. range-diff, introduced in Git 2.19, compares sequences of commits, capturing changes to order, messages, and content. The --remerge-diff option, added in 2.36, shows what Git would have produced at a merge stop versus what’s actually recorded—useful for reviewing how merge conflicts were resolved.

In Git 2.48, range-diff accepts --remerge-diff, so when a sequence is rebased with --rebase-merges and merge commits are modified, those changes can be reviewed alongside the rest of the range diff. This work also fixed a long-standing bug, enabling git log --remerge-diff to work with traversal-order options like --reverse.

A leak-free test suite

Memory-leak elimination in Git has been a multi-year effort, dating back to 2.34. For a command-line tool where each process is short-lived, leaks are rarely a practical problem—the kernel reclaims memory on exit. But they block the path toward reusing Git’s internals as a callable library, where leaks would accumulate.

That goal is now much closer. Git’s test suite runs cleanly with leak checking enabled, and much of the test infrastructure introduced in 2.34 has been removed, simplifying the tooling. This is a meaningful milestone toward making parts of Git usable as an embedded library.

Meson Joins Git’s Build Toolchain

For years, building Git from source has meant GNU Make: fetch the tree, run make, and you get a binary. Git also carries partial Autoconf and CMake support, but neither is maintained at the same level as the project’s Makefile. That file has accumulated more than 2,000 commits and now sprawls to nearly 4,000 lines, a burden that becomes harder to manage as Git approaches its 20th anniversary.

Git 2.48 adds a genuine alternative: Meson. It is not yet as complete as the Make-based build, but Meson brings real benefits. Its simpler syntax lowers the barrier for contributors unfamiliar with Make’s idiosyncrasies, and it offers first-class IDE integration plus support for out-of-tree and cross-platform builds — both areas where Git’s traditional build has struggled.

Make and CMake support will remain for the foreseeable future, and Autoconf will stick around a bit longer. If you want to try the newest option, a fresh checkout of Git 2.48 or later can be built with meson setup build && ninja -C build.

A Formal Home for Deprecations

Long-lived projects inevitably carry features that made sense in their era but have since been superseded. Git 2.48 starts cataloging those in Documentation/BreakingChanges.txt. The new document gives the project a single place to plan and discuss removals, while giving users a chance to see what is headed for the door and to make their case for keeping a feature before it is dropped. It also offers an early glimpse of what a future Git 3.0 might drop.

Faster Sorted Reference Output

Users who script against repository references know git for-each-ref well. The command gained significant performance improvements in Git 2.44, when reference filtering and formatting were merged into a single codepath, avoiding intermediate storage and sorting in common cases.

Git 2.48 extends that work to sorted output. Under certain conditions, git for-each-ref can now take the same optimized path even when the user requests results via --sort=refname. The result: listing a small number of refs in sorted order is now independent of the total ref count in the repository, so even large repositories can answer those queries quickly.

Reftable Refinements

The reftable subsystem received another round of hardening in this cycle. Its code now avoids pulling in several of Git’s convenience APIs, another step toward compiling reftable without linking against libgit.a. Memory allocation failures are now handled gracefully rather than aborting the process, and reference iterators can be reused between operations — changes which together mean faster ref creation and lower memory consumption for reftable users.

Keeping Remote HEAD in Sync

When you clone, the remote’s default branch is recorded locally in refs/remotes/origin/HEAD. Until now, later fetches never touched that symbolic reference, so it could silently go stale if the remote changed its default branch. Git 2.48 changes that: if the remote advertises a default branch and the local refs/remotes/origin/HEAD is missing, a fetch will now create and set it.

For stricter tracking, set remote.origin.followRemoteHead to warn or always. With warn, a fetch that finds refs/remotes/origin/HEAD pointing at a stale branch will notify you. With always, it will update the symref automatically.

Partial Clone Fixes

Partial clones got attention as well. Bug fixes in this release close an infinite loop, and prevent promisor references from pointing at non-promisor objects — a mix-up that could corrupt a repository after a git gc run.

For background on how partial clones work, the project’s guide to partial and shallow clones is a good starting point.

What Else Is In 2.48

These highlights are only a slice of the release. The complete change log is in the Git 2.48 release notes, with older notes for every prior version available in the Git repository.