I like to try things out. I like new, shiny, alternative stuff that is not hype yet. I created my first Twitter account when you could see the world timeline of tweets refresh in real time on the home page. I also like new ideas that build upon great systems in order to improve them or take them a few steps further. That’s why I use Zellij, not Tmux. That’s why I use Nushell, not bash, or zsh, as my main terminal shell. And that’s why I started using Jujutsu to version control my code.
Jujutsu is a version control system UX that builds upon multiple VCS backends (Git, Mercurial, Breezy…). Jujutsu (or JJ) provides a user-facing abstraction that makes your git workflow much more flexible.
For instance, there is no such things as branches. The closest equivalent is bookmarks. But bookmarks are more akin to mutable git tags. Git commits belong to a branch, and move when the branch gets merged into another. JJ puts this the other way round: bookmarks behave the way you’d expect a bookmark to behave: they can be moved around revsets (the jj equivalent of git commits). This alone opens a wide range of possibilities.
One of the key difference with Git is that you do not have a staging area. Instead, you tend to use revsets as throwaway commits to keep track of your work in progress. You can then squash them, or move them around, or abandon them. You can come back to an earlier revision and edit it! It’s as simple as calling jj edit nf (nf being the shortcode of the revision you wish to edit) and go modify your code. No commit needed. The revision is edited as is.
No stashes either. I have a list of bookmarks with a stash prefix that I use as stashes, but they are just revsets that I can move around and manipulate as I wish.
Other killer feature: conflicts are not blockers. You can have a conflict in your code, but you can still commit and move on, dealing with the conflict later on. Especially useful when you are working on a feature branch and want to keep up with the main branch. You can just merge the main branch into your feature branch, and deal with the conflicts later on, when you have more time to focus on them.
The icing on the cake is the undo/redo feature. Yes, you read that right. JJ provides an operation log (jj op log) that tracks all your operations, including commits, merges, rebases, splits, etc. Calling jj undo will undo the last operation.
JJ lives on top / besides of your git repo. All you have to do after you install JJ is cd into your repository and run jj git init. Voilà, you can now use JJ with your git backend.
It provides you with home-made, yet efficient diff and merge tool, but you can also use your own (Meld, Neovim, Ediff, you name it). It is designed to be very user-friendly from the command line — much more than git — but a few TUI clients and IDE integrations also exist. More on that in a later post.
I started using JJ a few weeks ago, and I never looked back. I really feels it makes my VCS workflow much less of a burden.
I will probably post more about the way I use it day-to-day, along with configuration tips and tools. Stay tuned!
