| name | jj-core |
| description | Manage version control with Jujutsu (jj) — no staging area, immediate changes, smart rebasing. Use when navigating history, squashing, or pushing to Git remotes. |
| token_cost | 220 |
| related | ["jj-hunk","conventional-commits","sem"] |
| keywords | ["jujutsu","jj","rebase","squash","split","push","commit"] |
| requires_tools | ["bash"] |
Jujutsu
Git-compatible VCS with a different data model — no staging area, changes are immediate. Every file is tracked in the working copy as "changes" (like commits without parents).
⚠️ Never use git for mutations in a jj repo — it corrupts history. Allowed: git log, git diff, git show, git blame, git grep.
Basic Workflow
Create a change, describe it, view history:
jj new
jj desc -m "feat: add login"
jj log
jj diff
Edit an existing change:
jj edit <change-id>
jj squash
Time Travel & Navigation
Jump to any point in history:
jj edit @-
jj next --edit
jj edit <change-id>
jj new --before @
Squash & Split Changes
Combine changes into one:
jj squash -m "combined message"
jj split
Auto-move changes to relevant commits in a stack:
jj absorb
Rebasing & Merging
Rebase changes onto another:
jj rebase -s @- -d main
jj rebase -d main -s ::@
Merge two changes:
jj new x yz -m "merge"
Conflicts
Resolve interactively:
jj resolve
Pushing to Git
Bookmarks are like branches. Track and push them:
jj bookmark create main -r @
jj git push --bookmark main
jj git fetch
jj bookmark track main@origin
Useful Patterns
Undo an operation: jj undo — reverses the last jj command.
Get git commit hash from jj change:
jj log -T 'commit_id\n' -r @
jj log -T 'commit_id.short()\n' -r @
git rev-parse @
Operation history: jj op log — see all jj operations.
Template Syntax (-T / --template)
Templates use jj's own language — NOT JavaScript, NOT shell interpolation.
String concatenation requires concat():
jj log -r @ -T 'commit_id.short() description'
jj log -r @ -T 'change_id.short() " | " commit_id.short()'
jj log -r @ -T 'concat(change_id.short(), " | ", description)'
Common fields: change_id, commit_id, description, author, committer, signature
Field name is description, NOT desc:
jj log -r @ -T 'desc'
jj log -r @ -T 'description'
Double quotes for pipe alternation in bash:
jj log -r "id1 | id2" -T 'concat(change_id.short(), "\n", description)'
jj log -r 'id1 | id2' -T 'description'
After jj desc, the working copy (@) moves:
jj desc -r <change-id> -m "new description"
jj log --no-graph -r <change-id> -T 'concat(change_id.short(), " | ", description)'
Common Pitfalls
- ❌ Use
@~1 → ✅ Use @- (parent)
- ❌ Use
a,b,c for union → ✅ Use a | b | c (pipe, not comma)
- ❌ Use
jj changes → ✅ Use jj log or jj diff
- ❌ Template: implicit string joining → ✅ Always use
concat(a, b)
- ❌ Template:
desc → ✅ Always use description
- ❌ Verify with
@ after jj desc → ✅ Always use original change ID