High Five Studio

October 2026

Undo History Holds 20 Steps, 33% of Devs Ship a Revert

A 20-step undo limit quietly shapes how much risk developers take, and why a third reach for revert within hours of writing code

Undo History Holds 20 Steps, 33% of Devs Ship a Revert

Every code editor ships with an undo stack of finite depth, and every developer eventually hits the bottom of it. The question worth sitting with is not how deep that stack should be, but what the existence of a 20-step limit does to the way we write code in the first place. This article looks at the psychology of reversibility in software work: why a third of developers reach for revert within hours, what that says about how we make decisions under uncertainty, and how interface design quietly shapes the risk we're willing to take.

The 20-Step Cliff and the Illusion of Safety

Most editors cap undo history somewhere between 20 and a few hundred steps, though the number is rarely surfaced to the user. VS Code defaults to a stack that feels effectively infinite for a single file session, but across file switches, reloads, and terminal-driven operations, the real depth collapses fast. JetBrains IDEs persist local history for days. Vim's undolevels defaults to 1000. The variation is enormous, and almost nobody knows their own number.

That asymmetry matters. When you don't know the depth of your safety net, you behave as if it's deeper than it is. Behavioral economists call this a framing effect: the same objective risk feels different depending on how it's presented. Kahneman and Tversky's work on prospect theory showed that people are loss-averse — losing something hurts roughly twice as much as gaining the equivalent feels good — but the flip side is that when the loss feels abstract or distant, we discount it heavily. An undo stack you've never hit the bottom of is an abstract loss. You'll happily refactor 40 lines because the cost of being wrong feels like one keystroke.

Then you hit the cliff. And the recovery cost isn't one keystroke — it's a git reflog dive, a stash you forgot you made, or a re-typed block from memory. The mismatch between perceived and actual reversibility is where a lot of avoidable frustration lives.

What the 33% Revert Figure Actually Measures

The statistic that roughly a third of developers ship a revert within a working session isn't a measure of incompetence. It's a measure of calibrated risk-taking. If you never revert, you're probably moving too slowly — over-testing, over-reviewing, refusing to commit until certainty arrives. If you revert constantly, you're likely committing before you understand the change.

The healthy middle is a revert rate that tracks the ambiguity of the task. Greenfield work with clear specs: low revert rate. Legacy code with undocumented behavior: high revert rate, and that's fine. The number itself is less interesting than whether it's intentional. A developer who reverts because the tests caught a regression is running a tight feedback loop. A developer who reverts because they pushed to main and something broke in staging is running an expensive one.

The distinction is the same one decision theorists draw between exploration and exploitation. Reverting during exploration is cheap and correct. Reverting during exploitation — after you've told stakeholders the feature is done — is expensive and usually avoidable.

Variable Rewards and the Refactor Loop

There's a reason refactoring is addictive, and it isn't purely aesthetic. Every time you clean up a function, you get a small, unpredictable payoff: sometimes nothing changes, sometimes a bug disappears, sometimes you uncover a deeper problem. That unpredictability is the signature of a variable-ratio reinforcement schedule, the same pattern B.F. Skinner identified as producing the most persistent behavior in his operant conditioning experiments.

Skinner's pigeons pecked for food that arrived after an unpredictable number of responses. They pecked more, and kept pecking longer, than pigeons on a fixed schedule. Developers refactoring without a clear target are the pigeons. The next commit might fix everything, or nothing. That uncertainty is what keeps the loop running past the point of diminishing returns.

The undo stack is part of this loop. When you know you can undo, you're more willing to make a speculative change — rename a variable, extract a method, flip a conditional — just to see what happens. The change itself is the peck. The compiler passing is the pellet. The compiler failing is also, weirdly, a pellet, because it's information. Either way you learned something, and the loop reinforces.

This is mostly good. Speculative editing is how you build a mental model of unfamiliar code. But the loop has no natural stopping point. You can refactor a file indefinitely and always find something. The undo stack doesn't tell you when to stop; it just makes stopping feel unnecessary.

Loss Aversion in the Diff Review

Loss aversion shows up most clearly when you're reviewing your own diff before committing. You've written 200 lines. You suspect 40 of them are wrong. Deleting those 40 feels like a loss — you spent time on them, they might be right, the tests might pass. Keeping them feels like the status quo.

Kahneman's insight was that losses loom larger than equivalent gains, which means the default wins by default. The 40 suspect lines stay in, get committed, and either pass review (and become someone else's problem later) or get reverted. The revert rate isn't a failure of skill; it's a predictable consequence of how humans weight sunk effort.

The countermeasure isn't willpower. It's structural: small commits, frequent reverts, and treating the undo stack as a first-class tool rather than a panic button. If you commit after every 20 lines, deleting 40 is trivial. If you commit after 400, deleting 40 means unpicking a tangled history.

Designing Interfaces That Make Reversal Cheap

Interface design has a direct effect on how much risk users will take, and this generalizes far beyond code editors. Don Norman's work on affordances and constraints established that the perceived cost of an action shapes whether people attempt it. A button that says "Delete" with no confirmation produces hesitation. A button that says "Move to Trash" with a 30-day recovery window produces action.

The same principle applies to deployment pipelines. A team with one-click rollback deploys more often than a team whose rollback requires a runbook, a Slack thread, and a database migration. This isn't because the first team is braver. It's because the perceived cost of being wrong is lower, so the threshold for trying is lower.

There's a concrete example worth citing here: Etsy's long-running practice of deploying continuously with a "deployinator" that made rollback a single action. The cultural effect was measurable — engineers shipped smaller changes more frequently because the cost of a bad deploy was bounded. The technical mechanism (fast rollback) enabled a behavioral shift (willingness to ship).

Croatian dev teams working with distributed clients often face a version of this problem. When your stakeholder is in a different timezone and your rollback procedure involves a scheduled call, you self-censor. You ship less. You bundle changes. You wait for certainty that never arrives. The undo stack — whether it's git, a feature flag, or a blue-green deploy — is what lets you ship without that certainty.

The Cost of Irreversibility

Some actions genuinely can't be undone, and recognizing which ones is a skill in itself. Dropping a production database table. Force-pushing over a colleague's branch. Sending a client an invoice with the wrong currency. These are the operations where the 20-step stack doesn't help, and where the psychology flips: loss aversion becomes correct, and caution is the right response.

The mistake is treating all actions as if they're in the reversible category. Developers who force-push habitually are running an irreversible operation with the mental model of a reversible one. The fix is procedural, not psychological: protect the branches that matter, require explicit confirmation for the operations that can't be undone, and make the irreversible ones feel irreversible in the interface.

Git does this reasonably well. git push --force requires you to type the flag. git reset --hard requires you to know what you're doing. But the friction is inconsistent, and inconsistency is what erodes the calibration.

Competitive Play, Risk, and the Speed-Accuracy Tradeoff

There's a reason competitive programmers and speedrunners tend to have low revert rates and high error rates in equal measure. Under time pressure, the optimal strategy shifts toward acting first and correcting later, because the cost of deliberation exceeds the cost of a mistake. This is the speed-accuracy tradeoff, formalized by Paul Fitts in the 1950s and still the best model we have for how humans balance the two.

In a competitive setting, the undo stack becomes a strategic resource. You spend it deliberately. You make a risky move because you know you can back out. You don't deliberate because deliberation is the expensive thing. This is exactly the behavior you want in a hackathon, a live debugging session, or a production incident.

It's exactly the behavior you don't want in a regulated environment, a financial system, or anything touching personal data. The same psychology that produces fast, adaptive work in one context produces reckless work in another. The variable isn't the developer; it's the cost structure of the environment.

Croatia's dev scene has a particular texture here. A lot of teams are small, client-facing, and working across EU regulatory boundaries. The cost of an irreversible mistake is high — GDPR, client contracts, reputational damage in a market where everyone knows everyone. But the cost of moving slowly is also high, because small teams can't afford to over-engineer. The undo stack, in this context, isn't a convenience. It's the mechanism that lets a five-person team ship at the pace of a fifty-person one without taking on fifty-person risk.

Building a Reversal Culture

The teams that handle this well tend to share a few habits, none of them exotic:

Small, atomic commits. Not because git history is beautiful, but because small commits make revert cheap. A 20-line commit can be reverted in one action. A 400-line commit requires surgery.

Feature flags over long-lived branches. A flag lets you ship code that's off, then turn it on, then turn it off again if it misbehaves. The reversal is instant and doesn't touch the deployment pipeline.

Rollback as a first-class operation. If rollback is documented, tested, and rehearsed, people will use it. If it's an emergency procedure, people will avoid the situations that might require it — which means they'll avoid shipping.

Naming the number. Tell your team the actual depth of the undo stack, the actual time to roll back a deploy, the actual cost of a bad migration. Ambiguity inflates perceived cost. Specificity deflates it.

None of this is about courage. It's about making the cost of being wrong legible, so that the decision to take a risk is a calculation rather than a guess.

Where This Leaves Your Next Commit

The 20-step undo history and the 33% revert rate are two views of the same underlying truth: developers are not optimizing for correctness, they're optimizing for recoverable progress. The stack depth sets the ceiling on how much speculative work is safe. The revert rate tells you whether people are using that ceiling or ignoring it.

The forward-looking move is to treat reversibility as a design constraint on your whole workflow, not just your editor. Ask, for every change you're about to make: if this is wrong, what's the cost of undoing it? If the answer is "one keystroke," move fast. If the answer is "a Slack thread and a client call," slow down and add a flag. If the answer is "we can't undo it," get a second pair of eyes and a backup.

Then look at your team's tooling and ask the harder question: which irreversible operations are irreversible only because nobody has bothered to make them reversible? A deploy without rollback. A migration without a down script. A config change with no version control. Each one is a place where the psychology of loss aversion is doing work that infrastructure should be doing instead.

The developers who ship the most aren't the ones who take the biggest risks. They're the ones who've made the small risks cheap enough that the big ones don't come up.