zev undo takes back the last thing you did, whether a commit, merge, rebase, deleted branch or add, without ever overwriting work that isn't saved anywhere. zev recover brings back edits a command threw away. zev op log shows every change.
Made a commit too early, merged the wrong branch, deleted a branch you needed? Type `zev undo`. zev records every command that changes your repository, and undo takes the last one back. Type it again to go further back. `zev redo` puts back what undo took away.
```diagram
type: cards
title: What zev undo takes back
---
✓ | A commit | the branch goes back; your changes stay, staged, ready to commit again
⑂ | A merge or rebase | the branch and your files go back to how they were
🌿 | A deleted branch | it comes back, at the same commit
↪ | A switch | you're on the branch you were on, with its files
+ | zev add or zev rm | the file is unstaged, or back on disk
```
```bash
$ zev commit -m "Fix the login page"
$ zev undo
↶ Undid #12 zev commit -m "Fix the login page"
main 4f2a91c0 → 9b1e07d3
Changed your mind? zev redo
$ zev status --brief
# main
M login.html
```
## It never throws away unsaved work
Undo changes only what the command changed. If one of those files has an edit you haven't committed or staged, undo stops and names the file, so the edit is never lost:
```text
Not undone: these files have changes that aren't saved anywhere, and zev undo would overwrite them:
f.txt
Commit or stash them first (zev stash), or run it again with --force to overwrite them.
```
Edits to files the command didn't change are left as they are. Undoing a commit never touches your files at all: the commit's changes simply become staged again.
## Edits you threw away: zev recover
Some commands throw away edits on purpose: `zev restore <file>` discards your changes to a file, and `--force` on switch, undo or merge overwrites files. Before any of them runs, zev keeps a copy of every file whose contents aren't saved anywhere. If the command changes or removes one, zev says so and lists it under `zev recover`. If nothing was lost, nothing is listed.
```bash
$ zev restore notes.md
Your unsaved edit to notes.md was kept: zev recover 3 brings it back
$ zev recover
#3 just now before zev restore notes.md on main
notes.md
$ zev recover 3
restored notes.md
```
`zev recover` doesn't overwrite newer work either. If you've changed the file since, the kept copy is written next to it as `notes.md.recovered-3`, so you can compare them. `--force` overwrites instead, and `zev recover 3 --show notes.md` prints the kept copy without writing anything. zev keeps the last 200 of these, and `zev gc` keeps what they need.
## Every change, and going back to any of them
`zev op log` lists what zev did, newest first, with what each command moved:
```text
#14 2 min ago zev merge feature
main 7c03d1e2 → 2b9f4a10
#13 5 min ago zev branch -d old-idea
-old-idea (was 51aa0c3e)
#12 9 min ago zev commit -m "Fix the login page" (undone)
```
`zev op restore <n>` takes the repository back to how it was right after operation `n`: its branches, tags, what was staged, and your files. That is itself an operation, so `zev undo` takes it back.
```diagram
type: history
title: Undo and redo move along the operations, never deleting one
start: Operations
---
branch ops | accent
commit A ops | #1 zev commit "Start"
commit B ops | #2 zev merge feature
commit C ops | #3 zev branch -d old | tone bad | info A mistake
step zev undo | #3 is taken back: the branch is there again
commit D ops | #4 zev undo (#3) | tone good
step zev redo | would take it away again, until you do something new
```
## For scripts and AI agents
`zev undo`, `zev redo` and `zev op log` take `--json` and `--brief` like the other everyday commands. An agent can try a change, check it, and take it back with one command. When a file is in the way, the answer is data, not a sentence:
```bash
$ zev undo --json
{"error":"files have changes that aren't saved anywhere","code":"unsaved_changes","files":["f.txt"]}
```
## How this differs from Git
Git keeps a reflog for each branch, but going back means finding the right entry and choosing between `git reset --soft`, `--mixed` and `--hard`; the wrong one discards work. A deleted branch, a merge and a rebase each need a different recipe. In zev it's one command for all of them, it never discards work that isn't saved anywhere, and `zev op log` shows the whole repository's history of changes in one place.
| In Git | In zev |
|---|---|
| `git reset --soft HEAD~1` (undo the last commit) | `zev undo` |
| `git reflog`, then `git reset --hard HEAD@{2}` (undo a merge or rebase) | `zev undo` |
| `git reflog`, then `git branch name <hash>` (bring back a deleted branch) | `zev undo` |
| `git reflog` | `zev op log` |
`zev gc` keeps every commit the operation log needs, so an undone commit can always come back with `zev redo` or `zev op restore`.
Already pushed the commit you want to undo? Others may have it, so make a new commit that reverses it instead: [How do I…? › Undo a commit I already made](/docs/en/how-do-i).
Made a commit too early, merged the wrong branch, deleted a branch you needed? Type zev undo. zev records every command that changes your repository, and undo takes the last one back. Type it again to go further back. zev redo puts back what undo took away.
What zev undo takes back
✓
A commit
the branch goes back; your changes stay, staged, ready to commit again
⑂
A merge or rebase
the branch and your files go back to how they were
🌿
A deleted branch
it comes back, at the same commit
↪
A switch
you're on the branch you were on, with its files
+
zev add or zev rm
the file is unstaged, or back on disk
Terminal
$ zev commit -m "Fix the login page"$ zev undo↶ Undid #12 zev commit -m "Fix the login page" main 4f2a91c0 → 9b1e07d3 Changed your mind? zev redo$ zev status --brief# mainM login.html
Undo changes only what the command changed. If one of those files has an edit you haven't committed or staged, undo stops and names the file, so the edit is never lost:
Text
Not undone: these files have changes that aren't saved anywhere, and zev undo would overwrite them: f.txtCommit or stash them first (zev stash), or run it again with --force to overwrite them.
Edits to files the command didn't change are left as they are. Undoing a commit never touches your files at all: the commit's changes simply become staged again.
Some commands throw away edits on purpose: zev restore <file> discards your changes to a file, and --force on switch, undo or merge overwrites files. Before any of them runs, zev keeps a copy of every file whose contents aren't saved anywhere. If the command changes or removes one, zev says so and lists it under zev recover. If nothing was lost, nothing is listed.
Terminal
$ zev restore notes.md Your unsaved edit to notes.md was kept: zev recover 3 brings it back$ zev recover#3 just now before zev restore notes.md on main notes.md$ zev recover 3 restored notes.md
zev recover doesn't overwrite newer work either. If you've changed the file since, the kept copy is written next to it as notes.md.recovered-3, so you can compare them. --force overwrites instead, and zev recover 3 --show notes.md prints the kept copy without writing anything. zev keeps the last 200 of these, and zev gc keeps what they need.
zev op log lists what zev did, newest first, with what each command moved:
Text
#14 2 min ago zev merge feature main 7c03d1e2 → 2b9f4a10#13 5 min ago zev branch -d old-idea -old-idea (was 51aa0c3e)#12 9 min ago zev commit -m "Fix the login page" (undone)
zev op restore <n> takes the repository back to how it was right after operation n: its branches, tags, what was staged, and your files. That is itself an operation, so zev undo takes it back.
Undo and redo move along the operations, never deleting one
zev undo, zev redo and zev op log take --json and --brief like the other everyday commands. An agent can try a change, check it, and take it back with one command. When a file is in the way, the answer is data, not a sentence:
Terminal
$ zev undo --json{"error":"files have changes that aren't saved anywhere","code":"unsaved_changes","files":["f.txt"]}
Git keeps a reflog for each branch, but going back means finding the right entry and choosing between git reset --soft, --mixed and --hard; the wrong one discards work. A deleted branch, a merge and a rebase each need a different recipe. In zev it's one command for all of them, it never discards work that isn't saved anywhere, and zev op log shows the whole repository's history of changes in one place.
In Git
In zev
git reset --soft HEAD~1 (undo the last commit)
zev undo
git reflog, then git reset --hard HEAD@{2} (undo a merge or rebase)
zev undo
git reflog, then git branch name <hash> (bring back a deleted branch)
zev undo
git reflog
zev op log
zev gc keeps every commit the operation log needs, so an undone commit can always come back with zev redo or zev op restore.