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

Restoring file contents

Reset your progress

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

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

Let's say Alice accidentally deleted the project's README.md file. After that, she made more changes before realizing her mistake:

rm README.md
echo '    print("In soviet Russia, world greets you!")' >> hello.py
jj show
Commit ID: 79cda7b43c273bb0597b7888b2ff9d3afee4a568
Change ID: nwstlotvuwrnxrupxnplywqvkloupnxu
Author   : Alice <alice@local> (2025-08-31 16:15:13)
Committer: Alice <alice@local> (2025-08-31 16:15:13)

    (no description set)

Removed regular file README.md:
   1     : # jj-tutorial
   2     : 
   3     : The file hello.py contains a script that greets the world.
   4     : It can be executed with the command 'python hello.py'.
   5     : Programming is fun!
   6     : 
   7     : ## Submission
   8     : 
   9     : Run the following command to create the submission tarball:
  10     : 
  11     : ~~~sh
  12     : tar czf submission_alice_bob.tar.gz [FILE...]
  13     : ~~~
Modified regular file hello.py:
   1    1: for _ in range(10):
   2    2:     print("Hello, world!")
   3    3:     print("Hallo, Welt!")
   4    4:     print("Bonjour, le monde!")
        5:     print("In soviet Russia, world greets you!")

The tools we've learned about so far don't really help in this situation. Alice could jj undo the last snapshot, but that would undo her changes to hello.py as well. The same goes for jj abandon. Luckily, there's a better way:

jj restore README.md
Commit ID: f2922ddd5ad552e1e499b461b8ed900d047cea91
Change ID: nwstlotvuwrnxrupxnplywqvkloupnxu
Author   : Alice <alice@local> (2025-08-31 16:15:13)
Committer: Alice <alice@local> (2025-08-31 16:24:18)

    (no description set)

Modified regular file hello.py:
   1    1: for _ in range(10):
   2    2:     print("Hello, world!")
   3    3:     print("Hallo, Welt!")
   4    4:     print("Bonjour, le monde!")
        5:     print("In soviet Russia, world greets you!")

Perfect, that's just what we wanted! jj restore on its own restores all changed files in your working copy commit. However, if you give it the names of specific files as additional arguments, it will only restore those.

That's not all though, jj restore can do more than that.

We've learned a lot about how to create commits, but not much about what you can do with them. We can look at the state of our repository at a given commit by running jj new <change-id>, but that's about it.

jj restore can not only restore files to their state in the parent of the working copy commit. It can restore them to their state in any commit. You can use the --from flag to specify which commit to restore from.

For example, let's restore hello.py to the state where it had a functioning loop, but no translations:

jj restore --from 'description(substring:"Fix loop syntax")' hello.py
Commit ID: c72f36748528f6893316089590374efed90a4214
Change ID: nwstlotvuwrnxrupxnplywqvkloupnxu
Author   : Alice <alice@local> (2025-08-31 16:15:13)
Committer: Alice <alice@local> (2025-08-31 16:43:32)

    (no description set)

Modified regular file hello.py:
   1    1: for _ in range(10):
   2    2:     print("Hello, world!")
   3     :     print("Hallo, Welt!")
   4     :     print("Bonjour, le monde!")

Fascinating! As always when we're done with a task, we should remember to push to the remote.

jj commit -m "Remove translations"
jj bookmark move main --to @-
jj git push