19 Oct 2026, 08:32

jj on NFS is not fun

You may have seen my relentless stanning of the jj version control system, e.g. in my recent FrOSCon 2026 talk. I think jj is super fun to use! But not on all setups.

In fact, I recently ran into the worst type of setup for it. My pkgsrc repo was located on a home server, on spinning rust – this is bad already because of operation latency. But then I imported it via NFS, over Wi-Fi, onto my laptop, and the experience was miserable.

You see, jj has the “magic” behavior that you are always editing a commit. That is, every file change you make, every non-ignore file you create, will end up in that commit. The way that this is implemented is through snapshots: say you run jj log or jj st. Before anything else happens, jj will snapshot the entire repository, by scanning it for changes. On a fast SSD, you might see a “snapshotting” line fly by, but with this NFS setup, snapshots take more than a minute. And if you do a mutating change, jj might need to snapshot again at the end of the command.

You can get around this on a per-operation basis by adding the --ignore-working-copy flag. For instance, jj log --ignore-working-copy will just show the log and not update the current commit. You can even do certain mutating commands this way. For instance, to “check out” the latest main branch, you can run

jj new main --ignore-working-copy

However, there is a problem now: none of the files in your working copy have been updated, because you explicitly told jj not to. This is called a “stale workspace”. You can get out of this situation (without a snapshot!) by running

jj workspace update-stale

This will actually reconcile the working copy with the operations in the oplog. Gentle reminder, you can inspect the operations that you did by running

jj op log

This is also the basis for jj undo.

Is this useful?

If you write scripts that do multiple jj operations in sequence, the --ignore-working-copy flag may give you a nice speed boost. Just add the flag to every operation that does not need an updated commit state and reconcile with jj workspace update-stale in the end.

Speaking of workspaces, this is probably a better way of fixing the slow operations: create a new workspace on local disk and work in that.