Git 2.44 reuses packs across multiple files for faster transfers

Git 2.44 is out, bringing improvements from over 85 contributors, 34 of them new. One of the headline changes is faster pack generation through multi-pack reuse, which cuts the cost of cloning and fetching large repositories.

If you have pushed or pulled from GitHub recently, you may have noticed a pack-reused count in the output. That figure tells you how many objects Git could transfer by streaming verbatim sections of an existing packfile instead of building a new pack from scratch.

$ git clone [email protected]:git/git.git
Cloning into 'git'...
remote: Enumerating objects: 361232, done.
remote: Counting objects: 100% (942/942), done.
remote: Compressing objects: 100% (453/453), done.
remote: Total 361232 (delta 598), reused 773 (delta 487), pack-reused 360290
[...]

In the sample above, pack-reused 360290 means GitHub reused 360,290 objects directly from disk. Only the remaining few hundred objects took the slower path of opening, parsing, and searching for new delta pairs.

This shortcut works because the wire format for transferring objects matches the on-disk .pack format, so Git can copy byte-for-byte from an existing pack. The catch has been that reusing objects this way requires the majority of an object set to live in one packfile, and certain delta types need offset patching when gaps appear between a delta and its base. That arrangement becomes unwieldy for huge repositories.

Git 2.44 now supports verbatim reuse across multiple packfiles when a multi-pack index with reachability bitmaps is in place. This removes the need to repack everything into a single file.

After upgrading, you might see a small change in your push output:

$ git push
Enumerating objects: 350175, done.
Counting objects: 100% (832/832), done.
Compressing objects: 100% (132/132), done.
Total 350175 (delta 735), reused 700 (delta 700), pack-reused 349343 (from 36)
[...]

The added (from 36) tells you objects were reused from 36 different packs.

To enable this behavior, run:

$ git config --global pack.allowPackReuse multi
$ git multi-pack-index write --bitmap

The command prepares the multi-pack index and bitmaps required for the optimization.

A new rebase engine: git replay

The merge-ort merge backend, introduced in Git 2.33 and made the default in Git 2.34, was designed from the start to solve performance and correctness problems that plagued the older recursive backend. One of its less obvious benefits is that it can compute merges without a fully populated checkout — the git merge-tree --write-tree command takes advantage of exactly that capability.

Rebases, however, did not get the same treatment. The existing git rebase sub-command carries years of design assumptions and backwards-compatibility constraints that make it difficult to retrofit onto merge-ort without sacrificing performance. Git 2.44 introduces git replay as an alternative that sidesteps those issues entirely. It is not just faster; it can run in bare repositories, rebase branches other than the one currently checked out, and even process multiple branches in a single invocation. GitHub has been using merge-ort to power all merges and rebases on GitHub.com for over a year, with substantial performance gains.

For scripting, performance-sensitive workflows, or simply experimenting with new Git internals, git replay is worth a look. Full documentation is available in the git-replay(1) man page.

Autosquash without the editor dance

Rebasing with --autosquash has long been a handy way to fold fixup!, squash!, or amend! commits into their target commits. Previously, this only worked with interactive rebases. To apply a fixup! commit without manually editing the todo list, you had two choices: launch git rebase -i and immediately close your $EDITOR, or set GIT_SEQUENCE_EDITOR=true git rebase -i.

Starting with Git 2.44, --autosquash works with plain non-interactive rebases. A bare git rebase will now automatically place and apply your fixup! commits in the correct locations, no todo list inspection or environment variable tricks required.

Advice messages that respect your preferences

hint: Updates were rejected because the tag already exists in the remote. 
hint: Disable this message with "git config advice.pushAlreadyExists false" 

When Git shows an advice message like the one above, it appends a line suggesting how to disable it — for example, git config advice.pushAlreadyExists false. But if you actually want to keep seeing that advice, the “Disable this message with […]” suffix becomes noise. In Git 2.44, setting the advice key to true (e.g., git config advice.pushAlreadyExists true) suppresses that disabling hint while continuing to show you the core warning.

Sorting semantics clarified in for-each-ref

Long-time Git users know that the --no-sort option to git for-each-ref never actually meant “unsorted” — it still produced sorted output, which prevented certain ordering-agnostic optimizations. In Git 2.44, --no-sort truly returns references in an arbitrary order. On a repository with many refs, this delivers a speedup of over 20% compared to the default sort, on at least one machine. The underlying details are in the linked patch series.

New pathspec magic for git add

Pathspecs are Git’s way of expressing “which filepaths to operate on.” They support a range of magic prefixes: :^Documentation/ excludes a directory, :(icase)**/*sha256* matches case-insensitively, and :(attr:!binary) filters by gitattributes attributes.

Up until now, the attr magic was only honored by commands like git show. Git 2.44 makes git add understand it too, so you can stage all text files with git add ':(attr:!binary)'.

Also new in this release is builtin_objectmode pathspec magic, which filters files by their mode — 100644 for regular files, 100755 for executables, 160000 for submodules. The builtin_ prefix means no corresponding entries are needed in .gitattributes; the mode is always available. For example, git add ':(builtin_objectmode=100755)' stages every executable file in the working tree.

More in Git 2.44

These highlights only scratch the surface. The full release notes for 2.44 and any earlier version are in the Git repository's Documentation/RelNotes directory.