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

Undoing mistakes

Reset your progress

To reset your progress to the start of this chapter, run the following command:

curl https://s2p2.github.io/jj-for-everyone/reset.sh | bash -s undo
cd ~/jj-tutorial/repo

Jujutsu keeps a log of every operation performed on the repository, not just the commit history. This lets you easily undo mistakes.

For example, let's fix a hastily written commit message. First, we'll check our current state.

cd ~/jj-tutorial/repo
jj log
@  pzsymsll alice@local 2025-09-10 20:52:56 1be9c292
│  (empty) (no description set)
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main git_head() 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

Making a Mistake

Let's add more greetings and create a commit with a poor description.

echo 'print("Hallo, Welt!")' >> hello.py
echo 'print("Bonjour, le monde!")' >> hello.py
jj commit -m "code improvements"
@  yxmkmosm alice@local 2025-09-10 20:53:46 d28a8261
│  (empty) (no description set)
○  pzsymsll alice@local 2025-09-10 20:53:46 git_head() 050b543b
│  code improvements
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

Undoing the mistake

To fix this, we restore the repository to its previous state with jj undo.

jj undo
@  pzsymsll alice@local 2025-09-10 20:53:46 94a7ca39
│  (no description set)
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main git_head() 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

We're back to the state before the bad commit. Now we can commit again with a better message.

jj commit -m "Print German and French greetings as well"
@  npnpqkvz alice@local 2025-09-10 20:54:33 8f11c4f5
│  (empty) (no description set)
○  pzsymsll alice@local 2025-09-10 20:54:33 git_head() df82ee49
│  Print German and French greetings as well
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

Undoing and Redoing Multiple Operations

jj undo works like Ctrl+Z; you can run it multiple times to go further back. It even undoes file system changes, because jj snapshots your workspace before running a command.

Let's undo the last three operations: the good commit, the file modifications, and the jj new main command from the previous chapter.

the good commit:

jj undo
@  pzsymsll alice@local 2025-09-10 20:53:46 94a7ca39
│  (no description set)
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main git_head() 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

the file modifications:

# hello.py
print("Hello, world!")
print("Hallo, Welt!")
print("Bonjour, le monde!")
jj undo
# hello.py
print("Hello, world!")

jj log to check:

@  pzsymsll alice@local 2025-09-10 20:52:56 1be9c292
│  (empty) (no description set)
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main git_head() 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

One last time: jj new main command from the previous chapter.

jj undo
@  wkqpyqlm alice@local 2025-09-10 20:52:56 640e22bf
│  (empty) (no description set)
│ ◆  lyquuqkl bob@local 2025-09-10 20:52:56 main 2ae165d3
│ │  Add submission instructions
│ │ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
│ ├─╯  WIP: Add for loop (need to fix syntax)
│ ◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
╭─┤  (empty) Merge code and documentation for hello-world
│ │
│ ~
│
◆  uvxzzlmr bob@local 2025-09-10 20:52:55 git_head() 60e09461
│  Document hello.py in README.md
~

The jj redo command re-applies undone operations, like Ctrl+Shift+Z. Let's use it to get back to our most recent state.

jj redo
jj redo
jj redo
@  npnpqkvz alice@local 2025-09-10 20:54:33 8f11c4f5
│  (empty) (no description set)
○  pzsymsll alice@local 2025-09-10 20:54:33 git_head() df82ee49
│  Print German and French greetings as well
◆  lyquuqkl bob@local 2025-09-10 20:52:56 main 2ae165d3
│  Add submission instructions
│ ○  vtnrtqsn alice@local 2025-09-10 20:52:56 push-vtnrtqsnrzqx d517a86d
├─╯  WIP: Add for loop (need to fix syntax)
◆  tlwyrrmy alice@local 2025-09-10 20:52:56 ffc6841f
│  (empty) Merge code and documentation for hello-world
~

Try jj redo one more time, you'd get an error that there's nothing to redo.

Important Considerations

  • Overwriting History: If you undo operations and then create a new one, the undone states become inaccessible via jj redo. This is similar to standard undo/redo stacks. However, unlike most graphical applications, Jujutsu has advanced commands to recover these "hidden" states, which is a topic for another day.

  • Remote Operations: Do not jj undo a push operation (e.g., jj git push). It only affects your local repository and can cause conflicts with the remote. If you do it by accident, immediately jj redo it.

  • Local History: The operation log is local to your machine and is not cloned or pushed. jj undo only works on the history created in your local repository clone.