| name | jj |
| description | Use when working in a jj (Jujutsu) repository. Covers the core workflow, workspace management, and common operations. jj is a newer VCS — do not assume git commands work here. |
jj (Jujutsu) VCS Cheatsheet
jj is a Git-compatible VCS with a different mental model. Every change is always
a commit — there is no staging area. The working copy IS a commit (@).
Core Concepts
| git concept | jj equivalent |
|---|
| staged changes | doesn't exist — edits are auto-tracked |
git commit | jj describe -m "msg" + jj new |
git status | jj status |
git log | jj log |
git diff | jj diff |
git checkout <branch> | jj edit <rev> |
git branch | jj branch list |
| worktree | jj workspace |
Daily Workflow
jj status
jj diff
jj describe -m "feat: add shell completions"
jj new
jj commit -m "feat: add shell completions"
jj log
jj log -r '::@'
Workspaces (multi-agent isolation)
jj workspaces are like git worktrees but tracked in .jj/:
jj workspace list
jj workspace add ../my-feature-workspace
jj workspace forget my-feature-workspace
Revsets (query language)
jj log -r 'main..@'
jj log -r '@-'
jj log -r 'description("fix")'
Key Differences from Git
-
No staging area. All file changes in the working directory are automatically part of the current change (@).
-
Commits are mutable. jj describe edits the current commit's message without creating a new one.
-
jj new moves forward. After describing a change, jj new creates a new empty commit on top. This is the equivalent of "I'm done with this commit, start a new one."
-
@ is always a commit. The working copy is always represented as a commit, even when empty.
-
Branches are optional. jj uses anonymous commits; branches are just named pointers.
In the bop context
When running as a dispatched agent in a jj workspace:
jj workspace list
jj describe -m "feat: what I implemented"
jj new
jj log -r 'main..@-'
The merge-gate will squash and push your changes to main via jj squash.
Do NOT try to push to origin yourself.
Common Mistakes
- ❌
git add && git commit — doesn't work, changes won't be recorded as jj commits
- ❌
git push — use jj git push if needed, but the merge-gate handles this
- ❌
jj squash before done — squash flattens into parent, reserve for cleanup
- ✅
jj status to see current state
- ✅
jj describe -m "..." + jj new to commit and move on