The undo button git never had.
Automatic safety‑net snapshots for any git repository — so you can never lose
work to reset --hard, clean -fdx, a bad rebase, or "oops I deleted it" again.
Zero dependencies · works in any repo · never touches your history.
pip install gitundo
Features · Quick start · Commands · Auto-guard · How it works · Recipes · Comparison · FAQ
Git only protects work you commit. Everything else — the half‑finished
refactor, the deleted file, the unstaged fix that took an hour — is one
reset --hard away from oblivion. gitundo is a safety net for exactly that:
gitundo snapstores the entire current state of your working tree (staged and unstaged and untracked) as a lightweight checkpoint.gitundo restorebrings any checkpoint back — even files you deleted.- The auto-guard (
gitundo autowrap) snapshots automatically before destructive commands likegit reset --hardorgit clean -fdx.
Checkpoints live on a hidden ref — refs/gitundo/checkpoints — so they are
ordinary git objects: deduplicated by git, visible in git log,
shareable, and safe. Your branches, commits, index and tags are never touched.
| 📸 Snapshot anything | Staged, unstaged, and untracked files, deletions, symlinks, binaries. Ignored files and the stash are never captured. |
| 🪂 Undo the un‑undoable | Recover files destroyed by reset --hard, clean -fdx, checkout -f, bad merges, editor mishaps — even files that were never committed. |
| 🛡️ Auto‑guard | Optional shell wrapper that snapshots before clearly destructive git commands. You are always one command from a safety net. |
| 🏷️ Tag & diff | Name checkpoints (gitundo tag demo-ready), inspect exactly what each one saved (gitundo diff). |
| 🔒 Zero‑invasion | Only a hidden ref is ever written. The index, working tree, and history stay exactly as they were. |
| 🪶 Zero dependencies | Pure standard library. Works everywhere git works. |
| 🚿 Prune | gitundo prune -k 50 keeps your latest 50 (+ tagged) and reclaims the rest. |
| 🧵 Library + CLI | Use it from your own scripts via from gitundo import core. |
| 🧑💻 VS Code extension | Official editor integration — sidebar checkpoints, one-click snapshot & restore, diff, tags and a live status bar (see extensions/vscode). |
# 1. install
pip install gitundo # or: uv tool install gitundo / pipx install gitundo
# 2. snapshot whenever you reach a point you might want to return to
gitundo snap "before the big refactor"
# ...edit files, experiment, break things...
# 3. bring back the state from any snapshot
gitundo list # see what you've saved
gitundo restore # latest snapshot
gitundo restore 2 # two snapshots ago
gitundo restore before-the-big-refactor # by taggitundo on # mark this repo as guarded
gitundo autowrap # install the shell wrapper (one time, per machine)The official gitundo extension puts a 🛟 GitUndo view in your Activity Bar: snapshot with one click, browse checkpoints, diff what each one saved, and restore from the right-click menu — all without touching your commits.
git clone https://github.com/xrchris7/gitundo
cd gitundo/extensions/vscode
npm install && npm run package # -> gitundo-<version>.vsix
code --install-extension gitundo-0.1.0.vsix
(Needs the CLI installed: pip install gitundo.) Full details in
extensions/vscode/README.md.
Now every time you run a destructive command, gitundo quietly saves a checkpoint first:
$ git reset --hard HEAD~3
gitundo snapshot before git reset --hard → 9f3a1c2
HEAD is now at 7b8c9d0 add feature
$ git clean -fdx
gitundo snapshot before git clean -dfx → 0e5d2b1
Removing build/cache/
# hours later — "wait, that reset was a mistake" →
$ gitundo restore
✔ restored working tree to latest (14 file(s) written, 0 removed)
Disable the guard at any moment with export GITUNDO_DISABLE=1.
| Command | What it does |
|---|---|
gitundo snap [msg] [-t TAG] |
Snapshot the current working state. |
gitundo list [-n N] [--tags] |
List checkpoints, newest first. |
gitundo restore [SEL] [--index] [--hard] [--delete-extraneous] |
Restore the working tree to a checkpoint. |
gitundo diff [SEL] [--from SEL] [--workdir] |
Show what a snapshot saved, or diff two snapshots. |
gitundo tag NAME [SEL] / gitundo untag [NAME] |
Give checkpoints readable names. |
gitundo prune -k N |
Delete old checkpoints (tagged ones survive). |
gitundo status |
Guard state + recent checkpoints + storage used. |
gitundo on / gitundo off |
Enable/disable the guard for this repo. |
gitundo autowrap [--uninstall] |
Install/remove the destructive-command shell wrapper. |
gitundo help |
Full command reference. |
Selectors — everywhere a checkpoint is expected:
latest | N (0 = latest, 1 = the one before…) | a tag name | an object-id prefix
Full reference in docs/CLI.md.
gitundo autowrap adds a tiny function to your ~/.bashrc / ~/.zshrc that
intercepts git and, only when the command is clearly destructive,
snapshots first, then runs your command normally (stdin/stdout/exit code all
inherited). Nothing else changes — git status is never slowed down.
Currently guarded: git reset --hard, git clean -dfx, git checkout -f /
-- / ., git restore, git rm, git branch -D, git update-ref, plus
plain-shell rm -rf, rmdir, shred, mv/cp, truncate, dd and
in-place sed -i-style edits when run through the wrapped git.
History operations like
merge,rebase,revertandcherry-pickare deliberately not guarded: git's own reflog already protects them and they never delete uncommitted work — auto-snapshots would only add noise.
Snapshots are plain commits hanging off a hidden ref:
git commit ← the snapshot
tree f02a9… ← complete working state: tracked + untracked files as-is
author gitundo <gitundo@localhost> ← never impersonates you
message before-the-big-refactor (subject)
snapshot-of: a1b2c3d ← your HEAD at capture time
created-by: gitundo
refs/gitundo/checkpoints o3 → o2 → o1 → … (linear chain of snapshots)
refs/gitundo/tags/demo-ready → o2 (tags are lightweight refs)
Because a checkpoint is a real commit, git does the heavy lifting for you:
- Deduplication is free. Ten snapshots of an almost-unchanged repo add only a few objects — identical file content is stored once, forever.
- Restore never rewrites history. It writes files back into your working tree. Committed work is left alone (it's already safe).
- You can inspect them with plain git:
git log refs/gitundo/checkpointsand even push the ref to back your safety net up on a remote.
- The working tree, index, branch refs and tags are never modified by snapshot / list / diff.
- Restore never deletes files that exist only in commits newer than the
checkpoint, and never deletes untracked files (unless you pass
--delete-extraneous). - Restore never overwrites a file with local edits — they are parked as
*.gitundo-keepand reported (pass--hardto overwrite instead). - Snapshot commits are authored
gitundo, so they are instantly recognisable ingit logand can never be mistaken for (or signed as) your work. - Every command degrades gracefully: if gitundo can't run, your git command still runs.
- Not a backup tool for
.gititself, and it does not protect committed history (reflog + remotes already do). - Not a replacement for good commits — it protects the stuff between them.
Recover from git clean -fdx (deleted untracked work):
gitundo snap # do this BEFORE you clean
git clean -fdx # ...or let the auto-guard snapshot for you
# hours later:
gitundo list
gitundo restore 0 # everything is back, as untracked filesUndo a wrong git reset --hard (uncommitted + committed work):
gitundo snap # before the reset
git reset --hard HEAD~5
gitundo restore # working tree is exactly what you snapshotted
git reset --hard <your branch tip> # then optionally re-point your branchBranch experiments without fear:
gitundo snap exp-start
git checkout -b experiment
# ... go wild ...
git checkout main
gitundo restore exp-start # clean tree exactly as you left itBefore an AI agent / co-pilot edits your repo:
gitundo snap "before agent run"
# let the agent do its thing; if it trashes files, gitundo restoreIn CI / scripts (zero output unless something is wrong):
gitundo snap -t ${GITHUB_SHA} || true # snapshot, never fail the buildAs a library:
from gitundo import core
core.snapshot(path=".", message="deploy preflight", tag="pre-deploy")
cps = core.list_checkpoints()
core.restore(path=".", selector="pre-deploy")| Tool | What it does | How gitundo differs |
|---|---|---|
git stash |
Temporarily shelves a single change set | Checkpoints stack: full history of every intermediate state, browseable & restorable by tag/number |
| reflog | Undoes committed operations | gitundo protects uncommitted state, which reflog can't |
ugit / gitjk |
Interactive recipe for reversing specific git commands | gitundo is automatic + non-interactive; snapshots include untracked files & deletions |
git-snap |
Manual snapshot to a side branch | gitundo: full undo cycle (snap → list → diff → restore), tags, guard, prune |
jj / agents' checkpoints |
Continuous op-log / per-session snapshots | gitundo rides on your plain git (no new VCS), opt-in per repo, no config |
Does it slow git down? Only the commands you ask it to guard, and only for the brief moment a checkpoint is written. Ordinary commands pass straight through.
Where does the data live? In your repo's own .git object store, under
refs/gitundo/. There is no daemon, no database, nothing to corrupt
independently of git.
Can I push checkpoints to a remote? Yes — they're refs:
git push origin refs/gitundo/checkpoints:refs/gitundo/checkpoints.
Is this safe for huge monorepos? Snapshots reuse git's own content addressing, so unchanged content costs almost nothing. Files larger than ~64 MB are skipped for byte-comparison during restore (still snapshotted).
How do I reclaim space? gitundo prune -k 20, then occasionally
git gc --prune=now.
Where are my checkpointed files if the working tree is clean? If a snapshot captured nothing new, gitundo says so and stores nothing.
Contributions are very welcome — docs, tests, shell guards, integrations
(IDE, pre-commit, Git hooks), and more destructive-command patterns. See
CONTRIBUTING.md. The codebase is intentionally small:
src/gitundo/core.py ~ the engine (snapshot, restore, diff, prune, guard)
src/gitundo/cli.py ~ the command-line interface
tests/ ~ 75+ tests against real throwaway git repositories
extensions/vscode/ ~ the official VS Code extension (sidebar, commands)