Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    dashed

    jj

    dashed/jj
    DevOps
    6
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Jujutsu (jj) version control system - a Git-compatible VCS with novel features.

    SKILL.md

    Jujutsu (jj) Version Control System

    Overview

    Jujutsu is a powerful Git-compatible version control system that combines ideas from Git, Mercurial, Darcs, and adds novel features. It uses Git repositories as a storage backend, making it fully interoperable with existing Git tooling.

    Key differentiators from Git:

    • Working copy is automatically committed (no staging area)
    • Conflicts can be committed and resolved later
    • Automatic rebasing of descendants when commits change
    • Operation log enables easy undo of any operation
    • Revsets provide powerful commit selection
    • Change IDs stay stable across rewrites (unlike commit hashes)

    When to Use This Skill

    • User mentions "jj", "jujutsu", or "jujutsu vcs"
    • Working with stacked/dependent commits
    • Questions about change IDs vs commit IDs
    • Revset queries for selecting commits
    • Conflict resolution workflows in jj
    • Git interoperability with jj
    • Operation log, undo, or redo operations
    • History rewriting (squash, split, rebase, diffedit)
    • Bookmark management (jj's equivalent of branches)

    Key Concepts

    Working Copy as a Commit

    In jj, the working copy is always a commit. Changes are automatically snapshotted:

    # No need for 'git add' - changes are tracked automatically
    jj status        # Shows working copy state
    jj diff          # Shows changes in working copy commit
    

    When Snapshots Are Triggered

    The working copy is snapshotted into the current commit (@) when running most jj commands. Key triggers:

    • jj new - Creates new commit, snapshots working copy into parent
    • jj status - Triggers snapshot before showing status
    • jj diff, jj log, jj describe - All trigger snapshot first

    Forcing a snapshot manually:

    # If you edited files but need to ensure they're committed:
    jj new                       # Snapshot into parent, create new @
    jj abandon @                 # Remove empty new commit if not needed
    
    # Alternative: describe triggers snapshot
    jj describe -m "updated"     # Snapshot and update description
    

    Important: When you jj edit a commit and make changes, those appear as "working copy changes" until a snapshot is triggered. This is normal behavior.

    Change ID vs Commit ID

    • Change ID: Stable identifier that persists across rewrites (e.g., kntqzsqt)
    • Commit ID: Hash that changes when commit is rewritten (e.g., 5d39e19d)

    Always prefer change IDs when referring to commits in commands.

    No Staging Area

    Instead of staging, use these patterns:

    • jj split - Split working copy into multiple commits
    • jj squash -i - Interactively move changes to parent
    • Direct editing with jj diffedit

    First-Class Conflicts

    Conflicts are recorded in commits, not blocking operations:

    jj rebase -s X -d Y     # Succeeds even with conflicts
    jj log                   # Shows conflicted commits with ×
    jj new <conflicted>      # Work on top of conflict
    # Edit files to resolve, then:
    jj squash                # Move resolution into parent
    

    Operation Log

    Every operation is recorded and can be undone:

    jj op log                # View operation history
    jj undo                  # Undo last operation
    jj op restore <op-id>    # Restore to specific operation
    

    Essential Commands

    Command Description Git Equivalent
    jj git clone <url> Clone a Git repository git clone
    jj git init Initialize new repo git init
    jj status / jj st Show working copy status git status
    jj log Show commit history git log --graph
    jj diff Show changes git diff
    jj new Create new empty commit -
    jj describe / jj desc Edit commit message git commit --amend (msg only)
    jj edit <rev> Edit existing commit git checkout + amend
    jj squash Move changes to parent git commit --amend
    jj split Split commit in two git add -p + multiple commits
    jj rebase Move commits git rebase
    jj bookmark / jj b Manage bookmarks git branch
    jj git fetch Fetch from remote git fetch
    jj git push Push to remote git push
    jj undo Undo last operation git reflog + reset
    jj file annotate Show line origins git blame

    Common Workflows

    Starting a New Change

    # Working copy changes are auto-committed
    # When ready to start fresh work:
    jj new                    # Create new commit on top
    jj describe -m "message"  # Set description
    # Or combine:
    jj new -m "Start feature X"
    

    Editing a Previous Commit

    # Option 1: Edit in place
    jj edit <change-id>       # Make working copy edit that commit
    # Make changes, they're auto-committed
    jj new                    # Return to working on new changes
    
    # Option 2: Squash changes into parent
    jj squash                 # Move all changes to parent
    jj squash -i              # Interactively select changes
    jj squash <file>          # Move specific file
    

    Rebasing Commits

    # Rebase current branch onto main
    jj rebase -d main
    
    # Rebase specific revision and descendants
    jj rebase -s <rev> -d <destination>
    
    # Rebase only specific revisions (not descendants)
    jj rebase -r <rev> -d <destination>
    
    # Insert commit between others
    jj rebase -r X -A Y       # Insert X after Y
    jj rebase -r X -B Y       # Insert X before Y
    

    Working with Bookmarks (Branches)

    jj bookmark list          # List bookmarks
    jj bookmark create <name> # Create at current commit
    jj bookmark set <name>    # Move bookmark to current commit
    jj bookmark delete <name> # Delete bookmark
    jj bookmark track <name>@<remote>  # Track remote bookmark
    

    Bookmark gotchas:

    # Moving backwards requires a flag:
    jj bookmark set feature -r <ancestor>                  # FAILS if ancestor
    jj bookmark set feature -r <ancestor> --allow-backwards  # Works
    
    # The * suffix means bookmark diverged from tracked remote:
    # feature* 123abc  ← Push to sync with remote
    jj git push --bookmark feature
    
    # Create vs Set:
    jj bookmark create feature     # FAILS if feature@origin exists
    jj bookmark set feature -r @   # Works, moves existing bookmark
    

    Pushing Changes

    # Push specific bookmark
    jj git push --bookmark <name>
    
    # Push change by creating auto-named bookmark
    jj git push --change <change-id>
    
    # Push all bookmarks
    jj git push --all
    

    Resolving Conflicts

    # After a rebase creates conflicts:
    jj log                    # Find conflicted commit (marked with ×)
    jj new <conflicted>       # Create commit on top
    # Edit files to resolve conflicts
    jj squash                 # Move resolution into conflicted commit
    
    # Or use external merge tool:
    jj resolve                # Opens merge tool for each conflict
    jj resolve --list         # List all conflicted files
    

    Resolving Binary File Conflicts

    Binary files (images, .wasm, compiled files) cannot have conflict markers. Resolve by choosing one version:

    # Take version from specific revision (e.g., main):
    jj restore --from main path/to/binary.wasm
    
    # Take version from feature branch:
    jj restore --from feature path/to/binary.wasm
    
    # For multiple binary files:
    jj resolve --list         # See all conflicted files
    for file in file1.wasm file2.wasm; do
      jj restore --from main "path/to/$file"
    done
    

    Multi-Parent (Merge) Conflict Resolution

    When a merge commit has conflicts:

    # Option 1: Work on child of merge
    jj new <conflicted-merge>    # Create child of merge
    # Edit files to resolve
    jj squash                    # Move resolutions into merge
    
    # Option 2: Edit the merge directly
    jj edit <conflicted-merge>   # Edit the merge itself
    # Make changes - they appear as "working copy changes"
    jj new                       # Snapshot changes into merge
    jj abandon @                 # Remove empty temp commit
    

    Creating multi-parent merges:

    jj new branch-a branch-b branch-c -m "integration: merge features"
    

    Undoing Mistakes

    jj undo                   # Undo last operation
    jj op log                 # View operation history
    jj op restore <op-id>     # Restore to specific state
    
    # View repo at past operation
    jj --at-op=<op-id> log
    

    Revsets Quick Reference

    Revsets select commits using a functional language:

    Expression Description
    @ Working copy commit
    @- Parent of working copy
    x- Parents of x
    x+ Children of x
    ::x Ancestors of x (inclusive)
    x:: Descendants of x (inclusive)
    x..y Ancestors of y not in ancestors of x
    x::y Commits between x and y (DAG path)
    bookmarks() All bookmark targets
    trunk() Main branch (main/master)
    mine() Commits by current user
    conflicts() Commits with conflicts
    description(text) Commits with matching description

    Examples:

    jj log -r '@::'           # Working copy and descendants
    jj log -r 'trunk()..@'    # Commits between trunk and working copy
    jj log -r 'mine() & ::@'  # My commits in working copy ancestry
    jj rebase -s 'roots(trunk()..@)' -d trunk()  # Rebase branch onto trunk
    

    Git Interoperability

    Colocated Repositories

    By default, jj git clone and jj git init create colocated repos where both jj and git commands work:

    jj git clone <url>        # Creates colocated repo (default)
    jj git clone --no-colocate <url>  # Non-colocated (jj only)
    

    Using Git Commands

    In colocated repos, Git changes are auto-imported. For non-colocated:

    jj git import             # Import changes from Git
    jj git export             # Export changes to Git
    

    Converting Existing Git Repo

    cd existing-git-repo
    jj git init --colocate    # Add jj to existing Git repo
    

    Colocated Mode Deep Dive

    In colocated mode, both jj and Git operate on the same repository. This creates some nuances to understand:

    Understanding git status output:

    $ git status
    HEAD detached from 82f30e2c
    nothing to commit, working tree clean
    

    The "detached from X" message shows the original detachment point, not current HEAD. To verify actual HEAD position:

    git log --oneline -1 HEAD  # Shows current HEAD
    

    Git index sync issues:

    After jj conflict resolution, git may show unmerged paths:

    $ git status
    Unmerged paths:
      both modified:   Cargo.lock
    

    Fix by updating the git index:

    git add <files>           # Clears unmerged entries
    

    When git and jj disagree:

    jj git import             # Force import git state to jj
    jj git export             # Force export jj state to git
    

    Best practice: Primarily use jj commands in colocated repos. Only use git for operations jj doesn't support (like interactive rebase with git add -p style workflows).

    Configuration

    Edit config with jj config edit --user:

    [user]
    name = "Your Name"
    email = "your@email.com"
    
    [ui]
    default-command = "log"   # Run 'jj log' when no command given
    diff-editor = ":builtin"  # For interactive diff editing (split, squash -i)
    
    [revset-aliases]
    'wip' = 'description(exact:"") & mine()'  # Custom revset alias
    

    For automation/LLMs: Use -m flags instead of relying on editors. See Non-Interactive Workflows for patterns that work without user interaction.

    See references/configuration.md for comprehensive configuration options including editor setup for interactive use.

    Advanced Topics

    For comprehensive documentation, see:

    • references/revsets.md - Complete revset reference
    • references/commands.md - Full command reference
    • references/git-comparison.md - Git to jj command mapping

    Troubleshooting

    "Working copy is dirty" - Never happens in jj! Working copy is always a commit.

    Conflicts after rebase - Normal in jj. Conflicts are recorded, resolve when convenient.

    Lost commits - Use jj op log to find when commits existed, then jj op restore.

    Divergent changes - Same change ID, different commits. Usually from concurrent edits:

    jj log                    # Shows divergent commits
    jj abandon <unwanted>     # Remove one version
    

    Immutable commit error - Can't modify trunk/tagged commits by default:

    jj --ignore-immutable <command>  # Override protection
    

    Non-Interactive Workflows

    Many jj commands open an editor by default. Use these flags for automation and CLI workflows:

    Commit Messages Without Editor

    Command Non-Interactive Flag Example
    jj describe -m or --stdin jj describe -m "Fix bug"
    jj commit -m jj commit -m "Add feature"
    jj new -m jj new -m "Start new work"
    jj squash -m or -u jj squash -u (use destination message)
    jj split -m (first commit only) jj split -m "First part" <files>

    Squash Without Editor

    # Use destination's message (discard source)
    jj squash --use-destination-message    # or -u
    
    # Provide explicit message
    jj squash -m "Combined commit message"
    

    Note: If either commit has an empty description, jj automatically uses the non-empty one without opening an editor.

    Conflict Resolution Without Merge Tool

    # Use built-in tools instead of external merge tool
    jj resolve --tool :ours <file>      # Take "our" version (side #1)
    jj resolve --tool :theirs <file>    # Take "their" version (side #2)
    
    # Or use restore for complete replacement
    jj restore --from <rev> <file>      # Take file from specific revision
    

    Inherently Interactive Commands

    These commands cannot be made non-interactive:

    • jj split (without file arguments) - requires diff selection
    • jj diffedit - opens diff editor by design
    • jj resolve (without --tool) - opens merge tool

    Workaround for split: Provide file paths to avoid interactive selection:

    jj split -m "First commit" src/file1.rs src/file2.rs
    

    Common Pitfalls

    Push Flag Combinations

    Some jj git push flag combinations don't work together:

    Flags Works? Notes
    --all ✓ Pushes all bookmarks
    --tracked ✓ Pushes tracked bookmarks that changed
    --bookmark <name> ✓ Pushes specific bookmark
    --change <id> ✓ Creates/pushes auto-named bookmark
    --all --allow-new ✗ Incompatible
    --tracked --allow-new ✗ Incompatible
    --bookmark <name> --allow-new ✓ For new bookmarks

    Working Copy Changes on Merge Commits

    When you jj edit a merge commit, changes appear as "working copy changes" even if you're resolving conflicts. This is expected - use jj new to trigger snapshot:

    jj edit <merge-commit>       # Edit the merge
    # Make changes...
    jj new                       # Snapshot into merge, create new @
    jj abandon @                 # Remove empty commit
    

    Git Status Shows Detached HEAD

    In colocated repos, git status shows "HEAD detached from X" - this is normal. The message shows the original detachment point. Check actual HEAD with:

    git log --oneline -1 HEAD    # Current HEAD position
    

    Bookmark Movement Refused

    If jj bookmark set fails because it would move "backwards":

    jj bookmark set name -r <rev> --allow-backwards
    

    This flag is required when moving a bookmark to an ancestor of its current position.

    Recommended Servers
    Bitbucket
    Bitbucket
    Repository
    dashed/claude-marketplace
    Files