| name | jujutsu |
| description | Version control instructions for Jonathan's workflow using jujutsu (jj) exclusively. Use this skill for ANY version control task — commits, branches, history, rebasing, pushing, merging, reviewing changes, or navigating a repo. Jonathan does NOT use git directly; all VCS operations must use jj commands. Trigger this skill whenever the user asks about commits, branches, history, diffs, pushing code, reviewing changes, undoing changes, or any other version control operation.
|
Jujutsu (jj) Version Control Skill
Jonathan uses jujutsu (jj) exclusively for version control. Never suggest raw git
commands — all VCS operations go through jj. When in doubt, suggest jj equivalents.
Core Mental Model
Jujutsu differs from git in key ways:
- Every working-copy state is a commit — there is no "index" or "staging area". The
working copy is always commit
@.
- Changes are first-class — jj tracks "changes" (identified by
change_id) separately
from commits (commit_id). A change survives rewrites; its commit hash changes.
- Conflicts are values — jj can commit conflict states and resolve them later; it never
blocks you with unresolved conflicts.
- No detached HEAD confusion —
jj edit <rev> moves @ to any commit for editing.
Jonathan's Config & Aliases
Revset aliases (defined in config)
| Alias | Meaning |
|---|
bases | present(bookmarks(exact:base)) or trunk() — the integration branch |
working_lineage | All commits from bases to @ and forward |
base_branches | Bookmarks in bases:: that are mine |
base_heads | Heads of bases:: that are mine |
base_roots | Roots of bases:: that are mine (excluding bases) |
base_to_branch(target) | Commits from bases to a named bookmark (exclusive) |
Shell aliases
| Alias | Expands to | Purpose |
|---|
jj l | jj log | Default log (uses custom revset: @ | bases | working_lineage | ...) |
jj ll | jj log -r all() -n 10 | Last 10 commits, all branches |
jj lc | jj log -r ::@ -n 10 | Last 10 ancestors of @ |
jj s | jj status | Working copy status |
jj f | jj git fetch | Fetch from remote |
jj b | jj edit -r @- | Move to parent commit |
jj n | jj edit -r @+ | Move to child commit |
jj cleanup | jj abandon bases:: ~ bases & empty() | Abandon empty descendants of base |
jj rb | jj rebase -s base -d trunk() | Rebase base bookmark onto trunk |
jj lm | jj log -r "heads(mine())" --no-graph -n 10 | My recent head commits |
jj nil | jj describe -m "∅" | Mark commit as empty/nil placeholder |
UI
- Pager:
delta
- Diff editor:
meld
- Diff formatter:
:git (git-style diffs)
- Default command:
jj l (just run jj with no args)
Common Operations
Viewing history
jj l
jj ll
jj lc
jj lm
jj log -r 'all()'
jj show
jj show <rev>
Making changes
jj describe -m "message"
jj new
jj new <rev>
jj new <rev1> <rev2>
Navigating commits
jj b
jj n
jj edit <rev>
jj next
jj prev
Undoing / fixing mistakes
jj undo
jj op log
jj op restore <op-id>
jj abandon <rev>
jj cleanup
Rebasing & restructuring
jj rebase -r @ -d <dest>
jj rebase -s <src> -d <dest>
jj rebase -b <branch> -d <dest>
jj rb
jj squash
jj squash -r <rev>
jj squash --from <rev> --into <dest>
Splitting & moving changes
jj split
jj split -r <rev>
jj move --from <rev> --to <rev>
jj restore --from <rev> <path>
Bookmarks (≈ git branches)
jj bookmark list
jj bookmark create <name>
jj bookmark create <name> -r <rev>
jj bookmark set <name>
jj bookmark set <name> -r <rev>
jj bookmark delete <name>
jj bookmark track <remote>/<name>
Remote operations
jj f
jj git fetch --remote origin
jj git push
jj git push -b <bookmark>
Resolving conflicts
jj status
jj resolve
jj resolve --list
Diffs
jj diff
jj diff -r <rev>
jj diff --from <rev> --to <rev>
jj diff <path>
Revset Syntax (quick reference)
@ # Working copy
@- # Parent of @
@+ # Child of @
trunk() # Default remote branch (main/master)
mine() # Commits authored by me
heads(x) # Commits in x with no children in x
roots(x) # Commits in x with no parents in x
x::y # All commits from x to y (inclusive)
x:: # x and all descendants
::x # x and all ancestors
x & y # Intersection
x | y # Union
x ~ y # Difference (x minus y)
present(x) # x if it exists, else empty (no error)
bookmarks(pattern) # Commits pointed to by matching bookmarks
description(glob) # Commits whose description matches glob
Workflow Patterns
Starting new work
jj f
jj new bases -m "feat: ..."
jj describe -m "final message"
jj git push -b <my-bookmark>
Amending the current commit
jj describe
Inserting a commit in history
jj new <parent-rev>
jj rebase -s <original-children> -d @
Cleaning up before push
jj cleanup
jj squash
jj l
Handling "detached" state (non-issue in jj)
Unlike git, jj has no detached HEAD. jj edit <rev> is always safe.
GPG Signing
Commits are GPG-signed on push (sign-on-push = true). Key is jonathan_lorimer@mac.com.
No action needed — signing is automatic.
Notes on git interop
Jonathan's repo uses jj git for remote operations. The underlying git repo is managed by jj.
- Never run raw
git commit, git add, git checkout, etc.
jj git fetch / jj git push are the only git-interop commands needed.
jj git import / jj git export exist if manual sync is ever needed.