Super Undo
Undo you can see before you take it. A VS Code extension.
Cmd+Z is a guess. You hold it down, watch the file flicker backwards, and hope you stop in the
right place — and whatever it took away is off the screen before you can read it. Overshoot and
you are redoing your way forward, guessing again.
Super Undo replaces the guess with a list and a diff. Every save is a version.
Cmd+Alt+Z opens every version of the current file beside your code, newest first, and arrowing
through that list shows you each one diffed against what is on screen right now. You read the
change before you accept it, you jump straight to the version you want instead of stepping
through everything in between, and nothing is written to the file until you say so.
Versions are stored in a shadow git repository outside your project — which is what makes the
list long enough to be worth having. Your own repo, branches, staging area and commit history are
never touched.
Installing
Not on the Marketplace yet. Build a .vsix and install it:
git clone https://github.com/mehradamiri/super-undo.git
cd super-undo
npm install
npx @vscode/vsce package
code --install-extension super-undo-0.1.0.vsix
Requires VS Code 1.100 or newer and git 2.32 or newer.
Using it
| Action |
Keybinding |
| Undo — list every version of this file |
Cmd+Alt+Z / Ctrl+Alt+Z |
| Apply the version you are looking at |
Cmd+Alt+Enter / Ctrl+Alt+Enter |
| Browse recent changes across the workspace |
Cmd+Alt+R / Ctrl+Alt+R |
The list lives in the File History panel in the sidebar, each row carrying +/− line counts
and how long ago that version was saved — enough to recognise the change you are looking for
before you open it. It sits beside your code rather than on top of it, so the history and the diff
are readable at the same time.
The keyboard lands in that list, on the newest version that actually differs from what is on screen,
with its diff already open. Arrow up and down and the diff follows the selection, so you read your
way back through the file rather than guessing how far to go. The version you are looking at is
coloured and marked with a ●, which the selection highlight cannot tell you — that only says where
the keyboard is, and it fades as soon as you click into the diff. Cmd+Alt+Enter applies whichever
version you are looking at, and the ✓ on a row does the same with the mouse.
When you apply a version it becomes an ordinary unsaved edit, so a plain Cmd+Z still reverses it
and nothing reaches disk until you save. Set superUndo.applyAndSave if you would rather it save
immediately.
Backing out of the list costs nothing, so there is no wrong place to look. A browse leaves no
trace: any version diffs VS Code tries to restore after a restart are closed on startup, so a
session always begins on your actual files rather than on a stale view of an old one.
The Super Undo view in the activity bar holds four panels:
- Recent Changes — every file that changed recently, each showing its last five versions with
+/− line counts. This is the whole-workspace view: what happened where, without having to
open each file to find out.
- File History — every stored version of the active file, and where
Cmd+Alt+Z puts you.
Select two entries to diff them against each other, or pin one so it is never thinned away.
- Deleted Files — files you deleted, restorable with one click. Content is captured before
the delete goes through and is exempt from thinning.
- What Gets Tracked — a checkbox tree of your workspace.
Recent changes
Cmd+Alt+R opens the same information as a picker, grouped by file, with the diff following your
selection — arrow through it to read each change, Enter to keep the diff open, or the ✓ button
to apply one on the spot. Typing filters by file name.
Five versions per file is a default, not a rule. Change it with superUndo.recentCount, or from
the list icon in the Recent Changes title bar, and any file with more history than that grows an
Older versions… row that opens its full list. Every row supports the same actions as File
History: diff, apply, apply-and-save, pin, and select two to compare.
Renames are followed exactly, using the editor's own rename event rather than git's similarity
guessing, so history survives a rename plus a large edit in the same move.
What gets tracked
Everything, until you say otherwise. Uncheck any folder or file in What Gets Tracked and it
stops being versioned; the choice is written to superUndo.exclude in workspace settings, so it is
visible, hand-editable and shareable with your team. The most specific rule wins, which means you
can uncheck src, re-check src/app, and uncheck src/app/legacy again.
A handful of exclusions are seeded on first run — node_modules, .git, build output — and they
show up as visibly unchecked boxes rather than invisible magic. Binary files and anything over
superUndo.maxFileSizeKB are skipped.
On secrets: files your .gitignore excludes, such as .env, are tracked by default. They
are the files git will never protect for you, which is exactly why they benefit most. The
tradeoff is that their contents sit in plaintext in the extension's storage folder. The shield
button in What Gets Tracked excludes the usual secret-bearing patterns in one click.
How it works
Each workspace folder gets a bare git repository under the extension's global storage, keyed by the
folder's real path. Saves are debounced and coalesced, so Save All across twenty files is one
snapshot, and a snapshot costs a fixed five git processes no matter how many files it covers:
hash-object --stdin-paths → update-index --index-info → write-tree → commit-tree → update-ref
If the resulting tree is identical to the previous one, nothing is written at all — that is what
absorbs format-on-save and autosave churn.
Every snapshot is a parentless commit under its own ref, rather than a chain of commits. Reading
one file's history means asking a single long-lived git cat-file --batch process what that path
pointed at in each snapshot, which stays fast into the thousands of snapshots. It also makes
thinning trivial: dropping a version is deleting a ref, with no history rewrite and no changed
SHAs.
Content is stored byte for byte. All git filters, hooks and user configuration are disabled inside
the shadow repo, so CRLF files, BOMs and unusual encodings come back exactly as they went in.
Retention
History is thinned as it ages rather than deleted:
| Age |
Kept |
| Under 24 hours |
every save |
| Under a week |
one per hour |
| Under 90 days |
one per day |
| Older |
one per week, indefinitely |
Nothing past the last tier is ever removed, and pinned versions, pre-delete captures and pre-rename
captures are exempt from thinning entirely. Adjust the tiers with superUndo.retention, or run
Super Undo: Thin History Now by hand. Super Undo: Show Storage Statistics reports snapshot
counts and on-disk size.
Settings
| Setting |
Default |
Meaning |
superUndo.exclude |
build output, node_modules, .git |
Globs that are not versioned |
superUndo.include |
[] |
Globs that override an exclusion |
superUndo.maxFileSizeKB |
2048 |
Skip files larger than this |
superUndo.debounceMs |
400 |
How long saves are coalesced |
superUndo.recentCount |
5 |
Changes shown per file in Recent Changes |
superUndo.baselineOnOpen |
true |
Capture a file when first opened, so its first save has a "before" |
superUndo.applyAndSave |
false |
Save immediately when applying a version |
superUndo.retention |
24h / 7d / 90d |
Thinning tiers |
superUndo.storagePath |
global storage |
Where shadow repos live |
Requirements
Git 2.32 or newer, discovered through VS Code's built-in git extension (so remote and WSL hosts
work). No runtime dependencies beyond that.
Development
npm install
npm run compile # or: npm run watch
npm run lint
npm test # 63 tests, ~6s: unit tests plus an activation smoke test, no editor required
Press F5 to launch an Extension Development Host with the extension loaded.
The store layer (src/store, src/git, src/tracking/policy.ts) never imports vscode, so it is
tested directly against a real git binary in a temp directory. Keep new storage logic on that side
of the line — ARCHITECTURE.md explains why, along with the storage model, the
write and read paths, and the invariants a change has to preserve. Read it before sending a patch.
Issues and pull requests are welcome. CI runs compile, lint and tests on Linux and macOS.
Known limits
- Two windows open on the same folder share one shadow repo. Writes are safe — they are serialised
through a cross-process lock — but the second window's history view may lag until it writes
something itself.
- Moving a project folder starts a fresh history, since repos are keyed by path.
License
MIT