Protocol v2 Becomes the Default for Fetching

Git 2.26 finally makes protocol version 2 the default for network fetch operations. The protocol, first introduced in Git 2.19, was designed to address a major inefficiency in the original protocol: servers would immediately send a full list of every branch, tag, and reference in the repository before the client could even make a request. For large repositories, that advertisement alone could mean megabytes of unnecessary data transfer when the client only needed, say, the master branch.

With protocol v2, the exchange starts with a client request, allowing the client to specify exactly which references it cares about. Fetching a single branch only queries for that branch; cloning typically asks only for branches and tags. This makes a noticeable difference on large repositories where the server may store many extra references, such as the heads of every pull request ever opened.

Because the protocol was designed with backward compatibility in mind, clients speaking v2 can seamlessly communicate with older servers, automatically falling back to the original protocol when needed. The years-long delay between introduction and activation by default was purely to let early adopters shake out bugs. If you want to opt in manually on Git 2.19 or later, you can set:

git config --global protocol.version 2

Config Inspections and Wildcard Credentials

Git pulls configuration from a handful of places: repository-level (.git/config), user-level (~/.gitconfig), system-wide (/etc/gitconfig), plus command-line and environment overrides. That flexibility sometimes makes it hard to know which source set a particular value. The existing git config --show-origin helps by revealing the exact file path, which is useful if you plan to edit the file manually — but less so if your goal is to override the value via git config --system, --global, or --local.

Git 2.26 adds --show-scope, which labels each setting with the same identifiers you would use to modify it:

$ git config --show-scope --get-regexp 'diff.*'
global  diff.statgraphwidth 35
local   diff.colormoved plain

$ git config --global --unset diff.statgraphwidth

You can combine --show-scope with --show-origin for even more context, and it works both when querying a single option and when listing all of them:

$ git config --list --show-scope --show-origin
global  file:/home/user/.gitconfig      diff.interhunkcontext=1
global  file:/home/user/.gitconfig      push.default=current
[...]
local   file:.git/config      branch.master.remote=origin
local   file:.git/config      branch.master.merge=refs/heads/master

Wildcard matching for credential URLs is another new capability. Git’s http config matcher has long supported patterns like *.example.com for options such as http.extraHeader, but the credential matcher never learned the same trick. In 2.26, you can now apply credential settings across subdomains:

[credential "https://*.example.com"]
    username = ttaylorr

That configuration will take effect for foo.example.com, bar.example.com, and any other subdomain.

Sparse-Checkout Gains an Incremental Add

Sparse-checkouts let you work with only part of a repository at a time. In a monorepo scenario where you only need the client/macos directory, there's no point downloading blobs from every other part of the tree. Git handles this in two steps: first, it requests only commit and tree objects from the server (skipping blobs entirely), and second, it configures the client to tolerate missing objects, fetching any that turn out to be needed for operations like checkout.

You can initiate this workflow at clone time with:

git clone --filter=blob:none --sparse <repository>

The first checkout will trigger a follow-up fetch, automatically pulling down the blobs needed for the top-level files so your working copy is browsable.

Previously, the only way to expand your sparse-checkout was git sparse-checkout set, which replaced the entire list and forced you to re-specify every directory you wanted. Git 2.26 introduces git sparse-checkout add, which appends new entries one at a time without requiring a full re-specification:

$ git clone --filter=blob:none --sparse [email protected]:git/git.git
Cloning into 'git'...
remote: Enumerating objects: 175470, done.
remote: Total 175470 (delta 0), reused 0 (delta 0), pack-reused 175470
Receiving objects: 100% (175470/175470), 59.07 MiB | 10.48 MiB/s, done.
Resolving deltas: 100% (111328/111328), done.
remote: Enumerating objects: 379, done.
remote: Counting objects: 100% (379/379), done.
remote: Compressing objects: 100% (379/379), done.
remote: Total 431 (delta 0), reused 0 (delta 0), pack-reused 52
Receiving objects: 100% (431/431), 1.73 MiB | 4.06 MiB/s, done.
Updating files: 100% (432/432), done.

$ cd git

$ git sparse-checkout init --cone
$ git sparse-checkout add t
remote: Enumerating objects: 797, done.
# ...
Updating files: 100% (1946/1946), done.

$ git sparse-checkout add Documentation
remote: Enumerating objects: 334, done.
# ...
Updating files: 100% (723/723), done.

$ git sparse-checkout list
Documentation
t

A few observations from the example output: the clone shows two "enumerating objects" phases — one for the initial clone, one for fetching the top-level blobs. Even after multiple git sparse-checkout add calls, only the new directory needs to be listed. There's still some roughness around how the client batches these fetch requests (adding the t directory generated three requests when one would have sufficed), but those inefficiencies are being smoothed out with each release, and cone-mode restrictions have also seen cleanup in this version.

Smaller Fixes That Matter

git grep has always been multithreaded when scanning the working tree, but historical searches ran single-threaded due to constraints in Git’s object storage. That limitation is gone in 2.26. Work by Google Summer of Code student Matheus Tavares made concurrent reads from the object layer possible, so git grep --threads now works at full speed whether you are searching checked-out files or old revisions. Since --threads defaults to your core count, you may not even need to pass the flag.

Command-line completion for git worktree also improved. The tab-completion engine now understands worktree subcommands, paths, and refs, which is useful if you keep multiple working copies of a repository mounted side by side.

Format strings gained a color upgrade. Git’s --format specifiers already accepted shorthand names like %C(blue) for ANSI colors, and 2.26 adds the bright variants. You can now write %C(brightblue) to get a more vivid shade in git log and other formatted output.

Filesystem monitor integrations such as Watchman now have better timestamp support. Watchman can report the last update time using a UNIX epoch, a vector clock, or opaque tokens, and it prefers the clock identifier format. Git 2.26 understands that format, so updating to the new fsmonitor sample hook is all that is required for the integration to work correctly.

Partial clone filtering got faster. Checking whether an object is a blob or determining its size previously required a full object traversal, which slowed down --filter=blob:none and --filter=blob:limit=<n> as repository size grew. Those checks now use the bitmap machinery, so no traversal is necessary. These patches are running in production at GitHub, meaning you can test partial clones on any repository hosted there.

Rebase Backend Consolidation

Interactive and non-interactive rebases no longer use different merge machinery. Previously, git rebase ran the “apply” backend while git rebase -i used the “merge” backend. Both now use the merge backend in 2.26, which removes the behavioral split but introduces a difference worth knowing about.

When a rebase pauses on a conflict in the old apply backend, running git rebase --continue after staging your fixes moved ahead immediately, keeping the original commit message unchanged. With the merge backend, you are now prompted to edit the commit message, giving you a chance to document how you resolved the conflict. The change author also added documentation covering other differences between the two backends, which is available in the Git rebase manual.

For the full list of changes, see the 2.26.0 release notes.