Skip to content
xrchris7Public

About

Automatic safety-net snapshots for any git repo — the undo button git never had. Never lose work to reset --hard, clean -fdx, a bad rebase or an accidental delete. Zero dependencies.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

🛟 gitundo

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

PyPI version Python versions License: MIT CI VS Code extension

Features · Quick start · Commands · Auto-guard · How it works · Recipes · Comparison · FAQ


The one-paragraph pitch

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 snap stores the entire current state of your working tree (staged and unstaged and untracked) as a lightweight checkpoint.
  • gitundo restore brings any checkpoint back — even files you deleted.
  • The auto-guard (gitundo autowrap) snapshots automatically before destructive commands like git reset --hard or git 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.


Features

📸 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).

Quick start

# 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 tag

The one-command setup you'll actually use

gitundo on        # mark this repo as guarded
gitundo autowrap  # install the shell wrapper (one time, per machine)

Editor integration (VS Code)

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.


Commands

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.


The auto-guard

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, revert and cherry-pick are deliberately not guarded: git's own reflog already protects them and they never delete uncommitted work — auto-snapshots would only add noise.


How it works

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/checkpoints and even push the ref to back your safety net up on a remote.

Guarantees

  • 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-keep and reported (pass --hard to overwrite instead).
  • Snapshot commits are authored gitundo, so they are instantly recognisable in git log and can never be mistaken for (or signed as) your work.
  • Every command degrades gracefully: if gitundo can't run, your git command still runs.

What gitundo deliberately is not

  • Not a backup tool for .git itself, and it does not protect committed history (reflog + remotes already do).
  • Not a replacement for good commits — it protects the stuff between them.

Recipes

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 files

Undo 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 branch

Branch 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 it

Before an AI agent / co-pilot edits your repo:

gitundo snap "before agent run"
# let the agent do its thing; if it trashes files, gitundo restore

In CI / scripts (zero output unless something is wrong):

gitundo snap -t ${GITHUB_SHA} || true     # snapshot, never fail the build

As 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")

Comparison

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

FAQ

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.


Contributing

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)

License

MIT

About

Automatic safety-net snapshots for any git repo — the undo button git never had. Never lose work to reset --hard, clean -fdx, a bad rebase or an accidental delete. Zero dependencies.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages