name: jj description: Jujutsu VCS workflows and custom aliases. Use when working with jj commands, commits, revsets, or version control operations. user-invocable: false
Jujutsu (jj) Version Control
Uses Jujutsu (jj) for version control with git backend. Key differences from git:
- No staging area - changes are automatically tracked
- Commits are mutable by default
- Working copy is always a commit (
@) - Branches are optional "bookmarks"
Signing Policy (Mandatory)
- Commit signing is required for pushable changes in this environment.
- Never bypass signing by overriding config at command time (for example
--config git.sign-on-push=falseor similar). - Never modify repo/user config to disable push signing.
- If signing fails (for example 1Password/SSH agent issues), stop and ask the user to fix or approve the next step; do not push unsigned as a workaround.
Core Concepts
@- The working copy commit (always exists)@-- Parent of working copy (very commonly used)trunk()- The main branch (usuallymainormaster)immutable()- Commits that shouldn't be modified- Revisions use short change IDs (e.g.,
xy,zk,trunk())
Most Used Commands
Status & Viewing (daily drivers)
jj st # Status (alias for jj status)
jj diff # Show changes in working copy
jj log # Show commit history
jj show # Show current commit details
jj show -r @- # Show parent commit details
Creating & Modifying Commits
jj new # Create new empty commit on @
jj new <rev> # Create new child commit from rev
jj new --insert-after <rev> # Create fixup after rev and rebase descendants onto it
jj commit -m "msg" # Describe @ and create new empty commit
jj commit <paths> # Commit only specific files (partial commit)
jj describe # Edit description of @
jj describe -r <rev> # Edit description of specific revision
jj edit <rev> # Make revision the working copy; use sparingly for direct mutation
Fixing Earlier Stack Commits
When fixing an earlier commit in a stack, prefer a temporary fixup commit over directly editing the target commit. This keeps the new delta easy to inspect with jj diff, while still letting later commits see the fix during verification.
jj new --insert-after <target-rev>
# edit files
jj diff
mise run pre-commit
jj squash
jj new --insert-after <target-rev> creates a new change immediately after the target commit and rebases the target's descendants on top of it. After verification, plain jj squash folds the current fixup commit into its parent, which is the target commit.
Use jj new <target-rev> when you only need a sibling fixup to inspect and squash locally. Use --insert-after when descendants should be tested with the fix before squashing. Reserve jj edit <rev> for inspection, intentionally continuing work in the current commit, or explicit direct mutation.
Squashing & Combining
jj sq # Squash @ into parent (alias for squash)
jj sq -r @- # Squash parent into its parent
jj sq -r @- --use-destination-message # Squash, keep destination's message
jj squash -r <rev> --into <target> # Squash rev into specific target
jj squash <paths> # Squash only specific files into parent
Reordering & Rebasing
jj rebase -r <rev> -d trunk() # Move single commit onto trunk
jj rebase -s <rev> -d trunk() # Move commit and descendants onto trunk
jj rebase -r <rev> --insert-after <x> # Insert commit after x
jj rebase -r <rev> --insert-before <x> # Insert commit before x
jj up # (alias) Rebase @ onto trunk(), dropping commits that become empty
Restoring & Undoing
jj restore # Restore @ to match parent (discard changes)
jj restore <paths> # Restore specific files only
jj restore --from <rev> # Restore @ from specific revision
jj restore --from <rev> <paths> # Restore specific files from revision
jj abandon <rev> # Delete a commit entirely
jj undo # Undo the last jj operation
jj op log # View operation history (for undo)
Git Integration
jj git fetch # Fetch from all remotes (configured: glob:*, handles fork workflows)
jj git push # Push current bookmark (must remain signed)
jj git push --named <branch>=<rev> # Create bookmark and push (e.g., --named my-feature=@)
jj git push -b <name> # Push specific bookmark
jj git init --colocate # Initialize jj in existing git repo
Bookmark Management
jj bookmark track <name>@origin # Track remote bookmark locally
jj bookmark list # List all bookmarks
jj tug # (alias) Move nearest bookmark to current pushable commit
File Tracking
jj file untrack <paths> # Stop tracking files (like .gitignore but immediate)
jj file list # List tracked files
Custom Aliases (from config)
Viewing History
jj open # Show all my unmerged commits
jj ropen # Show open remote branches
jj recent # Show last 20 commits
Branch Operations
jj up # Rebase onto trunk(), dropping commits that become empty
jj tug # Move bookmark to nearest pushable commit
jj branch-diff # Diff for entire branch (trunk..@)
jj branch-diff-files # List files changed in branch
jj stack-diff # Diff for full stack (includes sibling branches)
jj stack-diff-files # List files changed in stack
Pre-commit Integration
jj pre-commit-last # Run pre-commit on files in @
jj pre-commit-branch # Run pre-commit on branch files
jj pre-commit-stack # Run pre-commit on stack files
Private Commit Operations
jj rebase-private # Rebase private commits onto @, dropping empties
Custom Revset Aliases
branch() # Linear path from trunk() to @ (trunk()..@)
stack() # All commits diverging from trunk, including sibling branches (roots(trunk()..@)::)
open() # All user's commits not yet landed on immutable heads
private() # Commits with "private:" description prefix
# Ancestry/context helpers
slice() # Ancestors of reachable mutable commits from @, depth 2
slice(from) # Same but from a specific revision
stack_context() # Ancestry back to trunk divergence point, depth 2
stack_context(from) # Same but from a specific revision
# Bookmark/push helpers
closest_bookmark(to) # Nearest bookmark ancestor of a revision
closest_pushable(to) # Nearest ancestor with a description that is non-empty or a merge
# History
last() # Last 20 ancestors of @ (like git log)
last(n) # Last n ancestors of @
ropen() # Open remote branches (remote bookmarks minus immutable, depth 2)
Private Commits
Prefix with private: to prevent pushing:
jj commit -m "private: WIP debugging"
jj rebase-private # Later, rebase private commits onto @
Configuration Notes
- Colocated repos:
git.colocate = true-- all repos are colocated, git commands work alongside jj - Signing:
behavior = "drop"locally (commits may be unsigned), butsign-on-push = truesigns commits when pushed via 1Password SSH agent. Do not disable this for pushes. - Auto push bookmark: Creates
rwjblue/push-<change_id>on push when no bookmark exists - Fetch from all remotes:
git.fetch = ["glob:*"]-- handles fork workflows whereoriginandupstreamboth exist - Delta pager: Used only for
jj diff(scoped config), not for other commands to avoid terminal clearing - Scoped config: Different email/signing key for work repos vs personal repos