Jujutsu in practice
Jujutsu is a version control system, an alternative to Git. This blog post is not a tutorial, but practical examples of how I use it. · Frankfurt, Germany · LobstersThis post is not about the Japanese martial arts Jiu-jitsu, it’s about a new
VCS, or version control system.
There are some great tutorials and introductions for
Jujutsu, short jj
, so I want to give some
insight in how I use it day to day for this website.
Initialize a repository
You can initialize jj
in an existing git
repository like this:
This will create a .jj
directory next to .git
.
You can now use both git
and jj
, although I wouldn’t recommend it.
There’s a work-in-progress native storage backend, but since all my projects
are git
repositories anyway, this works great for me.
Note that this is non-destructive; if you want to go back to git
, all it takes
is a rm -r .jj
.
Get an overview
Running jj log
in the repository for this very website gives this output:
This already shows one of the biggest differences, compared to git
:
There’s no branches, other than main
.
You can create branches, which are called bookmarks in jj
, but you don’t
need to.
Instead, you work mostly with changes1.
The terminal above shows the change w
(you can use the first letter to
reference changes; on your terminal it’ll be highlighted as well) as a parent
to x
, t
, y
and q
.
All these child-revisions don’t have a branch/bookmark, but they don’t need one.
You can see what’s in-flight at this repository better than with any git
repo,
especially if branches haven’t been cleaned up in a while.
Create a revision
My usual flow with git
is to leave changes in the staging area until I’m
ready to commit.
Sometimes, if I have to switch branches or want to save my work, I’ll stash
or create a WIP commit.
In jj
, there is no staging area—everything is a revision.
Let’s create a new revision on top of my revisions where I add atoms
functionality:
Running git log
again:
()
)
You’ll notice that our active revisions are now left-aligned, and the one to
add this very blog post has moved to the right.
There’s no hierarchy, they’re all descendants of Add weekly/166
.
After doing some work, e.g. adding a new atom, I can describe that revision
with jj describe
.
This is comparable to git commit
, but it doesn’t actually create a commit or
a revision, it only describes the current one.
Sometimes I want to update a previous revision, in this case Add atoms/1
.
I can run jj squash
to merge the current one with its parent.
Push and pull
To fetch new revisions, I run jj git fetch
; to push branches/bookmarks, I run
jj git push
.
This uses the same git
server it was using before.
Before pushing, I need to move my bookmark to the revision I want to push.
I push the main
branch to deploy my website, so if I wanted to publish my
atoms functionality (should I?), I would run jj bookmark set main -r p
before
pushing.
Rebase and split
Sometimes I need to rebase. Fortunately that’s a lot simpler than it is in
git
:
I can run jj rebase -s <source> -d <destination>
to move revisions around.
If I wanted support for atoms for this blog post, I would run
jj rebase -s q -d p
and it would move the revision for this blog post on top
of “Add atoms/1”.
jj
also does automatic rebasing, e.g. if you squash changes into a revision
that has descendants.
And if I have a revision that I’d like to be two, I run jj split
and
interactively select what belongs to which revision.
Undo
Undoing an (interactive) rebase in git
is not fun.
jj undo
undoes the last jj
operation, doesn’t matter if it’s abandoning
(deleting) a revision or doing a rebase.
This is a life saver!
You can also run jj op log
to display your last jj
operations.
Things I stumble upon
I’ve been using
git
for a long, long time.
My brain assumes that after a commit
, I’m working on the next one.
It also assumes that jj describe
does the same as git commit
(it does not).
I often describe a revision and continue editing files, which then erroneously
get added to the current revision.
I’m not saying this is wrong, it makes sense in the jj
world, but I keep
tripping over that and have to run jj split
to pull changes out again.
alterae on Lobste.rs pointed out
that you can describe and immediately create a new revision on top of it with
jj commit
. Thanks!
One other thing is that you cannot check out a revision directly (or maybe I
just don’t know how to), so when I’ve moved to a different revision and want
to move back, I run
jj new <revision>
, which creates an empty revision on top
of it.
This means that if I’m not done with the revision, I have to keep running
jj squash
to move changes into it.
gecko on Lobste.rs pointed out
that you can check out a revision directly with jj edit <revision>
. Thanks!
Why it works for me
A week ago, I removed jj
from my website’s repository, to see if I’d miss it.
I added it back the same day.
Jujutsu feels lighter than git
, while at the same time giving you a full
overview of what’s in-flight right now2.
Having no staging area means I only need to worry about revisions (see caveat
above).
If trying new things sounds fun to you, give Jujutsu a spin!
Further reading
- Official Jujutsu Tutorial
- Comparison with Git
- Steve’s Jujutsu Tutorial
- Chris Krycho’s jj init essay
- Chris Krycho’s video on jj
-
What’s cool about a
jj
change, is that updating it doesn’t change its ID. ↩ -
If you work in large projects with many contributors, you can tune your
jj log
to only your revisions. ↩