Add jj simplify-parents command documentation to the Essential Commands section, explaining how to remove redundant parents from changes. Add critical workflow guidelines for ending with empty changes after multi-change operations, including detailed examples for splitting changes, creating parallel changes, and organizing history. This ensures users maintain a clean working copy following jujutsu's design philosophy.
14 KiB
| name | description |
|---|---|
| jj | Expert guidance for jujutsu (jj) version control system - modern VCS with first-class conflicts, change tracking, and powerful revsets |
Jujutsu (jj) Version Control System Skill
You are an expert in jujutsu (jj), a modern version control system. This skill provides comprehensive guidance for working with jujutsu repositories, understanding its unique concepts, and helping users leverage its powerful features.
Core Concepts
Changes vs Commits
- Jujutsu introduces "changes" as commits with stable identifiers that persist even when commits are rewritten
- Each change has both a change ID (stable) and a commit ID (changes with rewrites)
- This enables tracking changes across rebases and amendments
Working Copy as a Commit
- The working copy is an actual commit that auto-amends with each operation
- Most jj commands automatically commit working-copy changes if modified
- No need for explicit staging (like
git add) - files are automatically tracked - Use
jj describeto set the commit message for the working copy
First-Class Conflicts
- Conflicts are recorded directly in commits rather than blocking operations
- Operations like rebase/merge succeed and record conflict state
- Conflicts can be resolved later: check out the conflicted commit, resolve, and amend
- Descendants of rewritten commits automatically rebase
Essential Commands
Repository Setup
jj git clone <url> # Clone a Git repository
jj git init --git-repo=. # Initialize in existing Git repo
jj init --git # Create new repo with Git backend
Viewing State
jj st # Show working copy status
jj log # Show commit history
jj log -r '<revset>' # Show filtered commits
jj op log # Show operation history
jj show <commit> # Show commit details
jj diff # Show working copy changes
jj diff -r <revset> # Show changes in specific commits
Making Changes
jj describe # Set commit message (opens editor)
jj describe -m "message" # Set commit message inline
jj new # Create new commit on top of current
jj new <base> # Create new commit on specified base
jj edit <commit> # Edit an existing commit
jj abandon <commit> # Abandon a commit (preserve children)
jj simplify-parents # Remove redundant parents from current change
jj simplify-parents -r <commit> # Remove redundant parents from specific change
Moving Changes
jj squash # Move changes from @ into parent
jj squash -r <commit> # Squash specific commit into parent
jj squash -i # Interactively select changes to squash
jj split # Split current commit into multiple
jj move --from <src> --to <dst> # Move changes between commits
jj diffedit # Interactively edit changes
Branching and Bookmarks
jj bookmark create <name> # Create bookmark at current commit
jj bookmark set <name> -r <commit> # Set bookmark to specific commit
jj bookmark list # List all bookmarks
jj bookmark delete <name> # Delete a bookmark
jj bookmark track <name>@<remote> # Track remote bookmark
Rebasing
jj rebase -d <destination> # Rebase current commit
jj rebase -r <commit> -d <dest> # Rebase specific commit
jj rebase -s <source> -d <dest> # Rebase source and descendants
jj rebase -b <branch> -d <dest> # Rebase branch (all ancestors)
Conflict Resolution
jj resolve # Interactively resolve conflicts
jj resolve --list # List conflicted files
jj resolve <file> # Resolve specific file
Working with Git
jj git fetch # Fetch from remotes
jj git push # Push changes
jj git push --change <id> # Push specific change
jj git push --bookmark <name> # Push specific bookmark
jj git remote add <name> <url> # Add remote
jj git remote list # List remotes
jj git export # Export to Git (updates Git refs)
jj git import # Import from Git
Undo and Recovery
jj undo # Undo last operation
jj op undo <operation> # Undo specific operation
jj op restore <operation> # Restore to specific operation
jj op abandon <operation> # Abandon operation from log
Multi-Workspace
jj workspace add <path> # Create new workspace
jj workspace list # List workspaces
jj workspace forget <name> # Remove workspace
jj workspace update-stale # Update stale working copy
Important Symbols and Operators
Revset Symbols
@- The working copy commit<workspace>@- Working copy in another workspace<name>@<remote>- Remote-tracking bookmarkroot()- The root commit- Commit/Change IDs - Full or unique prefixes
Revset Operators
x-- Parents of xx+- Children of xx::- Descendants of x (inclusive)::x- Ancestors of x (inclusive)x..- Non-ancestors of x (x and descendants minus ancestors)..x- Ancestors of x excluding rootx & y- Intersectionx | y- Unionx ~ y- Difference (x but not y)~x- Complement (everything except x)
Fileset Operators
~x- Negation (everything except x)x & y- Intersectionx ~ y- Differencex | y- Union
Common Workflows
Daily Development
# Start new work
jj new main # Create new commit based on main
jj describe -m "Add feature" # Describe your work
# Make changes to files
jj st # Check status
jj diff # Review changes
# Create another commit
jj new # Start fresh commit
jj describe -m "Add tests"
# Make more changes
# Update existing commit
jj edit <commit-id> # Edit specific commit
# Make changes
jj new # Return to working on new commit
Interactive Editing
# Move some changes from working copy to parent
jj squash -i # Select which changes to squash
# Split a commit
jj edit <commit> # Edit the commit
jj split # Interactively split changes
# Edit changes visually
jj diffedit -r <commit> # Edit commit's changes in difftool
Working with Branches
# Create feature branch
jj bookmark create feature
jj new # Start working
# Rebase on updated main
jj git fetch
jj rebase -d main@origin # Rebase current commit on remote main
# Push branch
jj git push --bookmark feature
Resolving Conflicts
# After a rebase creates conflicts
jj log -r 'conflict()' # Find conflicted commits
jj edit <conflicted-commit> # Edit the conflicted commit
jj resolve # Interactively resolve conflicts
# Or manually edit files
jj new # Move back to working copy
Recovering from Mistakes
# Undo last operation
jj undo
# View operation history
jj op log
# Restore to specific point
jj op restore <operation-id>
# Abandon unwanted changes
jj abandon <commit>
Best Practices
When to Use Commands
jj new- Start new work or move away from edited commitjj edit- Modify existing commits directlyjj squash- Combine changes (default: move @ into parent)jj squash -i- Selectively move changes between commitsjj describe- Set commit messagesjj rebase- Move commits to new bases
Understanding Auto-tracking
- New files are automatically tracked (no
jj addneeded) - Deleted files are automatically removed
- Working copy changes auto-commit on most commands
- Use
.gitignoreto exclude files
Conflict Management
- Don't fear conflicts - they're stored in commits
- Resolve conflicts when convenient
- Descendants automatically rebase after resolution
- Use
jj resolvefor interactive resolution or edit files manually
Operation Log
- Every command creates an operation in the log
- Operations can be undone/restored
- Use
jj op logto understand repository history - Operations include timestamps and descriptions
Commit Descriptions
- Use conventional commit format:
feat:,fix:,test:,refactor:, etc. - Optionally add scope for context:
feat(api):,test(protocol): - Write in lowercase throughout (except for code element references)
- Header is single line, imperative mood; body is optional and explains "why"
- See descriptions.md for complete style guidelines and examples
Advanced Features
Revsets (Detailed reference in revsets.md)
Powerful query language for selecting commits:
jj log -r 'author(name) & description(keyword)'
jj log -r 'bookmarks() & ~remote_bookmarks()'
jj log -r 'ancestors(@, 5)' # Last 5 ancestors
jj log -r 'mine() & ~::main' # My commits not in main
Filesets (Detailed reference in filesets.md)
Precise file selection:
jj diff '~Cargo.lock' # Exclude file
jj split 'glob:"src/**/*.rs"' # Only Rust files
jj diff 'root:src & ~glob:"**/*.test.ts"' # Source minus tests
Templates (Detailed reference in templating.md)
Customize output formatting:
jj log -T 'commit_id.short() ++ " " ++ description.first_line()'
jj log -T 'if(conflict(), "⚠️ ", "") ++ description'
Configuration
Edit config with jj config edit --user:
[user]
name = "Your Name"
email = "your@email.com"
[ui]
default-command = "log"
diff-editor = "vimdiff"
merge-editor = "meld"
[aliases]
l = ["log", "-r", "(main..@):: | (main..@)-"]
Comparison with Git
Key Differences
- No staging area - Changes in working copy are automatically tracked
- Working copy is a commit - Auto-amends instead of separate staging
- Conflicts are first-class - Stored in commits, resolved later
- Auto-rebase - Descendants automatically update when parents change
- Change IDs - Stable identifiers across rewrites
- Operation log - Complete undo/redo history
Command Mapping
git add→ Not needed (automatic)git commit→jj describe+jj newgit commit --amend→jj describe(working copy auto-amends)git rebase -i→jj rebase,jj squash,jj editgit cherry-pick→jj rebaseorjj duplicategit reflog→jj op loggit reset --hard→jj undoorjj op restoregit stash→jj new(changes are always in commits)git branch→jj bookmark
Troubleshooting
Stale Working Copy
If working copy becomes stale (interrupted operations):
jj workspace update-stale
Lost Changes
Check operation log and restore:
jj op log
jj op restore <operation-id>
Unexpected State
View recent operations to understand what happened:
jj op log --limit 10
jj undo # Undo last operation
Complex Conflicts
Use merge tools:
jj resolve --tool meld
# Or configure in settings
jj config set --user ui.merge-editor "code --wait --merge"
Resources
Supplemental Documentation
- descriptions.md - Commit description style guidelines
- revsets.md - Comprehensive revset language reference
- filesets.md - Complete fileset syntax and patterns
- templating.md - Template language for custom output
Official Documentation
- Main docs: https://jj-vcs.github.io/jj/latest/
- Tutorial: https://jj-vcs.github.io/jj/latest/tutorial/
- GitHub: https://github.com/martinvonz/jj
Guidelines for Assistance
When helping users with jujutsu:
- Understand their workflow - Ask about their current VCS (Git, Mercurial, etc.)
- Explain key concepts - Working copy as commit, change IDs, first-class conflicts
- Use revsets effectively - Leverage the query language for complex operations
- Emphasize safety - Highlight operation log and undo capabilities
- Show examples - Provide concrete commands for their specific use case
- Reference supplemental docs - Point to revsets.md, filesets.md, templating.md for details
- Explain differences - Help Git users understand jj's different mental model
- Encourage experimentation - Everything is recoverable via operation log
- Always end with new empty change - After performing operations that create or modify changes, create a new empty working copy change as the final step
Critical Workflow Rule: End with Empty Change
IMPORTANT: When performing operations that create or modify changes, ALWAYS end by creating a new empty change. This ensures the working copy is ready for new work.
When to Create New Empty Change
- After splitting a change into multiple commits
- After creating multiple parallel changes
- After rebasing or moving changes
- After any operation that leaves you on a non-empty change
- When organizing or restructuring commit history
How to Create New Empty Change
# After any multi-change operation, end with:
jj new # Create new empty change on current commit
# Or for parallel changes:
jj new <change1> <change2> # Create new empty merge commit above multiple changes
jj simplify-parents # Simplify if merge has redundant parents
Note on Redundant Parents: When creating merge commits with jj new <change1> <change2>, if one change is an ancestor of another, use jj simplify-parents to remove redundant parents and create a cleaner history.
Examples
Splitting changes:
# User asks: "Split my current change into tests and implementation"
jj split # Split into two changes
jj new # Create new empty change above both
Creating parallel changes:
# User asks: "Create separate changes for feature A and feature B"
jj new -r base_commit
jj describe -m "feat: add feature A"
# Make changes for A
jj new -r base_commit
jj describe -m "feat: add feature B"
# Make changes for B
jj new <changeA> <changeB> # Create new empty merge change above both features
jj simplify-parents # Remove redundant parents if any
After organizing history:
# After rebasing, squashing, or other history operations
jj new # Always end with fresh empty change
This ensures users always have a clean working copy ready for new work, following jujutsu's design philosophy of treating the working copy as a first-class commit.
Remember: jujutsu's design philosophy prioritizes safety, ease of use, and powerful functionality. Help users leverage these strengths.