My most frequently used Jujutsu VCS commands
A cheat-sheet of jj commands you're most likely to need day-to-day using jj as a git replacement.
by Danver Braganza on 2025-06-21
A bit over three months ago, I switched to using the Jujutsu Version Control
System as my daily-driver frontend to
git
. Since then I’ve been able to refine my workflow to the point where I am
much more productive than I was with git
. A key component of those
productivity gains was becoming familiar with just a few commands. I’m sharing
these commands with you as a cheat-sheet if you are considering replacing git
with jj
.
On the 7th of April, 2025, I joined Imbue as a Member of
Technical Staff. At Imbue, git
is the standard VCS used by the engineering team.
I had been curious about the Jujutsu Version Control System (jj), and decided
to attempt to make the switch while joining.
Jujutsu makes it easy to interoperate and collaborate with others using a git
repository, but memorizing the idiomatic replacements to my existing git
workflow with the equivalent jj
commands took a bit of time. Answers to my
questions were availible in many excellent online resources like Steve Klabnik’s
Jujutsu
Tutorial
and the jj reference.
However, this would come at the expense of pulling me out of the flow of the
task I was working on.
Over the past 3 months, I have been refining the jj
commands that I keep in my
short-term memory, to build a smooth process that is a superior replacement for
the git
flow I previously enjoyed. I find myself having to consult the
references extremely rarely–not because I have committed more of jj
to memory,
but because I have learned the subset of jj
that is likely to come up during the
working day.
I believe that Zipfian distributions rule over many of our human experiences. In Zipfian distributions, the frequency of any outcome is inversely proportional to its rank, meaning that the second most-common outcome occurs roughly half as often as the most common, and so on. In practice, this means the distribution is dominated by the few most-common outcomes.
You might also think of the Pareto Principle or 80-20 rule which states that 80% of the outputs are caused by 20% of the inputs. What follows are my “20% inputs” that I found most useful.
I generated this list by running the following shell snippet:
history | # All my history
grep "jj" | # Find only the commands with jj in them
grep -v grep | # Exclude grep
# Remove the line number that history prints
sed 's/^ *[0-9]\{1,\} *//' |
# Duplicate commands without their final argument
sed -E 'h; s/[^[:space:]]+[[:space:]]*$//; G' |
sort | uniq -c | sort -n | # Standard UNIX-ism to order by count
tail -n 40 # Give me the highest 40 frequencies
I chose to duplicate commands without their final argument so that commands that only varied by the final argument would be grouped together and counted. I then edited the results by hand, taking out commands that I no longer use or commands that had been incorrectly truncated.
The final result looked like this. I’ve removed the exact counts, but you can see what amounts to a power law.

A look at each of the commands
jj edit <-r/-b> <ident>
I was surprised to find that jj edit
is my most commonly used command. There
are two main use cases:
The first is as a replacement for git switch
/git checkout
.
The second is to jump back in time to fixup a prior revision if I’ve forgotten
something. With git, I would infrequently use git rebase -i
to edit a prior
commit. Since that operation was quite tedious, I would only edit previous
commits in severe cases. Because jj
reduces the friction to editing prior
changes, I find myself doing it much more often.
jj b c -r@ <branchname>
This is shorthand for jj bookmark create --revision @
, and @
itself is
shorthand for the current revision.
This is the equivalent to git’s git checkout -b <branchname>
or
git switch -c <branchname>
, both of which begin a new branch.
Bookmarks in jj
behave similarly to branches when uploaded and viewed in Git
hosting platforms. There are a few small differences when viewing and editing
them locally, which you can feel your way through.
jj rebase -b@ -dmain
The jj
equivalent to git rebase
In my workflow, I often want to rebase my current branch onto main. I used to spell this in various different ways, some of which dynamically depended on the name of the bookmark I was rebasing.
I’ve recently settled on jj rebase -b@ -dmain
which does not vary each time I
call it. This is constantly accessible through C-r
in my terminal, and it
always does the right thing.
jj show
and jj diff
I seem to use jj show
and jj diff
interchangeably to view the changes that
are pending with the current revision. When called with no arguments, they
assume the default argument of -r@
which signifies the current revision.
Less frequently, I also use these commands to look at other revisions in the tree when I just want to view the changes without visiting that revision.
I also use jj diff
to specifically look at the diff of single files, or to see
changes between revisions, but these occurrences are very rare.
jj new -r main
I use this command to start a new branch off main. Usually I will follow this up
with jj b c -r@ <branchname>
. This corresponds to the named bookmark
workflow
described at that link.
jj git fetch
Equivalent to git fetch
, this updates my local state to be the same as the
remote.
A couple of caveats to keep in mind when using this: * This automatically updates all named, non-owned bookmarks, even the ones I’m not currently visiting. In particular, this will automatically update main. * This will automatically delete any bookmarks that have been deleted from the remote repository. Usually they have been deleted by me, because I merged and deleted them in Gitlab, but I can imagine this could drop a bookmark that I wanted.
jj restore
jj restore
is an analog to git restore
. It allows you to checkout a
file from a given revision. For old-timers who were used to the old
git checkout --
syntax, this is much more intuitive to learn and use.
You could theoretically, use jj restore filename --from some-revision --to
other-revision
, to restore a file between two revisions without checking them
out yourself. When I’m restoring a file I’ll usually want to examine how that
file is going to interact with the other files around it, and to run tests. I’ll
first move to the destination revision, and then restore to the current revision
(@
) which is the default behaviour when --to
is not passed.
jj git push
Just like git push
, this will push updates to your tracked bookmarks to the
remote repository.
I almost always use the flag --allow-new
, which allows new bookmarks I’ve
created to be pushed to the remote. In my workflow, there is never an occasion
where I would want to have a branch locally that isn’t pushed up to my remote.
If you need to, jj
can be configured to refuse to push certain commits to
git
jj b f <branchname>
Short for jj branch forget <branchname>
, this command will remove the branch
from your local set of bookmarks, while still keeping it in the remote. This is
useful when I need to check out a colleauge’s branch to inspect it, but don’t
want to stay subscribed to edits until that branch closes.
jj desc -m <description>
This command sets or changes the description for the current revision. Unlike
git, you are allowed to have revisions without descriptions, but jj
will
refuse to push them to remotes.
Although jj new -m <description>
exists, I never use that, and instead choose
to use a second command to set the description.
jj st
Just like git status
, this will get the status of the current revision in jj
.
Unlike git, in jj
you are always working on a revision, and so there’s
never the concept–or worry–of a dirty working copy.
jj tug-
Bookmarks in jj
do not automatically update. Since my preference is to commit
often and to push early, I’m usually adding commits on top of bookmarks, and
then pushing them.
jj tug
is an alias that I found online attributed
here.
It updates the closest bookmark ancestor to point to the current revision,
giving me an easy command to type before I jj git push
To set it up, I just add the following two commands to my .jjconfig.toml
:
[aliases]
tug = ["bookmark", "move", "--from", "heads(::@- & bookmarks())", "--to", "@"]
tug- = ["bookmark", "move", "--from", "heads(::@- & bookmarks())", "--to", "@-"]
tug-
updates the bookmark to the previous revision, while tug
updates it to
the current one. It’s useful to have both versions, since you might be working
on the current revision, and so don’t want to push it just yet.
jj log
Similarly to git log
, this shows the current history of all revisions.
jj abandon
I almost always use jj abandon
on leaf revisions, to discard a draft of an
idea or a false start. One gotcha to be careful of is that if you jj abandon
a
commit with a bookmark, jj
will also delete that bookmark. If you then do a jj
git push
, this will push that deletion to the remote, potentially closing your
open pull requests.
You can abandon
revisions that have descendants, in which case all the
descendants will be rebased onto the parent. This will be as if the commit
you’ve abandoned never existed. Personally, I’ve never had to abandon
an
intermediate commit, but it’s good to know that it’s possible.
Honourable mention
Before closing, I wanted to make sure I talked about the following commands which I’ve fished out of the long tail. Although used less often, I think they’re worth discussing because they are useful in error recovery or during setup.
jj mine
This is another alias, defined as
[aliases]
mine = ["bookmark", "list", "-r", "mine()"]
jj mine
prints out the bookmarks/branches that I am currently working on, when
I want to take stock and switch between them.
jj undo
Short for jj operation undo
, jj undo
is a lifesaver! I cannot think of an
equivalent for git
although having ohshitgit.com on
your browser bookmarks toolbar comes close.
Exactly what it says on the tin, jj undo
will reverse the last operation you
performed, allowing you to recover from mistakes or unexpected behaviour.
As you can see, I don’t have much reason to call this function, but knowing that it’s there makes me breathe easier.
jj git init --colocate
This is the command that gets you started by transforming a local git
repository into a jj
repository. If you have read this far, you’re obviously
quite interested in how jj
does things.
The best way to learn how to use jj
is through doing. Let this be the sign
you’ve been waiting for, and give jj
a
try!