Jj vcs
Using jj (Jujutsu) for version control. Make sure to use this skill whenever the user mentions jj, jujutsu, version control, commits, branches/bookmarks, rebasing, history rewriting, cloning/pushing/pulling, or any VCS workflow — even when they don't explicitly say "jj." This skill covers daily editing, history restructuring, collaboration with remotes, and recovery from mistakes. When the user's repository uses jj (look for a .jj/ directory), ALWAYS use jj commands instead of git commands.From its SKILL.md
npx -y skills add OpticLM/jj-skill --skill jj-vcsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.7 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Core mental model
jj is a Git-compatible version control system built around changes (revisions) that evolve over time. Each change has a change ID (stable — follows the change across rebases) and a commit hash (changes whenever the commit content changes). Refer to changes by their change ID (short prefix form) when you want to track a logical change, or by commit hash when pinning exact content.
Key differences from Git:
- No staging area. The working copy (
@) is itself a commit.jj statuscompares@to its parent. Changes to tracked files are automatically part of@. - Change IDs, not branch names, are the primary way history is organized. A commit's change ID survives rebase, squash, and split.
- Operation log. Every jj command creates an operation.
jj undosimply undoes the last operation.jj op logshows the full history of commands run. Nothing is lost unless you explicitly garbage-collect. - Bookmarks, not branches. Bookmarks are labels on revisions. To move a bookmark to point at a different revision, use
jj bookmark move. Git branches are just bookmarks that jj syncs to the remote. - Revsets. jj's revision selection language. Used everywhere commands accept revisions. Learn the common patterns (see core-concepts.md).
Finding the right command
Daily work loop
The core cycle is: start a change → make edits → describe → (optionally) start the next change.
| Intent | Command |
|---|---|
See what's changed in @ | jj status (aliases: st) |
| See file-level diff | jj diff (use --git for git-style output, -s for summary) |
Start a new change on top of @ | jj new [REVISION] (defaults to @) |
| Describe/set the commit message | jj describe -m "msg" or jj describe (opens editor) |
| Describe + start next change | jj commit -m "msg" (equivalent to describe -m && new) |
| View revision graph | jj log (use -r with a revset to filter, -p for patch) |
| Browse file in older revision | jj file show -r REV PATH |
jj new is the primary way to create changes. It creates an empty child of the given revision and makes it the new @. Unlike git checkout -b, it does not need a branch name.
When the user says "commit my changes" they almost always mean jj describe -m "message" to record a message on the current change, or jj commit -m "message" to record and start a new empty change on top.
History restructuring
jj makes rewriting history safe because nothing is truly lost (the operation log preserves everything).
| Intent | Command |
|---|---|
| Move a change to a different parent | jj rebase -r REV -o NEW_PARENT |
| Move a whole branch of changes | jj rebase -b REV -o NEW_PARENT |
Absorb changes from @ into parent | jj squash (moves @'s diff into its parent) |
| Squash specific changes into sibling | jj squash -f FROM_REV -t INTO_REV |
| Split a revision in two | jj split [-r REV] (interactive by default) |
| Drop a change entirely | jj abandon [-r REV] (defaults to @ if empty) |
| Rename/edit a change's description | jj describe -r REV -m "new message" |
| Edit a change's metadata (author, etc.) | jj metaedit -r REV |
| Pull edits from child into parent | jj absorb (auto-detects where changes belong) |
| Reorder siblings into a chain | jj parallelize -r REVS... |
| Interactive graph rearrangement | jj arrange |
| Touch up a change's content diff | jj diffedit -r REV |
Common squash patterns:
jj squash— squash@into its parent (the most common: you made a small fix that belongs in the previous commit)jj squash -f FEATURE_REV -t MAIN— move changes from a feature revision into main
Common rebase patterns:
jj rebase -r REV -o DEST— rebase a single revision onto DESTjj rebase -b REV -o DEST— rebase REV and all its descendants onto DESTjj rebase -r REV --insert-after ANCHOR— reorder REV to come after ANCHOR (useful for reordering commits in a stack)jj rebase -r REV --insert-before ANCHOR
When rebasing after a squash/split/abandon, jj automatically rebases descendants. You rarely need to manually restack.
Collaboration
jj interoperates with Git remotes. The workflow is: fetch → rebase → push.
| Intent | Command |
|---|---|
| Clone a remote repo | jj git clone <URL> |
| Fetch from remote | jj git fetch [--remote NAME] |
| Push to remote | jj git push [--remote NAME] |
| List bookmarks and their targets | jj bookmark list (aliases: b l) |
| Track a remote bookmark as local | jj bookmark track NAME --remote origin |
| Move a bookmark to point at a revision | jj bookmark move --to REV BOOKMARK (aliases: b m -t REV BOOKMARK) |
| Create a new bookmark | jj bookmark create NAME |
| List remotes | jj git remote list |
| Add a remote | jj git remote add NAME URL |
Push workflow:
- Ensure the bookmark you want to push points at your revision:
jj bookmark move --to=@ BOOKMARK - Push:
jj git push - If the remote has new commits:
jj git fetchthenjj rebase -b BOOKMARK -o BOOKMARK@origin
Important: Before pushing, always check the change has a description. jj git push will fail or warn you if a change lacks a description. Use jj describe -m "msg" first.
Recovery
| Intent | Command |
|---|---|
| Undo the last operation | jj undo |
| Redo an undo | jj redo |
| See operation history | jj op log |
| Restore repo to a past state | jj op restore OPERATION_ID |
Restore files in @ (undo edits in wd) | jj restore (restores all files from parent) |
| Restore specific paths from another revision | jj restore --from SOURCE_REV PATH... |
| Undo the changes introduced by a commit | jj restore --changes-in REV (creates a reverse of REV on top of @, effectively undoing its changes) |
| Resolve conflicts | jj resolve PATH... (opens external merge tool) |
| Inspect old repo state without restoring | jj --at-op OPERATION_ID status |
jj undo is the first thing to reach for when something goes wrong. If you need to undo farther back, jj op log + jj op restore can take you to any previous state.
Git-to-jj translation
When a user asks for a git command, translate to the equivalent jj command:
| Git | jj |
|---|---|
git add FILE | Edit FILE (no staging needed — tracked files auto-included) |
git commit -m "msg" | jj describe -m "msg" (or jj commit -m "msg" to also start a new change) |
git commit --amend | jj squash (move @'s changes into its parent) |
git checkout BRANCH | jj new BOOKMARK |
git checkout -b BRANCH | jj new then jj bookmark create NAME |
git branch -d BRANCH | jj bookmark delete NAME |
git rebase main | jj rebase -b @ -o MAIN |
git reset HEAD~1 | jj restore then jj abandon @ |
git revert COMMIT | jj restore --changes-in COMMIT |
git log --oneline | jj log --no-graph |
git stash | Not needed — just jj new to start fresh on top, or jj bookmark create to save the current state |
Choosing the right ancestor (-o) vs insert-after (-A) vs insert-before (-B)
-o/--onto: makes the source revision(s) children of the target. Most common.-A/--insert-after: inserts the source revision(s) after the target, making them siblings of the target's current children. Use when reordering within a stack.-B/--insert-before: inserts the source revision(s) before the target, making them parents of the target. Use when you want to add a step before an existing commit.
These options appear on rebase, new, split, squash, and restore.
Reference files
Read these for deeper guidance on specific workflows:
- references/core-concepts.md — Revsets, change IDs, working copy mechanics, configuration
- references/daily-work.md — Commands and patterns for the daily edit/describe/log loop
- references/history-rewriting.md — Detailed squash, rebase, split, abandon, and absorb patterns
- references/collaboration.md — Pushing, pulling, bookmark management, Gerrit
- references/recovery.md — Undo, operation log, conflict resolution, and restore
- references/commands.md — Quick reference for every jj command with key flags
What ships with it: 6 files
27.9 KB alongside SKILL.md
references/
- collaboration.md4.9 KB
- commands.md4.3 KB
- core-concepts.md5.1 KB
- daily-work.md3.9 KB
- history-rewriting.md5.0 KB
- recovery.md4.6 KB