Git 2.56.0 landed on September 28, 2026, tagged by Junio C Hamano with changes from more than 104 contributors, 39 of them new. It is the biggest Git release in a while by contributor count, and the headline items are a new git refs subcommand family, a conflict-resolution-aware git add mode, and several fixes to commands that had become unusably slow on large repositories.
There is one change that can break a script without announcing itself: asking git for help now exits 0 instead of 129. Everything else in the release is additive or opt-in. And if you have been waiting to move off the files-based ref backend, reftable is still not the default — that is a Git 3.0 change, and it is the one to plan for now.
Key takeaways:
git add --resolvedstages paths whose conflict markers are gone, and refuses to stage anything if any marker survives.git refs create/delete/update/renamegives ref manipulation a stable command surface instead of script-shapedupdate-refinvocations.- Several large-repository fixes are substantial: a Chromium checkout path-limited
git diffwent from about eight minutes to 0.07 seconds. - Help output now exits 0, not 129. If you assert on that exit code anywhere, fix it before you upgrade.
- Reftable and SHA-256 arrive as defaults in Git 3.0, not in 2.56.
The one change that can break your scripts
Option parsing in git rev-parse --parseopt and most git subcommands now exits 0 instead of 129 when a user asks for help directly with -h or --help. In isolation this is a reasonable cleanup. In practice it is a silent behaviour change for anything that checked the exit status:
# Breaks after upgrading to 2.56 if your helper probes for help
git some-subcommand --help
if [ $? -eq 129 ]; then
echo "not supported"
fi
If you maintain wrappers around git, this is the one to grep for before you roll the upgrade out.
git add –resolved
Marking a merge conflict as resolved has always meant staging the file manually and hoping. git add --resolved makes the operation conditional on the conflict actually being gone:
git add --resolved <pathspec>
It stages unmerged paths matching the pathspec only when no conflict markers remain in the working tree, including binary files and deletions. If any path in the selection still has leftover markers, the command refuses to stage anything at all and reports which ones:
fatal: the following paths still have conflict markers:
That all-or-nothing behaviour is the point. It is a check, not a convenience. It cannot be combined with -u or -A.
A proper git refs subcommand family
Four new subcommands under git refs give ref manipulation a documented interface:
git refs create [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value>
git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]
git refs update [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value> [<old-value>]
git refs rename [--message=<reason>] <old-ref> <new-ref>
The semantics carry over from git update-ref: in update, an all-zeroes <new-value> deletes the ref, and an all-zeroes <old-value> asserts that the ref does not exist. Supplying the old value is how you make a ref update a compare-and-swap instead of a blind write.
This is a quiet but real improvement. If you have ever wrapped update-ref in a shell function with careful quoting, you can replace it with something whose argument grammar is documented.
Cleaning up merged branches
git branch --delete-merged takes a pattern rather than a list of branch names, which makes it usable directly against remote-tracking refs:
# See what would go, without touching anything
git branch --dry-run --delete-merged 'origin/*' 'topic-*'
It skips a branch when its upstream is gone, when it is checked out in a worktree, when deleting it would update an upstream that still needs it, when it is the local upstream of a branch being kept, or when branch.<name>.deleteMerged is set to false for it. That last one is a per-branch opt-out, and explicit git branch -d is unaffected by it. Branches that are not merged are silently skipped rather than treated as an error; use -D when you really mean force.
Performance: the fixes that matter at scale
Important caveat before the numbers: Git’s own release notes contain no benchmark table. The figures below come from GitHub’s engineering write-up of the release, and describe measured workloads rather than synthetic ones.
| Change | Measured effect |
|---|---|
| merge-base early exit | Linux kernel, git merge-base --all v4.8 v4.9: 167,441 to 3,887 traversal steps, 0.29s to 0.01s |
| merge-base early exit | One monorepo traversal: 0.68s to 0.01s. On two production monorepos, roughly 70x faster in one and about 20x on average in the other |
| Path-walk repack | Repacking a recent clone of microsoft/fluentui with deltas forced to recompute: 558.5 MB bitmapped versus 164.4 MB with --path-walk, about 71% smaller |
| Index cache-scan quadratic fix | Path-limited working-tree diff in a Chromium checkout with roughly 500,000 index entries: about 8 minutes to 0.07 seconds |
| Reftable tombstone handling | In-tree reftable performance tests: about 13s to 0.2s |
| Packfile loading | Fixed quadratic behaviour when loading packfiles; quoted against a repository with 37,815 packs |
The Chromium case is the one worth understanding. It was not slow because git was slow; it was slow because the index cache scan was quadratic in the number of index entries. A 500,000-entry checkout is not exotic — it is roughly what a monorepo checkout looks like — so this single fix removes a failure mode that “git is fine on my laptop” testing never surfaces.
The repack feature for partial clones
git repack --drop-filtered lets a partial clone shed blobs it had already been ignoring, instead of keeping them around indefinitely:
# Requires -a, implies -d, and needs a promisor remote
git repack -a --filter=blob:limit=1m --drop-filtered --dry-run
Only --filter=blob:limit=<n> is accepted, and it cannot be combined with --filter-to or the bitmap index options. --dry-run here is genuinely useful: it lists the object IDs that would be dropped, one per line, so you can see the effect before committing to it.
Smaller changes worth knowing
git bisect --reset-when-found[=<where>]returns the checkout tooriginal(the default) orfoundafter a bisection identifies a commit, so scripted bisections stop leaving your tree on some arbitrary commit.git replay --linearizedrops merge commits and flattens history, matchinggit rebase --no-rebase-merges. Experimental, and cannot be combined with multiple branches or--contained.git history drop <commit>removes a commit from history, with--dry-run,--update-refsand--emptyhandling. Experimental, and does not work on histories containing merges.git cat-file --batch-commandgainedremote-object-info, which fetches object metadata such as size over protocol v2 without downloading the object.git rev-list --missing-onlyrequires--missing=printor--missing=print-info.git log --graphnow indents visual roots by default. Opt out with--no-graph-indentorlog.graphIndent=false. Expect golden-file tests to notice.git worktree addandgit checkoutnow error on an ambiguous remote-tracking-branch DWIM instead of guessing. This is a behaviour change that surfaces sloppy branch setups rather than fixing them.
New configuration options
| Variable | Default | Purpose |
|---|---|---|
branch.<name>.deleteMerged | true | Set to false to exempt a branch from git branch --delete-merged |
log.graphIndent | true | Indentation of visual roots in git log --graph |
fetch.followRemoteHEAD | mirrors the per-remote setting | Global default for how fetch treats a remote’s HEAD: create, warn, always, never |
promisor.acceptFromServerUrl | none | Glob allowlist for server-advertised URLs accepted from a promisor remote |
promisor.acceptFromServerURL while the configuration documentation uses promisor.acceptFromServerUrl; check your git version before setting it.What is still coming in Git 3.0
Reftable is available in 2.56. It is not the default. files remains the default ref storage format; reftable becomes the default only in a build with breaking changes enabled, which means Git 3.0. There is no release date set for 3.0.
What 3.0 is planned to change:
- Default ref storage for newly created repositories:
filestoreftable - Default object hash for new repositories:
sha1tosha256 - Rust becomes mandatory; the build-time opt-out is removed
- Default branch name
main, andsafe.bareRepositorydefault moves fromalltoexplicit - Removals including commit grafts,
git-pack-redundant,name-rev --stdin,git-whatchanged,core.commentString=autoandcore.preferSymlinkRefs=true
Git’s own documentation names the prerequisite: alternative implementations such as JGit, libgit2 and Gitoxide need to support reftable first. That is the honest reason 3.0 is not imminent, and it is worth tracking rather than guessing at. It is also worth keeping in view that a Git installation is a supply chain like any other: the executables, the hooks and the CI jobs around them are all trusted code paths, which is the same surface covered in how AI agents attack software supply chains.
You can still opt in on 2.56 with init.defaultRefFormat=reftable, and migrate an existing repository with git refs migrate --ref-format=reftable. Two documented limits before you try it on anything that matters: it is not possible to migrate a repository that has worktrees, and there is no way to block concurrent writes during an ongoing migration. Unregister any scheduled maintenance first.
Should you upgrade?
If you work in large checkouts, the merge-base, index scan and repack fixes justify the upgrade on their own. If you maintain tooling around git, do the exit-code audit first. If you are planning a reftable migration, 2.56 is a good place to start testing it on a copy of a real repository rather than a toy one, because the worktree limitation and the concurrent-write gap are exactly the kind of thing that only shows up on real repositories. If the repository is shared or driven by automation, review its access control at the same time; protecting a Git repository from automated abuse covers that side.
References
- Highlights from Git 2.56 — Elijah Newren, GitHub Blog, September 28, 2026
- Git 2.56.0 release notes — upstream documentation
- git-scm.com — download and documentation
- Git breaking changes — the planned Git 3.0 list
Related Tools
Try these companion tools on DevStackIO Tools:
- Git token generator — generate secure API and access tokens for Git authentication.