Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Undo is why I experiment

This is one of the reasons I am comfortable being creative with jj.

If I make a mess, I usually do not clean it up by hand. I undo the operation.

jj undo

jj keeps an operation log: every commit, rebase, split, squash, bookmark move, and undo I asked it to do. jj undo steps back through that log.

It is not a time machine for the remote, but it is enough to make local experiments feel cheap.

If I undo too far, I can move forward again:

jj redo

When I reach for it

The simple case is after I run a command and immediately dislike the result:

jj squash
jj undo

This also pairs really well with agents.

If I ask an agent to resolve a conflict or reshape some code and the result is not going in the right direction, I do not need to manually reconstruct the old state. I can usually do:

jj undo
jj status
jj diff

Then I try again with a narrower prompt.

Why this changes behavior

Undo makes experimentation cheap. I can let an agent try something, inspect the diff, and back out quickly if the result is worse than the starting point.

When undo is not enough

If I need more context than “undo the last thing”, I look at the operation log:

jj op log

If I want to see what an operation changed:

jj op show -p

And if I want to restore a specific earlier operation:

jj op restore <operation-id>

Most of the time I only need the short version:

jj undo

That one command makes a lot of the other workflows feel less scary.