Restoring file contents
Reset your progress
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("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
Now you have the skills to get yourself out of most problems that can come up when working with version control. Let's summarize what we've learned:
jj undo
can restore previous states of your entire repository step-by-step. Don't worry about making mistakes! Experiment freely andjj undo
if anything goes wrong.- If you want to work on a bookmark that only exists on the remote, for example after making a fresh clone of your repo, run
jj bookmark track
. - Combining two branches can lead to conflicts if they change the same part of a file. Resolve such conflicts by carefully removing the conflict markers to produce a sensible result.
- If you end up with commits you no longer need for whatever reason, deleted them with
jj abandon
. - You can restore the content of a file using
jj restore
. By default, it restores to the parent of your working copy, but you can specify any commit to restore from with the--from
flag.
Now you know pretty much everything you need. You should be productive and rarely get stuck. Some readers may decide to stop reading the tutorial here.
For those who want more, the next level will teach you how to rewrite history effortlessly. This skill will allow you to produce a much better commit history. Some projects like the Linux kernel or Jujutsu itself require their contributors to know these skills. Without them, they cannot meet the projects quality standards.
Aside from that, being able to rewrite history is simply freeing. You'll worry less about how to separate your changes into neat commits and what description to give them, because you can easily change these things later.
Nevertheless, feel free to take a long break before coming back to that. You have learned a lot so far and it will be benefitial to have mastered that with practice before continuing.
At this point, you should also start to explore the Jujutsu CLI a little bit on your own.
This tutorial is not a comprehensive reference of everything Jujutsu has to offer.
Would you like to display all commits made by a specific author?
Run jj log --help
to find out how.
Would you like to tweak the behavior of Jujutsu in some way?
Maybe the configuration guide can help you out.