
Git 2.56: Which New Commands Actually Help
Quick answer: Git 2.56 shipped on 28 September 2026. The two commands that will get the most attention — git history drop and git replay --linearize — are both experimental, and drop refuses merge commits and root commits outright. The changes worth adopting this week are git branch --delete-merged and git add --resolved, both fully documented and both safer than the shell one-liners they replace. The biggest win is one you get for free, and it depends on whether your repo has a commit-graph.
Most release round-ups sort features by novelty. That is the wrong sort order for a version control system, where the interesting question is not what is new but what you can put in a script on Monday without regretting it on Friday.
Git 2.56 splits cleanly along that line. Two headline commands are marked experimental in the release notes and carry hard restrictions. Two smaller additions are fully specified in the manual pages, with documented refusal conditions, and immediately replace fragile shell pipelines that teams have been copy-pasting between repos for a decade. Then there are two performance changes nobody will tweet about, one of which is conditional on repository state most people never think about.
The split: experimental versus documented
Git's release notes use the word "experimental" deliberately, and 2.56 applies it to git history. The note reads: "The experimental git history command has been taught a new drop subcommand to remove a commit, with its descendants replayed onto its parent." git replay, which gains --linearize in this release, is likewise still an experimental command. Neither label is a formality — it means the interface can change, and in drop's case it means the command declines whole classes of input.
| Feature | Status | Hard limit |
|---|---|---|
git history drop | Experimental | No merge commits, no root commits |
git replay --linearize | Experimental | Drops merge commits by design |
git branch --delete-merged | Documented | Five documented skip conditions |
git add --resolved | Documented | Cannot combine with -u or -A |
git refs create/update/delete/rename | Documented plumbing | Does not touch branch config |
--delete-merged is the one you will actually run
Every team has a variant of the same branch-cleanup one-liner: git branch --merged | grep -v main | xargs git branch -d. It is wrong in a specific and annoying way. --merged tests reachability from your current HEAD, not from the branch's upstream, so the answer changes depending on what you happen to have checked out.
The new option asks the right question. Per the git-branch manual: it will "Delete local branches whose configured upstream matches <pattern>, but only when their tip is reachable from that upstream." The pattern can be a ref, a remote, or a shell-style glob, and optional trailing patterns narrow which local branches are considered — git branch --delete-merged origin/* topic-* is a valid invocation.
What makes it trustworthy is the refusal list. Git will not delete a branch when its configured upstream ref no longer exists, when it is checked out in any worktree, when it is the local upstream of a branch that is not being deleted, or when branch.<name>.deleteMerged is set to false. There is also a subtle fourth case: Git skips a branch if pushing it would update its upstream, because such a branch "cannot be distinguished from a branch that just looks fully merged right after a pull." That is precisely the failure mode of the shell one-liner, handled in C instead of in your head.
Pair it with --dry-run, which "print[s] which branches would be deleted and exit[s] without touching any ref." Run the dry run once in a repo you care about before you put the real thing in an alias. The related --forked <branch> option, also new, filters git branch listings by configured upstream and implies --list — useful for auditing which locals point at a remote you are about to retire.
--resolved fixes the conflict-marker footgun
The second genuinely useful addition is git add --resolved. It updates "the index for unmerged paths matching <pathspec> where no conflict markers remain in the working tree." Paths with no markers — including binary files and deletions — get staged as resolved, and if any path still has leftover markers the command refuses to stage anything. It cannot be combined with -u or -A.
That all-or-nothing behaviour is the point. The classic mid-rebase mistake is running git add -A, committing a file with <<<<<<< still in it, and finding out in CI. If you review conflicts by diffing the two sides side by side — whether in your editor or in a browser-based text diff checker — the new flag is the safe way to commit the result. Note the scope: it only inspects unmerged paths and ignores unrelated local modifications, so it is not a substitute for reading your own diff.
The speedups you get without changing anything
Two performance changes matter more than any new subcommand, because they affect operations you already run thousands of times a day in CI.
Merge-base traversal stops earlier
The merge-base walk now stops once one side's exclusive paint is exhausted, instead of continuing into history that is already common. GitHub's write-up reports gains up to 70x, roughly 20x on average in large monorepos, and a Linux-kernel case improving from 0.29 seconds to 0.01 seconds.
Here is the part that gets left out. The same release notes record that the early-exit optimisation in paint_down_to_common() "has been gated on the queue being generation-ordered," fixing a bug where git merge-base without --all could return incorrect results on repositories with v1 commit graphs and clock skew. So the shortcut applies when generation ordering holds. If your repo has no commit-graph, or an old v1 one, your mileage is not the headline number. Writing a commit-graph is cheap and is the actual prerequisite for the win.
Path-walk repacking is no longer mutually exclusive with bitmaps
Previously you chose between --path-walk packing and reachability bitmaps plus delta islands. In 2.56, pack-objects supports them concurrently, falling back to path-walk when bitmaps cannot fully satisfy a request. GitHub's benchmark reports a pack shrinking from 558.5 MB to 164.4 MB — about 71% smaller. It is not on by default; this release removes the reason you could not turn it on. If you self-host Git or mirror large repos in your build infrastructure, that is the experiment to schedule, alongside the runner-image work that lands with the ubuntu-latest move to Ubuntu 26.
One more disk-space lever: git repack -a --filter=blob:limit=1m --drop-filtered removes large promisor blobs that a partial clone can fetch again, and supports --dry-run. It requires a promisor remote and currently handles only blob:limit filters.
git refs is plumbing, and reads like it
The git refs toolbox gains create, delete, update and rename, with optional expected-old-value arguments that give you compare-and-swap semantics. This is aimed at tooling authors, not at your daily driver. The giveaway is that rename does not adjust branch configuration — rename a branch with it and the upstream tracking does not follow. If you are building automation on top of Git, this is a cleaner surface than shelling out to update-ref — and the sort of surface most of the CLIs in the developer tools directory end up depending on; if you are not, ignore it. The same distinction applies to git cat-file's new remote-object-info, which, per GitLab's rundown, fetches object metadata over protocol v2 without transferring the objects.
What to do this week
Three concrete steps. Replace your branch-cleanup alias with git branch --delete-merged origin/* and run it with --dry-run first. Retire any git add -A muscle memory during conflict resolution in favour of --resolved. Write a commit-graph in your big repos so the merge-base improvement actually applies to you.
Leave history drop and replay --linearize out of shared scripts until the experimental label comes off. Both are fine for interactive local surgery; neither belongs in a CI job that runs against branches other people depend on, which is the same reasoning behind GitHub's move to block pull_request_target by default. If you want to see which tools in your stack are already wired to newer Git plumbing, the cloud and DevOps category and the open-source listings are the fastest way to check.
FAQ
When was Git 2.56 released?
28 September 2026, per GitHub's release highlights post. Release candidates were tagged in the preceding weeks, with 2.56.0-rc2 appearing on 26 September 2026.
Is git history drop safe to use on shared branches?
No. It is an experimental command that rewrites history by replaying descendants onto the dropped commit's parent, and it cannot handle merge commits or root commits. Treat it as local surgery on a branch nobody else has pulled.
How is --delete-merged different from git branch --merged?
--merged filters by reachability from your current HEAD. --delete-merged matches each branch against its own configured upstream and only deletes when the tip is reachable from that upstream, so the result does not depend on what you have checked out.
Do I get the merge-base speedup automatically?
Partly. The early-exit optimisation is gated on the traversal queue being generation-ordered, which in practice means having a usable commit-graph. Repositories with a v1 commit graph and clock skew were the ones that produced wrong answers, which is why the gate exists.
Is path-walk repacking enabled by default in 2.56?
No. What changed is that --path-walk now works alongside reachability bitmaps and delta islands instead of conflicting with them. You still opt in, which makes it a benchmark-then-adopt change rather than a free one.
Should tooling authors switch from update-ref to git refs?
It is a cleaner interface with compare-and-swap via expected-old-value arguments, but it is deliberately minimal. In particular git refs rename does not adjust branch configuration, so a branch rename through it leaves upstream tracking behind.
The best feature in a Git release is usually the one that makes a command you already run stop being slow. This time it is also the one with a prerequisite.


