Zero-side-effect working tree snapshots for Git.
git snapshot # save everything, index and worktree untouched
git snapshot list # see what you've got
git snapshot show # what's in the latest snapshot vs HEAD
git snapshot restore 0 # bring it all backCreates a real commit from your full working tree (tracked, untracked, staged,
unstaged) without touching the index or working tree. Snapshots are stored in
the reflog and expire naturally with git gc.
git snapshot # default message: "snapshot"
git snapshot -m "before refactor" # custom message
git snapshot -i # include ignored filesgit snapshot list2dde69e snapshots@{0} before refactor 2026-02-20 11:15:34 +0100
53cb51e snapshots@{1} snapshot 2026-02-20 11:10:02 +0100
git snapshot show # stat summary, latest snapshot vs HEAD
git snapshot show 2 # stat summary, snapshots@{2} vs HEAD
git snapshot show 0 -p # full patch
git snapshot show 0 -- path # limit to specific pathsgit snapshot files # latest
git snapshot files 3 # snapshots@{3}Snapshots are regular commits, so standard Git syntax works:
git show refs/snapshots@{0}:path/to/filegit snapshot restore 0 # restore everything
git snapshot restore 2 path/to/file.txt # restore specific filesNote: A full restore (
restore Nwith no paths) replaces the worktree with the snapshot's tree exactly. Tracked files that don't exist in the snapshot will be removed from the worktree (untracked files are left alone). Your committed history is never affected.
git snapshot drop 3 # remove snapshots@{3}git snapshot prints the commit SHA. It's a real commit, so you can use it anywhere:
sha=$(git snapshot)
git diff $sha HEAD
git log -1 $sha
git cherry-pick $sha
git show $sha:some/file.txt# symlink (updates when you git pull)
ln -s "$(pwd)/git-snapshot" /usr/local/bin/
# or copy
cp git-snapshot /usr/local/bin/Git automatically picks up executables named git-* on your PATH as
subcommands.
- Copies the index to a temp file (real index is never touched)
- Runs
git add -Aagainst the temp index to capture untracked files git write-treeto create a tree object from the temp indexgit commit-treeto wrap it in a commit (with HEAD as parent)git update-refto store the SHA inrefs/snapshotswith a reflog entry- Temp index is deleted; working tree and real index are unchanged
- Snapshots respect
.gitignoreby default; pass-ito include ignored files - Snapshots expire with
git gcaccording to your reflog expiry settings (default: 90 days for unreachable entries) - Only works inside a Git repository with at least one commit
- Snapshots are stored in
refs/snapshots, which is shared across linked worktrees. Use the snapshot message orgit snapshot listto identify which worktree a snapshot came from
66 tests (201 assertions) covering snapshots, restore, edge cases, and error handling:
bash test.sh- temptree - disposable Git worktrees for AI agents and throwaway experiments
MIT