Tables, git equivalents, troubleshooting, and the revset cheatsheet: REFERENCE.md.
House style
- Descriptions are mandatory. Never leave the working copy as "(no description set)".
- Bookmarks exist for GitHub, not for you. Work with anonymous changes; add bookmarks only when pushing.
- Use
absorbover manual squash routing. Let jj distribute hunks to the right ancestor.
Non-interactive split
jj split needs both filesets and -m:
jj split -r <rev> -m "first part" path/a path/b # rest stays in the child commit
Evolog addressing
Previous versions: <change-id>/0 (latest), /1 (previous). jj restore --from xyz/1 --into xyz reverts to a prior state.
Workflows
Squash (recommended)
jj describe -m "feat: what I'm building"
jj new -m "wip"
# ... make changes ...
jj squash -m "feat: done"
Edit (mid-stack fix)
jj edit <change-id>
# ... fix ...
jj new -m "back to work" # descendants auto-rebased
Absorb
From @, jj absorb routes each hunk to the ancestor where those lines were last modified.
Bookmarks & pushing
Bookmarks don't auto-advance — move them explicitly. Target whichever revision actually holds the work, which depends on the flow you just used:
jj bookmark set <name> -r @- # after `jj squash`/`jj commit`: @ is a fresh empty change
jj bookmark set <name> -r @ # after `jj describe -m` alone: @ IS the work
jj git push
Getting this wrong is silent: pushing @- when @ holds the work publishes the previous commit.
Don't rewrite reviewed PR history
Default (safe — preserves comment anchors):
jj new feature-x -m "fixup: address feedback"
# ... make changes ...
jj bookmark set feature-x -r @
jj git push
jj new feature-x (no trailing -) stacks the fix on top of the bookmark.
feature-x- is the revset for parents of feature-x, so it would branch a
sibling off the reviewed commit and bookmark set -r @- would then drag the
bookmark backwards, dropping the very commit the reviewers annotated.
Creating PRs (jj + gh)
In jj-colocated repos, git HEAD is detached — gh pr create fails with "not on any branch". Always pass --head <bookmark> — never rely on git auto-detection:
jj bookmark set feature-x -r @- # or -r @ — see "Bookmarks & pushing" above
jj git push
gh pr create --head feature-x --title "..." --body "..."
Recovery
jj op log, then jj op restore <id>; jj evolog -r <change-id> shows one change's history. Full block in REFERENCE.md.
Immutable commits
Pushed commits are protected by immutable_heads(). jj squash --into <id> --ignore-immutable is the approved way to fold a fix into a pushed commit; rules/pr-safety.md still gates it on a reviewed PR.
Revsets
jj log -r 'trunk()..@' # everything between main and here
jj log -r '::@ & ~::trunk()' # my branch only
jj log -r 'mine()' # my commits
jj log -r 'author(substring:"trevor")' # bare strings in author()/description() are whole-string globs; say substring: for partial