| name | jj |
| description | Use this skill when the user asks about `jj` (Jujutsu) or any operation
on a git repo where they want jj semantics — clones, commits, bookmarks,
rebases, conflict handling, undo via `op log`. Triggers include:
"use jj for this", "jj clone …", "make a bookmark", "what does
`jj describe` do", "rebase this stack with jj", "undo my last jj
operation". This is the canonical reference for the jj-native workflow
on this hub.
|
jj — Jujutsu VCS skill
This hub is jj-native. We do not use GitHub PRs. Reviews happen via
compare-URL hand-off to a human:
jj git push --bookmark feature-x
If you find yourself reaching for gh pr create or "let me install
gh" — stop. That's the wrong mental model for this hub. PR-flavored
work belongs in claude-github-and-spoke.
Seven-point mental model
Adapted from the upstream
git comparison doc.
Each one is a place git-habits silently mislead.
-
Working copy is auto-committed. Every jj command snapshots first.
There is no jj add, no equivalent of "untracked changes" anxiety. Save
the file, run any jj command, and the snapshot is captured.
-
No index. git add -p; git commit becomes jj split. To amend the
parent with current changes: jj squash (or jj squash <file> for a
single path, jj squash -i for an interactive picker).
-
No current bookmark — this is the biggest git-habit trap.
jj describe and jj new do not advance any bookmark. Bookmarks
(jj's term for branches) must be explicitly moved with
jj bookmark create <name> -r @ (new) or
jj bookmark set <name> -r @ (move existing) before jj git push.
The -r @ (working copy) vs -r @- (parent) choice trips git brains;
for "the change I just described and want to push", -r @ is correct.
-
Conflicts commit. jj rebase / jj merge never fail on conflict;
conflicts get recorded into the commit and resolved later with
jj resolve. Don't treat exit code 0 as "merge succeeded" — check
jj log for a conflict marker on the commit.
-
Descendants auto-rebase. jj rebase -r X -d Y propagates to X's
children automatically. No manual fix-up of stacked commits.
-
Bookmarks travel by name across remotes. jj git push --bookmark main
is the whole story; no origin main:main ceremony, no upstream-tracking
dance.
-
jj op log + jj op restore <id> undoes anything. Replaces
git reflog. Every jj operation (including git push, bookmark create, rebase, even pulls) gets a unique op ID. To roll back:
jj op log
jj op restore <op-id-prefix>
This is the agent-recovery primitive that earns jj its keep. If
something goes sideways, the path back is always one command away.
Common verbs (cheatsheet)
jj log
jj log -r 'all()'
jj show
jj diff -r @
jj op log
jj bookmark list -a
jj new <rev>
jj describe -m "msg"
jj squash
jj squash --from <rev> --into <rev>
jj split
jj abandon
jj bookmark create feature-x -r @
jj bookmark set feature-x -r @
jj bookmark delete feature-x
jj bookmark forget feature-x
jj git clone https://github.com/owner/repo .spokes/repo
jj git fetch
jj git push --bookmark feature-x
jj git push
jj git push --deleted
jj rebase -r X -d Y
jj rebase -s X -d Y
jj resolve
jj op log
jj op restore <id-prefix>
jj undo
End-to-end recipes
Clone and ship a change
jj git clone https://github.com/owner/repo .spokes/repo
cd .spokes/repo
jj new main
$EDITOR src/thing.py
jj describe -m "fix: handle empty input in thing()"
jj bookmark create feature-x -r @
jj git push --bookmark feature-x
echo "Review: https://github.com/owner/repo/compare/main...feature-x"
Stack a second change on top
jj new
$EDITOR src/other.py
jj describe -m "test: cover the empty-input path"
jj bookmark set feature-x -r @
jj git push --bookmark feature-x
Split a commit you already made
jj log -r feature-x
jj edit <commit-id>
jj split
jj bookmark set feature-x -r @
Squash a fix into the previous commit
$EDITOR src/thing.py
jj squash
Resolve a conflict
jj rebase -r feature-x -d main
jj log
jj resolve
jj squash
Undo the last push
jj op log --limit 5
jj op restore <op-id-prefix-of-the-one-BEFORE-the-push>
Deleting a remote bookmark
jj git push --deleted is its own form — not a flag combined with
--bookmark. Order matters:
jj bookmark delete feature-x
jj git push --deleted
Since the spoke is colocated, plain git also works as a fallback:
git push origin --delete feature-x
When jj doesn't cover something — pointers
When to stop and ask
- A
jj git push would touch a repo the user doesn't own and you have
no clear instruction to act there. The compare URL is a soft commit;
the bookmark on the remote is harder to retract.
jj op log shows operations from before this session that you don't
recognize — surface them before continuing.
- A rebase records conflicts you can't tell how to resolve from the
surrounding context — show
jj resolve --list output and ask.
- You're about to run
jj abandon on a commit that has descendants on
bookmarks you didn't create — confirm first.
Gotchas (diagnosed during this hub's bring-up)
jj git push --bookmark X --deleted is rejected by jj's argument
parser. Use the two-step jj bookmark delete X; jj git push --deleted.
--colocate on jj git clone is now the default in v0.41+; the
flag still exists for compat but has no effect. Don't sweat including
it.
- The auto-snapshot means an unsaved-buffer mistake gets captured. If
you snapshot bad content into
@, the fix is either edit-and-resnapshot
or jj abandon + jj new.