Jujutsu Usage Guide
Jujutsu (jj) is a next-generation VCS compatible with Git repositories but with fundamentally different usage patterns.
Mental Model (Fundamental Differences from Git)
Don't Think in Git Terms
| Git Thinking | Problem |
|---|---|
git add | jj has no staging area, don't need add |
| Commits can't be changed | jj commits are editable "changes" |
| Use branches | jj uses bookmarks, lightweight pointers |
git stash | Use jj new @- instead |
| Conflicts must be resolved immediately | jj conflicts can be deferred |
Correct Mental Model
- Auto-tracking — jj tracks all changes automatically, no
git addneeded - Mutable commits — commits are editable "changes", can be modified anytime
- Undoable operations — almost all operations can be undone with
jj undo - Bookmarks — lightweight pointers, similar to Git branches but with tracked concept
- Revsets — powerful query syntax for complex conditions
- No checkout — use
jj editto switch to a commit - Non-blocking conflicts — conflicts are recorded in commits, can be resolved later
Core Concepts
Change vs Commit
- Commit: Snapshot of files + metadata (author, date, parents)
- Change: Evolution history of a commit, identified by change ID (similar to Gerrit's Change-Id)
- Working-copy commit: The commit corresponding to the current working directory (@ symbol)
Change ID vs Commit ID
- Change ID: Unique to jj, 16 bytes randomly generated, format like
kntqzsqt, remains unchanged - Commit ID: Git-compatible commit hash, changes with content
Bookmark vs Branch
- Bookmark: Named pointer to a commit, similar to Git branch
- No "current bookmark" — jj has no concept of active branch
- Tracked bookmark: Automatically tracks remote bookmark of the same name
Colocated Workspaces
jj and git can coexist in the same directory:
.jj/+.git/coexist- jj and git commands can be mixed
- jj automatically imports/exports to git
Quick Command Reference
# Status
jj st # Current changes (like git status)
jj log # History
jj log --graph # Graph view
# Working with changes (no add needed)
jj diff # View current changes
jj describe # Edit commit message
jj commit -m "message" # Commit (auto-includes all changes)
jj squash # Squash into parent (like git commit --amend)
jj restore <path> # Discard file changes
# ⚠️ No checkout!
# Switch to edit a commit: jj edit <revision>
# Create new change: jj new
# Creation and switching
jj new # Create new empty change (child of current @)
jj new <revision> # Create new change based on revision
jj new -b <bookmark> # Create new change and set bookmark
jj edit <revision> # Switch to a commit for editing (like checkout)
# Bookmarks
jj bookmark list # List bookmarks
jj bookmark create <name> -r <revision> # Create bookmark
jj bookmark delete <name> # Delete bookmark
jj bookmark move <name> --to <revision> # Move bookmark
jj bookmark track <name> --remote=<remote> # Track remote bookmark
# Rebase
jj rebase -b <bookmark> -o <dest> # Move entire branch
jj rebase -s <commit> -o <dest> # Move commit and descendants
jj rebase -r <commit> -o <dest> # Move only specified commit
# Remote operations
jj git fetch # Fetch
jj git push # Push
jj git push --bookmark <name> # Push specific bookmark
# Undo
jj undo # Undo last operation
jj op log # View operation log
# Multiple remotes
jj config set --user git.fetch '["upstream", "origin"]'
jj bookmark track main --remote=origin
Common Workflows
Daily Commit
jj st
jj diff
jj commit -m "feat: add new feature"
jj log
Modifying Historical Commits
# Edit current commit message
jj describe -m "new message"
# Squash current changes into parent
jj squash
# Squash into specific commit
jj squash --into <commit>
Editing Existing Commit (like git checkout)
# Switch to a commit for editing — all subsequent changes amend this commit
jj edit <revision>
Creating New Branch
jj new main -b topic
Rebase
jj rebase -b topic -o main # Move entire branch (with all descendants)
jj rebase -s <commit> -o <dest> # Move single commit and descendants
jj rebase -r <commit> -o <dest> # Move only single commit (no descendants)
Handling Conflicts
# Conflicts don't block; jj creates a conflicted change
jj new <conflicted-commit> # Create new commit to resolve
# Edit conflict markers in files...
jj resolve <file> # Mark resolved
jj squash # Squash into original
Temporarily Stashing Work
jj new @- # Create sibling commit (like git stash)
jj edit <original-commit> # Restore
Divergent Changes
jj log # Shows divergent label
jj abandon <unwanted-commit-id> # Abandon one version
jj metaedit --update-change-id <commit-id> # Generate new change ID
jj squash --from <source> --into <target> # Merge both versions
Important Notes
- Don't use
git add— jj auto-tracks - No checkout — use
jj editto switch,jj newto create jj commitauto-includes all changes — no-aneeded- Conflicts don't block — can continue working, resolve later
jj newcreates a change — editable empty commit, NOT a checkout- Bookmarks have tracked concept — like Git's upstream
Revset Quick Reference
@ # Current working-copy commit
@- # Parent commit
root() # Root commit
jj log -r ::@ # Ancestor chain of current commit
jj log -r 'all()' # All visible commits
jj log -r main.. # Commits after main branch
Getting Help
jj help
jj help <subcommand>
Reference Files
references/commands.md— Full Git-to-jj command mapping table; read when looking up a specific command equivalentreferences/revsets.md— Complete revset query syntax and functions; read when writing-rexpressionsreferences/pitfalls.md— Common mistakes and pre-operation checklist; read when uncertain about correct approachreferences/advanced.md— Colocated workspaces, multiple remotes, divergent changes, filesets, operation log; read for advanced scenarios