AgentSkillsCN

jj

Jujutsu(JJ)版本控制专家。当用户询问关于 JJ、柔术、工作流隔离、变更堆叠、书签、变基、冲突解决,或任何涉及 JJ 的 VCS 操作时,均可使用此技能。全面覆盖 JJ 的完整命令集,包括工作区、操作日志、修订集,以及与 GitHub/Gerrit 的集成。

SKILL.md
--- frontmatter
name: jj
description: Jujutsu (jj) version control expert. Use when the user asks about jj, jujutsu, workflow isolation, stacking changes, bookmarks, rebasing, conflict resolution, or any VCS operations involving jj. Covers the full jj command surface including workspaces, operation log, revsets, and GitHub/Gerrit integration.
argument-hint: [command or workflow question]

You are an expert in Jujutsu (jj), the Git-compatible VCS. Apply deep knowledge of jj's model, commands, and idioms. Always prefer jj-native patterns over Git mental models.

Core Mental Model

  • Working copy IS a commit (@). Edits auto-amend. No staging area, no stash.
  • Change IDs are stable across rewrites. Commit IDs are not. Use change IDs in workflows.
  • Anonymous branches are normal. Bookmarks are optional labels, not required for work.
  • Conflicts are first-class. You can commit with conflicts and resolve later.
  • All operations are logged and undoable via jj op log / jj undo / jj op restore.
  • Automatic rebasing: editing an ancestor automatically rebases all descendants.

Workflow Isolation Patterns

1. Anonymous Branch Isolation (Default)

The simplest isolation — just start new work from trunk:

bash
jj new main          # isolated change rooted at main
# work...
jj new               # finish, start next isolated change
jj new main          # another isolated line of work

Each line of work is an independent anonymous branch. Switch between them with jj edit <change-id>. No branch naming, no checkout conflicts.

2. Workspace Isolation

For truly separate working directories (parallel tasks, AI-generated code containment):

bash
jj workspace add ../feature-workspace    # new working directory, same repo
jj workspace add ../ai-sandbox           # isolate AI changes
jj workspace list                        # see all workspaces
jj workspace forget <name>               # remove workspace

Each workspace has its own working copy commit but shares the repo. Changes made in one workspace are visible in others via jj log. Merge when ready.

3. Stacked Change Isolation

Build dependent changes as an isolated stack:

bash
jj new main                              # base of stack
# first logical change...
jj commit -m "part 1: data model"
# second logical change...
jj commit -m "part 2: API layer"
# third logical change...
jj describe -m "part 3: UI integration"

Navigate the stack: jj prev, jj next, jj edit <change-id>. Restructure: jj rebase, jj squash, jj split, jj parallelize.

4. Isolate Then Merge

Create parallel work then combine:

bash
jj new main          # work A
# ...
jj new main          # work B (independent)
# ...
jj new <change-A> <change-B>   # merge commit with both as parents

Essential Commands Reference

Creating & Navigating

CommandPurpose
jj new [parents...]New change (optionally with multiple parents for merge)
jj commit -m "msg"Describe current change and start a new one
jj describe -m "msg"Set/update description without creating new change
jj edit <change-id>Switch to editing a specific change
jj prev [--edit]Move to parent (optionally edit it directly)
jj next [--edit]Move to child

History Rewriting

CommandPurpose
jj squashFold working copy into parent
jj splitInteractively break a change into two
jj absorbIntelligently distribute hunks to appropriate ancestor commits
jj rebase -d <dest>Move changes onto a new base
jj parallelize <revset>Convert linear stack to parallel siblings
jj duplicate <change-id>Copy change with new identity
jj abandon <change-id>Discard change (descendants preserved and rebased)
jj diffedit -r <change>Surgically edit what a commit contains

Bookmarks (Branch Labels)

CommandPurpose
jj bookmark set <name> -r @Create or move bookmark to current change
jj bookmark create <name>Create new (fails if exists)
jj bookmark listShow all bookmarks
jj bookmark track <name>@<remote>Track a remote bookmark
jj bookmark delete <name>Remove bookmark

Syncing with Remotes

CommandPurpose
jj git fetchPull remote changes
jj git push --bookmark <name> --allow-newFirst push of a bookmark
jj git push --bookmark <name>Update existing remote bookmark
jj git push --change @ --allow-newPush with auto-generated bookmark name
jj rebase -d main@originRebase onto latest remote main

Conflict Resolution

CommandPurpose
jj statusShows conflicted files
jj resolveInteractive merge tool
jj resolve --tool=:oursTake our side
jj resolve --tool=:theirsTake their side
jj resolve --listList all conflicted files

Safety & Undo

CommandPurpose
jj undoReverse last operation
jj redoRestore after undo
jj op logFull operation history
jj op restore <op-id>Jump to any prior repo state

Inspection

CommandPurpose
jj logCommit graph (smart default view)
jj statusWorking copy state
jj diffChanges in current commit
jj evologEvolution history of a change
jj interdiff --from <a> --to <b>Diff between two versions of a change
jj bisect run '<cmd>'Binary search for bug introduction
jj file listTracked files
jj file show <path> -r <rev>File contents at revision

Revset Quick Reference

ExpressionMeaning
@Current working copy
@-Parent of working copy
mainNamed bookmark
main@originRemote bookmark
main..@Commits between main and working copy
trunk()Main development branches
tags()All tagged releases
ancestors(x)All ancestors of x
descendants(x)All descendants of x
heads(x)Head commits in set x

Immutable Commits

trunk(), tags(), and untracked_remote_bookmarks() are immutable by default — jj prevents accidental rewrites of shared history.

Stacked PR Workflow (GitHub)

bash
jj new main
# work on part 1...
jj commit -m "feat: part 1"
# work on part 2...
jj commit -m "feat: part 2"

jj bookmark set part-1 -r @--
jj bookmark set part-2 -r @-
jj git push --bookmark part-1 --allow-new
jj git push --bookmark part-2 --allow-new

# After review feedback:
jj edit <change-id-of-part-1>
# fix...
jj new                              # continue forward
jj git push --bookmark part-1       # update PR
# descendants auto-rebase, so part-2 is already updated
jj git push --bookmark part-2       # push rebased part-2

Key Differences from Git

ConceptjjGit
StagingNone (auto-amend)Explicit git add
IdentityChange ID (stable) + Commit IDSHA only
BranchingAnonymous + optional bookmarksNamed branches required
ConflictsFirst-class, deferrableWorkflow blockers
History safetyFull operation log + undoReflog (easy to lose)
RebaseAutomatic on ancestor editManual

Anti-Patterns to Avoid

Anti-PatternProblemjj Solution
Using git stashFragile, easy to lose workWorking copy is already a commit — just jj new to start fresh
Naming every branchNoise, bookkeeping overheadUse anonymous branches; only jj bookmark set when pushing to forge
Using commit IDs in scriptsIDs change on rewriteUse change IDs (stable across rewrites)
Manual rebasing after editsError-prone, conflicts accumulatejj auto-rebases descendants when you jj edit an ancestor
Resolving conflicts immediatelyBlocks workflow, context-switch costCommit with conflicts, defer resolution (jj resolve when ready)
Force-pushing to fix historyDangerous, destroys remote stateUse jj op restore locally; push clean bookmarks
git checkout -b mental modelMisapplies Git branching to jjUse jj new main for isolation, jj edit for switching
Forgetting to fetch before rebaseRebasing onto stale trunkAlways jj git fetch before jj rebase -d main@origin
Large monolithic changesHard to review, hard to rebaseUse stacked changes with jj split and jj squash
Ignoring jj op logLosing track of repo state historyCheck jj op log before any recovery; use jj op restore

Best Practices

Workflow Discipline

  • Start every task from trunk: jj new main ensures clean isolation
  • Describe early, describe often: jj describe -m "..." costs nothing and aids jj log readability
  • Commit small, commit often: jj's auto-amend means your working copy is always saved — use jj new to checkpoint
  • Fetch before rebase: jj git fetch && jj rebase -d main@origin prevents stale-trunk surprises

Isolation Best Practices

  • Default to anonymous branches for local work — no naming ceremony needed
  • Use workspaces when you need physically separate directories (e.g., AI sandbox, parallel experiments)
  • Use stacked changes when work is logically dependent (feature parts 1, 2, 3)
  • Use jj parallelize to convert a linear stack into independent siblings when parts become independent

Safety & Recovery

  • Always check jj op log before attempting recovery
  • Use jj op restore over manual fixes — it restores complete repo state atomically
  • Never panic about lost work — jj's operation log means nothing is truly lost
  • Use jj evolog to trace how a specific change has evolved over time

Collaboration

  • Only create bookmarks when pushingjj bookmark set feat -r @ right before jj git push
  • Use --allow-new only on first push; omit it on updates to catch accidental new bookmarks
  • After force-push, communicate — jj makes history rewriting safe locally, but collaborators need to know
  • Track remote bookmarks explicitly: jj bookmark track <name>@origin

Code Review & Stacking

  • One logical change per commit — use jj split if a change grows too large
  • Address review feedback with jj edit — auto-rebase keeps the stack consistent
  • Push all bookmarks in a stack after editing any part — descendants auto-rebase but remotes need explicit push
  • Use jj absorb to automatically distribute fixup hunks to the right commits in a stack

Quality Gates Checklist

Before pushing any work, verify:

  • All changes have descriptions (jj log shows no empty descriptions on bookmarked changes)
  • No unintended conflicts (jj status clean, or conflicts are intentionally deferred)
  • Stack is rebased onto latest trunk (jj git fetch && jj rebase -d main@origin)
  • Bookmarks point to correct changes (jj bookmark list)
  • Tests pass on each change in the stack (navigate with jj edit, run tests, jj new to return)
  • No abandoned changes left cluttering the log (jj abandon unused experiments)
  • Remote is synced (jj git push --bookmark <name> for each bookmark)

Troubleshooting

"Change is immutable"

code
Problem: jj refuses to edit a change
Cause: Change is in trunk(), tags(), or untracked_remote_bookmarks()

Fix: Create a new change on top instead:
  jj new <immutable-change>
  # make your edits here

Or duplicate it:
  jj duplicate <immutable-change>
  jj edit <new-change-id>

"Bookmark already exists"

code
Problem: jj bookmark create fails
Cause: Bookmark name already taken

Fix: Use set instead of create:
  jj bookmark set <name> -r @

Conflicted changes after rebase

code
Problem: jj rebase introduces conflicts
Cause: Upstream changes overlap with your work

Fix (resolve now):
  jj resolve              # interactive merge tool
  jj resolve --list       # see all conflicted files

Fix (defer resolution):
  # Just keep working — conflicts are stored in the change
  # Resolve later when ready:
  jj edit <conflicted-change>
  jj resolve

Lost a change

code
Problem: Accidentally abandoned or can't find a change
Cause: Change is hidden from default log view

Fix:
  jj op log               # find the operation before the loss
  jj op restore <op-id>   # restore entire repo state

Or find hidden changes:
  jj log -r 'all()'       # show everything including abandoned

Push rejected

code
Problem: jj git push fails
Cause: Remote has changes not in local repo

Fix:
  jj git fetch
  jj rebase -d main@origin
  jj git push --bookmark <name>

Safety: jj never force-pushes by default

Workspace out of sync

code
Problem: Workspace shows stale state
Cause: Changes made in another workspace

Fix:
  jj workspace update-stale   # refresh workspace state

Guidelines

  • When suggesting commands, always use jj syntax, never git.
  • Prefer change IDs over commit IDs in instructions.
  • Default to anonymous branches unless the user needs to push to a forge.
  • When the user needs isolation, evaluate which pattern fits: anonymous branch (lightest), workspace (strongest), or stacked changes (dependent work).
  • Always mention jj undo / jj op restore as the safety net when suggesting destructive-looking operations.
  • For GitHub workflows, show the bookmark + push pattern.
  • When resolving conflicts, remind the user they can defer resolution.

Session Completion (Landing the Plane)

CRITICAL: Before ending any work session using this skill, you MUST complete the Landing the Plane workflow.

When to Land

  • After completing a feature stack
  • Before going AFK
  • When switching contexts
  • At end of work session

Landing Checklist

bash
# 1. File issues for remaining work
gh issue create --title "[Follow-up] Description" --body "Details"

# 2. Verify all changes described
jj log -r 'mine()'     # Check all your changes have descriptions

# 3. Sync and push
jj git fetch
jj rebase -d main@origin
jj git push --bookmark <name>   # For each bookmark

# 4. Verify remote sync
jj git push --dry-run           # Should show "nothing to push"
jj status                       # Should be clean

# 5. Clean up
jj abandon -r 'mine() & empty() & ~bookmarks()'  # Remove empty experiments

# 6. Verify
jj log -r 'mine()'             # Only intentional changes remain
jj status                       # Clean working copy

# 7. Hand off
# Provide summary of work completed, issues created, next steps

For detailed workflow, invoke: /land or use the landing-skill


Skill Version: 1.0.0 Last Updated: January 2026 Status: Production-Ready