This post is not about the Japanese martial arts Jiu-jitsu, it’s about a newVCS, or version control system.There are some great tutorials and introductions forJujutsu, short jj, so I want to give someinsight in how I use it day to day for this website.
Initialize a repositoryYou can initialize jj in an existing git repository like this:
$ jj git init --git-repo .
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 projectsare git repositories anyway, this works great for me.
Note that this is non-destructive; if you want to go back to git, all it takesis a rm -r .jj.
Get an overviewRunning jj log in the repository for this very website gives this output:
$ jj log@ qzsvtxpv hey@arne.me 2024-10-21 09:58:06 e18f7532│ Add blog/jj-in-practice│ ○ yoxxsupn hey@arne.me 2024-10-20 22:55:03 ae5d9109├─╯ Add library/calibans-war│ ○ tvkvwslw hey@arne.me 2024-10-20 22:49:54 5e4dee1f├─╯ Add library/the-posthumous-memoirs-of-bras-cubas│ ○ pywmtrys hey@arne.me 2024-10-20 21:20:11 7bda14b7│ │ Add atoms/1│ ○ xnlzypwn hey@arne.me 2024-10-20 21:20:10 8a004404├─╯ Add atoms functionality◆ wxxtrmqk hey@arne.me 2024-10-20 16:18:15 main HEAD@git 1eb46c81│ Add weekly/166~
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’tneed to.Instead, you work mostly with changes1.
The terminal above shows the change w (you can use the first letter toreference changes; on your terminal it’ll be highlighted as well) as a parentto 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 revisionMy usual flow with git is to leave changes in the staging area until I’mready to commit.Sometimes, if I have to switch branches or want to save my work, I’ll stashor 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 atomsfunctionality:
$ jj new -r p
Running git log again:
$ jj log@ kxqvnxnw hey@arne.me 2024-10-21 10:03:20 22c020cf│ (empty) (no description set)○ pywmtrys hey@arne.me 2024-10-20 21:20:11 HEAD@git 7bda14b7│ Add atoms/1○ xnlzypwn hey@arne.me 2024-10-20 21:20:10 8a004404│ Add atoms functionality│ ○ qzsvtxpv hey@arne.me 2024-10-21 10:03:18 27229dca├─╯ Add blog/jj-in-practice│ ○ yoxxsupn hey@arne.me 2024-10-20 22:55:03 ae5d9109├─╯ Add library/calibans-war│ ○ tvkvwslw hey@arne.me 2024-10-20 22:49:54 5e4dee1f├─╯ Add library/the-posthumous-memoirs-of-bras-cubas◆ wxxtrmqk hey@arne.me 2024-10-20 16:18:15 main 1eb46c81│ Add weekly/166~
You’ll notice that our active revisions are now left-aligned, and the one toadd 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 revisionwith jj describe.This is comparable to git commit, but it doesn’t actually create a commit ora 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 pullTo fetch new revisions, I run jj git fetch; to push branches/bookmarks, I runjj 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 myatoms functionality (should I?), I would run jj bookmark set main -r p beforepushing.
Rebase and splitSometimes I need to rebase. Fortunately that’s a lot simpler than it is ingit: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 runjj rebase -s q -d p and it would move the revision for this blog post on topof “Add atoms/1”.
jj also does automatic rebasing, e.g. if you squash changes into a revisionthat has descendants.
And if I have a revision that I’d like to be two, I run jj split andinteractively select what belongs to which revision.
UndoUndoing 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 erroneouslyget added to the current revision.I’m not saying this is wrong, it makes sense in the jj world, but I keeptripping over that and have to run jj split to pull changes out again.~~
alterae on Lobste.rs pointed outthat you can describe and immediately create a new revision on top of it withjj commit. Thanks!
~~One other thing is that you cannot check out a revision directly (or maybe Ijust don’t know how to), so when I’ve moved to a different revision and wantto move back, I run jj new <revision>, which creates an empty revision on topof it.This means that if I’m not done with the revision, I have to keep runningjj squash to move changes into it.~~
gecko on Lobste.rs pointed outthat you can check out a revision directly with jj edit <revision>. Thanks!
Why it works for meA 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 fulloverview of what’s in-flight right now2.Having no staging area means I only need to worry about revisions (see caveatabove).
If trying new things sounds fun to you, giveJujutsu 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
jj change, is that updating it doesn’t change its ID. ↩jj log to only your revisions. ↩