| name | jj |
| description | Prefer Jujutsu (`jj`) for VCS operations whenever `jj` is installed. The `jj.ts` extension warns when `git` is used directly. Working copy is auto-tracked. Run `jj <cmd> --help` or `jj help -k <topic>` for exact syntax — this skill stays at the concept/workflow layer on purpose. |
Policy
If jj is on the machine, jj is preferred. The jj.ts extension warns on
every git invocation (including read-only inspection and network ops),
because jj has natural equivalents for all of them and jj st/jj log/jj diff
surface jj-native state (change IDs, DAG, conflict markers) that git equivalents
hide.
- Colocated repo (
.jj/ present): use jj.
- Plain git repo (no
.jj/): prefer adopting jj with jj git init --colocate.
- Using
git directly still works but triggers a warning.
Key differences from git
- Working copy IS a change (
@) — no staging area; edits mutate @
automatically.
- Two IDs: stable change ID (survives rewrites, prefer this) vs
commit ID (git-compatible hash, churns on rewrite).
- Conflicts are data, not control flow — recorded in files, no command
aborts, no
--continue ceremony.
For deeper coverage: jj help -k tutorial.
Looking up syntax
Do not memorize flags — they drift across jj versions. If unsure about
basic concepts or workflows, start with jj help -k tutorial. Always verify
exact flags against the installed version:
jj <cmd> --help — flags + examples for one command
jj help -k <topic> — conceptual topics (tutorial, revsets, bookmarks,
conflicts, working-copy, operation-log, git-compatibility)
jj --help — list of commands
- Git→jj translation:
jj help -k git-compatibility and
https://docs.jj-vcs.dev/latest/git-command-table/
Common workflows
Describe intent
A multi-line jj describe message can carry the change goal, plan, and
acceptance criteria. jj show reads it back later. Prefer describing the
change before or while implementing it, so the commit message and work stay
aligned.
Checkpoint work
Use changes as explicit workspace checkpoints. Before risky edits, inspect
jj st and ensure @ contains only intended files. Commit or split unrelated
work first, then continue from a clean, intentional change.
Pre-plan a multi-step task
Chain empty described changes (a sequence of jj commit) as a spec skeleton,
then jj edit <first> and fill them in one at a time. Descendants auto-rebase.
Explore alternatives
Use jj new for a separate experimental change. Use jj workspace add <path>
for separate on-disk worktrees sharing the same store. Done? jj new a b to
merge approaches, or pick one and jj abandon the other.
Undo or recover
Prefer explicit history operations: inspect jj log/jj op log, then use
jj restore, jj abandon, jj edit, or jj op restore as appropriate. Be
extra careful with operation restore; see the snapshot trap below.
PR review loop
This multi-step workflow isn't in any single help page:
- Fix the description —
jj describe -r <change>.
- Amend the diff —
jj edit <change> and edit, or
jj squash --into <change>.
- Move the bookmark forward —
jj bookmark move <name> --to <change>.
- Re-push —
jj git push.
Your own published bookmark is in mutable() territory — amend + push is
safe, and the operation is in jj op log, so accidental rewrites are undoable.
Common pitfalls
- Push
@-, not @ — @ is typically empty after jj commit.
- Bookmarks don't auto-advance — you must
jj bookmark set/move explicitly.
- Don't reach for
git in a colocated repo; it bypasses jj op log.
jj abandon drops a change and rebases descendants past it; it's undoable.
--ignore-working-copy skips the auto-snapshot on read, but the result may
be stale; avoid it in write workflows.
Working-copy snapshot trap
Every jj command auto-snapshots @ first — all current disk state becomes
part of @ before the command runs. This bites hard with rewrites:
- Default
jj squash (i.e. --from @) pulls the entire @ into the
parent (or --into <target> for a non-parent destination), not just files
you edited this session.
jj op restore rewinds metadata but the working tree stays; the next
snapshot lifts dirty files into whatever change is now @.
Before any rewrite (squash/split/op restore/abandon of ancestor):
jj st — read every line. Unexpected paths? Stop.
- If
@ is mixed, jj split <fileset> first so each change is intentional.
- For files that should never be tracked,
jj file untrack <path> —
.gitignore alone does nothing for already-tracked paths.
- After
jj op restore, run jj st immediately.
Warning sign: --stat shows a commit touching far more files than you
edited. That's working-copy contamination — abandon and redo with explicit
path args.