Jujutsu Impressions
TL;DR
- JJ does things differently from Git, but it’s compatible enough to try. The core unit is the persistent change, which evolves through snapshots.
- Actions are logged as operations, enabling undo and restore to any point in time.
- No Git-style branches. Changes have persistent IDs, and you use bookmarks for Git-forge workflows.
- You can colocate
jj
with an existing Git repo, keeping your Git workflow intact whilejj
handles history. - Curious? Follow the tutorial or experiment on a current repo to see the difference firsthand.
In this post I’ll share some insights about using the Jujutsu version control system, which I’ll call jj
for the rest of the post.
jj
is a version control system, currently built on top of git, using its building blocks. However, it’s not just a new porcelain; it defines new abstractions and data structures of its own.
Concept: The Change as the Atomic Unit
The most important concept is the change. The change defines an atomic unit of, well, change. Its analog is the git commit. But in jj
, a change can develop in time. Technically, it’s a git commit that keeps getting amended, the difference being that the change keeps its identity via a persistent ID and a description field. A change updates whenever jj
takes a snapshot of the repo—every time you call jj
. If you think about it, jj
can’t lose work, as it always starts by taking a snapshot, even for informative commands like jj log
.
Thus the change represents an amended commit, the “last” change. However, jj
lets you inspect the internal, previous commits inside the change, by calling jj evolog
. These internal commits are not synced to git forges and are not automatically garbage collected, like git amended commits are.
When we are done with a change, we can give it a description (which we can do at any time using jj description
) and create an empty change on top of it, ready to receive new modifications. We do that using jj commit
.
For example, when you initialize a repo, the initial current change is empty. You add files, edit them. When you are ready, you give this change a name via jj description
and then start a new change via jj new
, or do both at the same time via jj commit
.
Graph, Branches, and Bookmarks
Moving around (git checkout
) is done with jj edit
. But we need to be careful, as any edit we make after the jump will get snapshots (“amended”) on top of the current change, modifying it. If you want to jump in to do some work, it’s better to use jj new
.
You might see the claim there are no branches in jj
. There aren’t branches in the usual git sense. In jj
s graph there are “branches”, but they don’t need names. The persistent change IDs serve as feature names and jump addresses (using edit
or new
). Nevertheless, branch names are introduced in jj
in order to be compatible with git forges; they are called bookmarks, and they need to be moved explicitly across the changes.
Logging and Time Travel
jj
logs what’s happening using operations: these are the commands you enter and the current change you’re in, in addition to some metadata. The logs enable handy features like jj undo
or the deeper jj op restore
(restore to any point in time). For browsing the operation log, see jj op log
.
There is a comparison table between git
and jj
commands, which could be useful but it’s important to not fixate on how git
is doing things in order to be open to the new paradigm jj
represents. However, some features seem to have been added in response to git users’ needs or workflows, or perhaps jj
developers rediscovered the same needs.
Mixing JJ with Git
I chose one existing git project and converted it to a mixed usage of jj
and git
, using jj git init --colocate
. It means jj
initialize its presence in an existing repo and it will keep updating the .git
folder with what’s happening, at a level compatible with git constructs; for example, the changes are saved as git commits, jj git fetch
is fetching from git forges into .git/
, etc. I haven’t used rebasing, squashing or other history-changing operations so I can’t comment on how easy they are to use, maybe next time.
If you found it interesting, give it a try. There’s the tutorial, or you can run it on an existing git repo.
Enjoy Reading This Article?
Here are some more articles you might like to read next: