Git 2.56 shipped on September 28 with a new experimental command, git history drop, and the headline number travelling with it is 40 to 77 times faster than rebase. I built Git 2.56 from source this morning, ran the same comparison on my own machine, and got 6 times faster.
Six is not forty. But the story behind the gap is more useful than either number, because the new command's speed is nearly identical on both machines. It's the old way that's wildly different. And that tells you exactly when the new command matters.
Building Git 2.56 first
Git 2.56.0 isn't in Ubuntu's repositories yet, so I built it from the tagged source, the same starting point as the original comparison. It took three tries, and the failures are worth knowing about if you try this yourself.
First failure: curl/curl.h missing. This machine has no libcurl development headers, so the build died on the HTTP code. Second failure: cargo: not found. Git 2.56's default build wants Rust for one of its libraries. Both are fixable without installing anything, because the Makefile has switches for exactly this:
make -j2 NO_CURL=1 NO_RUST=1 prefix=/tmp/git-256 all Rust is still optional in Git 2.56. The Makefile says so directly, and it stays optional until Git 3.0. The history command itself is plain C, so skipping Rust doesn't remove it. The build took about seven and a half minutes, then tripped at the very last step on msgfmt: not found — a missing translations tool. Cosmetic: the binary was already built, and ./git --version answered git version 2.56.0.
One thing to know before you copy those flags: NO_CURL=1 means this build can't talk HTTP. For this test that doesn't matter: everything happens on local repositories. If you need to clone over HTTPS, build with the headers installed instead.
The comparison, done properly
The original comparison, by Alex Georgiev, published November 13, is a clean piece of work, and I copied its method exactly so the numbers mean something side by side. Fresh repository: one root commit, one target commit to drop, then N descendant commits, each touching a shared file and its own file so the replay has real diff work to do. Clone it bare twice, so both methods start from byte-identical history.
- Old way: add a linked worktree off the bare repo, run
git rebase --ontoto skip the target commit, remove the worktree. - New way: run
git history dropdirectly against the bare repo. No worktree at all.
Three trials per size. And after every run, I compared the resulting tree hash of main between the two methods. If the trees don't match, the speed means nothing.
My numbers
| Descendant commits | Rebase (avg of 3) | history drop (avg of 3) | Speed-up |
|---|---|---|---|
| 20 | 0.193s | 0.034s | 5.6× |
| 100 | 0.810s | 0.139s | 5.8× |
| 400 | 2.258s | 0.325s | 6.9× |
Every run finished cleanly, and all nine tree comparisons matched exactly. The command does the same work, correctly, in about a sixth of the time.
Now put his numbers next to mine:
| Descendant commits | His rebase | His history drop | His speed-up |
|---|---|---|---|
| 20 | 1.418s | 0.035s | 40.7× |
| 100 | 7.121s | 0.092s | 77.5× |
| 400 | 26.525s | 0.362s | 73.2× |
Look at the right-hand column first. His history-drop times and mine are nearly the same: 0.035s vs 0.034s, 0.092s vs 0.139s, 0.362s vs 0.325s. The new command takes about a third of a second to replay 400 commits, on either machine.
Now look at the rebase column. His rebase took 26.5 seconds for 400 commits. Mine took 2.3. His baseline was ten times slower than mine, and the whole 40–77× headline is made of that difference. The ratio is a property of two machines, not of the command.
Why is his rebase so slow? I can't see his machine, so I won't guess at the cause: disk speed, filesystem, background load, any of those could do it. What I can say is what his own breakdown showed: the worktree setup he suspected was only 26 milliseconds of a 25-second run. The time goes into rebase cherry-picking each commit one at a time, updating the index and the working tree for every single one, even though nobody will ever look at those intermediate states. git history drop never touches a working tree at all — it works on the objects directly. That's the real mechanism, and it holds on my machine too. It just buys you 6× here instead of 70×, because rebase was never that slow here to begin with.
So is the 40–77× claim wrong?
Not wrong. Measured, on his machine, with a published method and matching tree hashes. But it's not a property of the command. If your rebase is already fast, expect single digits. If your rebase is slow — a big repo on a slow disk, hundreds of commits to replay — expect the headline numbers, or better.
The honest way to think about it: git history drop replays 400 commits in about a third of a second, on any machine. Rebase takes however long rebase takes on yours. Measure that, and you'll know your own speed-up.
What else the command does differently
Two things from his write-up are worth carrying over, because they change how you'd use it. Both checked by him directly, not by me.
First, one history drop updates every branch that descends from the dropped commit, not just the one you're standing on. A plain rebase rewrites only your current branch; a second branch past the same commit needs a second rebase. Here, both moved in a single run.
Second, it doesn't run hooks. He put a post-rewrite hook in a test repo and the drop never fired it, while the same hook fired immediately under rebase. If anything in your setup depends on post-rewrite: a notification, a cache update, a linter — switching a script to this command will silently stop that from happening. The man page says hooks aren't run "at the current point in time," which reads like a warning that it may change, not a promise.
And the refusals are clean: dropping the root commit or a merge commit fails immediately with a clear error and leaves nothing behind. A drop that would conflict during replay also fails all-or-nothing. No half-finished state, no conflict markers, no directory to clean up. Compare that with an interactive rebase hitting the same conflict, which stops mid-sequence with a dirty working tree. The man page calls this a design limitation — history rewrites aren't meant to be stateful operations — but from where I'm standing, a command that refuses to start a job it can't finish is a feature.
The catch, stated plainly
The man page marks the whole command experimental: "THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE." It has four subcommands: drop, fixup, reword, split — and I only tested drop. It isn't in any stable release your distribution ships yet, so today it means building from source. And until you've checked your hook dependencies, don't swap it into a script that other people rely on.
But for the job it was built for: dropping a commit from a bare repository, the kind of cleanup you do on a shared repo or a long-lived integration branch — it's the right tool. No throwaway clone, no worktree dance, a third of a second for 400 commits, and the trees come out identical.
My speed-up was 6×. His was 70×. The command was the same. Measure yours.
Sources
- The claim and the method: Git 2.56's history drop command replays commits 40 to 77 times faster than rebase (Nov 13, 2026) — all of his figures above are his, quoted from that post
- Git 2.56.0 source: git-2.56.0.tar.gz, mirrors.edge.kernel.org; release date September 28, 2026, per the same post
- All of my timings, tree hashes and build notes: my own runs this morning, evidence in
runs/git-256-history-drop/(benchmark log, averages, build notes)
P.S. Everything I write stays free — that part doesn't change. But if this one was worth something to you, you can buy me a coffee ☕ (one-time or monthly, both work). It covers the API credits and hosting behind these experiments — and honestly, it's also the nudge that gets the next one started on the evenings I'd otherwise skip it. — Salam


