Jujutsu VCS: My Personal Cheat Sheet



A practical quick-reference for the JJ (Jujutsu) version control system: not a tutorial, but a ready-to-use guide with the most essential commands and workflows.
š§ Heads-Up: This Is Not a Tutorial!
If you're expecting a walkthrough on how to use Jujutsu (JJ) from scratch, this post probably isn't what you're looking for.
There are already some great tutorials out there, including the excelent official one.
While this post serves as a cheat sheet and not a beginner
tutorial, if you're looking for a video walkthrough to complement it,
check out DevOps Toolbox
awesome video:
š¦ Why JJ?
Jujutsu is a powerful version control system for software projects. You use it to get a copy of your code, track changes to the code, and finally publish those changes for others to see and use. It is designed from the ground up to be easy to use, whether you're new or experienced, working on brand new projects alone, or large scale software projects with large histories and teams.
What sets JJ apart is its focus on automatic working commits, which track your changes continuously without the usual manual commit overhead. This design makes JJ extremely fast, highly scriptable, and encourages maintaining a cleaner, more intuitive project history.
That said, JJ introduces new workflows and concepts that may feel
unfamiliar at first. Common operations like merge
or rebase
behave
differently, so keeping a quick reference or cheat sheet handy can
make your transition smoother and more productive.
š The cheat sheet!
Basic Commands
jj git init | Inits jj with git backend |
jj st | prints status |
jj status | same as above |
jj | prints log |
jj log | same as above |
jj diff | diffs current change |
jj diff –git | diffs current change in git style |
jj desc | adds a description to the current change |
jj describe | same as above |
jj describe -m "..." | same as above, but inline |
jj new | ends a change and inits a new one |
jj new -m | ends a change and inits a new one |
setting a description | |
jj file annotate filename | annotates filename, similar to |
git blame or hg annotate | |
jj undo | undoes last jj command |
jj squash | combines changes and descriptions |
jj squash file | instantly squashes file down to |
last change | |
jj squash -i | opens an ui to select |
what to squash | |
jj abandon | drops everything on current change |
and starts a new one in place. | |
jj split | splits current change creating a new change with the selected content on @- |
jj commit -m "..." | adds a description for current change and starts a new one (equivalent to jj desc -m "..." && jj new ) |
Time Traveling
jj new -B @ -m "msg" | Creates a new change B efore current (@) |
setting a description | |
jj edit change-id | Moves to whathever change-id |
jj next –edit | Jumps to next change |
jj edit @+ | |
jj edit @- | Jumps to prev change |
Branchless Workflow
jj new change-id | Creates a new change before a |
given change-id |
More on log
jj log -r revsets | Applies a revset to log, similar |
to hg(1) (Mercurial) | |
jj --limit number | Limits log lines |
jj log -r 'heads(all())' | Shows all 'heads' or 'forked' |
changes top change |
Merging
Note: there's no jj checkout
nor jj merge
, those used to exist but are
now deprecated. We use jj new ...
for everything.
jj new x yz -m "message" | Creates a new change by merging |
x and yz change ids defining | |
a message "merge". User can | |
merge as many change-ids as | |
they wish. |
Rebasing
Notice: rebase always
succeeds even with conflicts pending.
jj rebase -s o -d x | Rebases change with id o (source) |
to change with id x (destination) |
Merge Conflicts
If a conflict is present, jj st
will tell you on which files
you need to look for conflicts and solve.
Just save your file after solving and nothing else, no need to continue anything.
jj resolve | Opens an ui to choose how to solve conflicts |
(plus: mouse is supported) |
Log - Template Language
jj log -T 'TEMPLATE' | Applies a template to jj log |
jj help -k templates | Print the help doc with all template |
language options |
A bunch of options are provided to go with templates, some examples:
Format log to have commit-id, new line, description and ----
before
next log entry.
jj log -T 'commit-id ++ "\n" ++ description ++ "\n------\n"'
Get short commit IDs of the working-copy parents:
jj log --no-graph -r @ -T 'parents.map(|c| c.commit_id().short()).join(",")'
Show machine-readable list of full commit and change IDs:
jj log --no-graph -T 'commit_id ++ " " ++ change_id ++ "\n"'
Log - Revset Language
jj log -r 'REVSET' | Applies a revset to jj log |
jj help -k revsets | Prints the help doc with all revsets |
language options |
A bunch of options are provided to go with templates, some examples:
Show the parent(s) of the working-copy commit (like git log -1 HEAD
):
jj log -r @-
Show all ancestors of the working copy (like plain git log
):
jj log -r ::@
Show commits not on any remote bookmark:
jj log -r 'remote_bookmarks()..'
Show commits not on `origin` (if you have other remotes like `fork`):
jj log -r 'remote_bookmarks(remote=origin)..'
Show the initial commits in the repo (the ones Git calls "root commits"):
jj log -r 'root()+'
Show some important commits (like `git āsimplify-by-decoration`):
jj log -r 'tags() | bookmarks()'
Show local commits leading up to the working copy, as well as descendants of those commits:
jj log -r '(remote_bookmarks()..@)::'
Show commits authored by "martinvonz" and containing the word "reset" in the description:
jj log -r 'author(martinvonz) & description(reset)'
Diff - Fileset Language
jj help -k filesets | Prints the help doc with all filesets |
language options |
A bunch of options are provided to go with templates, some examples:
Show diff excluding Cargo.lock
.
jj diff '~Cargo.lock'
List files in src
excluding Rust sources.
jj file list 'src ~ glob:"**/*.rs"'
Split a revision in two, putting `foo` into the second commit.
jj split '~foo'
JJ & Git - Co-locate
This means jj side by side with git.
Your project will have on its root, both a .jj
and a .git
directory.
jj git init –colocate . | Set a new version control |
with both jj and git, or if | |
git is present, make arrangements | |
so both can be colocated. |
Simple workflow to main branch:
jj log
jj commit -m "msg"
jj bookmark set --revision @- main
jj git push -r @-
jj op log
Workflow to push to a 'new git branch'
jj
jj bookmark set -r @ 'feat/blahk'
jj git push -r @ --allow-new --remote origin
To the next pushes, simply:
jj git push -r @
Some other useful commands since jj/git colocated relies heavily on bookmarks:
jj bookmark move --from=@- --to=@
jj bokmark delete '...'
jj bookmark track main@origin
jj git push --all --deleted
A complete set and more examples with:
jj help -k bookmarks
Note, after performing jj motions, probably the git part of the thing will be HEADLESS or in a detached state.
If you wish to perform "regular" git operations, most probably you need to first "git checkout" to a branch.
Stageless Workflow
Jujutsu has no traditional staging area like Git. This means changes you make in your working copy are immediately part of your current change (also called a working commit). So what if youāve modified 10 files but only want to ācommitā 2 of them?
š” You can mimic partial commits with a few simple commands.
Special thanks to @Cassiano for for pointing this out to me!
šŖ The trick: jj split
Use jj split
to break your current change into two:
jj split
This opens a TUI (Text User Interface) where you can select which files or even hunks to split into a new change.
What happens:
-
The selected changes go into a new change (on top of your current one)
-
The rest stay in the original change
š¬ Think of it like āstagingā part of your work and ācommittingā it, without ever touching an index.
š§Ŗ Example Workflow
- You edit
fileA.ts
,fileB.ts
, andfileC.ts
. - But you only want to commit the changes to
fileA.ts
. - Run:
jj split
- Select only
fileA.ts
in the UI. - Give the new change a description with:
jj describe -m "Refactor fileA logic"
Now your fileA.ts
changes are safely committed. You're still on the
remaining changes for fileB.ts
and fileC.ts
.
š You can repeat the process to incrementally split off changes until you're happy.
š Wrapping Up
This cheat sheet is not a comprehensive tutorial, as said before, itās
a quick reference, a jumping-off point, and a distilled
guide for navigating jj
. Whether you're exploring jj
out of
curiosity or looking to speed up your workflow without staging
overhead, I hope this post gave you enough to get started with
confidence.
Remember: tools donāt define your flow, your habits and clarity
do. If jj
helps you think more clearly about your changes, then
itās doing its job. And if not? Thatās fine too, thereās always git
or even hg
right around the corner.
If you have tweaks, corrections, or your own tricks, Iād love to hear them!
Thanks for reading! š§ š»š„