← Back to articles

Versioning with Jujutsu

A few weeks ago I read Git Is Not Fine and it reminded me how I was intrigued by Jujutsu when it was first mentioned in cool tech circles.

Jujutsu is a version control software that uses Git as backend storage and offers a new way to manage changes.

The main idea is that any change is a commit.

Unlike Git where there are:

In Jujutsu all changes are always stored in a commit.

Actually almost: changes are only recorded when a jj command runs, so between edits the files on disk are ahead of the commit. Every Jujutsu command invocation, even jj status, snapshots the working copy into the commit that represents it.

This matters because it removes a whole layer of Git ceremony: no stash, no detached HEAD, no staging. Any state is a commit you can name, move, or undo.

So here is a quick guide to the most basic unit of work: creating a repo, making a change, pushing to a remote repo.

Repo creation

jj git init

As of recent versions, the repository is colocated by default (--colocate is the default).

It means you will get a .jj directory standing next to a .git directory, so Git commands will also work.

The path to the git repository is known to jj through the .jj/repo/store/git_target file.

Repo can also be non-colocated, which means only jj can touch it.

Making a change

A fresh jj git init repo already puts you on an empty working copy change, so you can start right away: just edit your files.

There is no git add: every time you run a jj command, Jujutsu snapshots the working copy into the current change. This is why each command scans the directory first.

# edit some files
jj status

jj status shows the files you touched, plus two identifiers:

You work with the change id most of the time.

Describing

The change you just edited has no description yet. Add one with:

jj describe -m "Update README"

Pushing

A repo created with jj git init has no remote yet. Add one (the commands mirror Git’s):

jj git remote add origin git@github.com:user/repo.git

What gets pushed to a remote is a bookmark: a named pointer to a commit, Jujutsu’s equivalent of a Git branch. There is no branch to switch onto; you place a bookmark where you want it. The simplest path is to let jj git push create one for the current change:

jj git push -c @

-c/--change creates a bookmark (named push-<change id> by default) and pushes it. Jujutsu refuses to push a change with no description, so describe it first.

Starting the next change

Once that first change is described and pushed, jj new opens a fresh empty change on top of it, and you begin the next unit of work:

The whole loop

Putting it together, each unit of work looks like this:

# edit some files
jj status                    # see what changed
jj describe -m "msg"         # describe it
jj git push -c @             # create a bookmark and push
jj new                       # start the next change

More on rebase later: editing history is where Jujutsu really shines, but that is a topic for another post.