Jujutsu (jj) is a next-generation version control system that addresses several pain points Git users face daily:
Problems jj Solves:
- No staging area confusion - Work directly with commits, no
git add
complexity - Automatic conflict resolution workflow - No
git rebase --continue
dance - Safe history rewriting - Rebase/amend operations can't lose work
- Lock-free concurrency - Multiple operations can run simultaneously
- Unified mental model - One consistent way to handle all operations
Key Benefits:
- Every operation is reversible via the operation log
- Commits are automatically rebased when their parents change
- Conflicts are stored as first-class objects in commits
- Working copy changes are automatically committed
Commits (Revisions)
- Immutable snapshots identified by change IDs (not hashes)
- Change IDs stay constant through rewrites (unlike Git SHA-1s)
- Every change has both a change ID and a commit ID
Bookmarks (Similar to Git branches)
- Mutable pointers to commits that automatically move with rewrites
- Replace Git's branch concept with better merge tracking
- Can track remote Git branches seamlessly
Working Copy
- Always corresponds to a commit (the "working-copy commit")
- Changes are automatically committed when you switch revisions
- No staging area - edit files and they're in the next commit
Operation Log
- Records every command that modifies the repository
- Enables undo/redo of any operation
- Provides lock-free concurrency by storing operation history
graph TB
subgraph "jj Repository"
subgraph "Working Copy"
WC[📁 Working Directory<br/>Always auto-committed]
WCC[📝 Working-Copy Commit<br/>@ - Current commit]
end
subgraph "Commit Graph"
C1[📦 Commit A<br/>Change ID: abc123<br/>Commit ID: def456]
C2[📦 Commit B<br/>Change ID: ghi789<br/>Commit ID: jkl012]
C3[📦 Commit C<br/>Change ID: mno345<br/>Commit ID: pqr678]
end
subgraph "Bookmarks"
BM1[🏷️ main]
BM2[🏷️ feature-branch]
BM3[🏷️ remote/origin/main]
end
subgraph "Operation Log"
OP1[⚡ Op: jj new main]
OP2[⚡ Op: jj describe]
OP3[⚡ Op: jj rebase]
OP4[⚡ Op: Current @]
end
end
%% Relationships
WC --> WCC
WCC --> C3
C3 --> C2
C2 --> C1
BM1 --> C2
BM2 --> C3
BM3 --> C1
OP1 --> OP2
OP2 --> OP3
OP3 --> OP4
%% Styling
classDef commitStyle fill:#e1f5fe,stroke:#01579b
classDef bookmarkStyle fill:#f3e5f5,stroke:#4a148c
classDef workingStyle fill:#e8f5e8,stroke:#1b5e20
classDef opStyle fill:#fff3e0,stroke:#e65100
class C1,C2,C3,WCC commitStyle
class BM1,BM2,BM3 bookmarkStyle
class WC workingStyle
class OP1,OP2,OP3,OP4 opStyle
jj new
- Create new commit (replacesgit checkout -b
)jj edit
- Switch to editing a commit (replacesgit checkout
)jj describe
- Change commit message (replacesgit commit --amend
)jj abandon
- Delete commits (replacesgit reset --hard
)jj rebase
- Move commits (likegit rebase
but safer)
With Git (Co-located Repository):
- jj and Git repos share the same
.git
directory - Use
jj git import/export
to sync between jj and Git - Can use Git tools alongside jj commands
- Push/pull through jj's Git integration
Without Git (Pure jj Repository):
- Native jj storage format
- All features available without Git compatibility layer
- Can still push to Git remotes when needed
Question 1: What is the key difference between jj's change IDs and Git's commit hashes?
Click to reveal answer
Change IDs remain constant through rewrites (like amend, rebase), while Git commit hashes change with every modification. This means you can reliably refer to a logical change even after rewriting its history.
Question 2: In jj, what happens when you edit files in your working directory?
Click to reveal answer
Files are automatically staged and committed to the current working-copy commit (@). There's no staging area or need for git add
- changes are immediately part of the commit.
Question 3: How do bookmarks differ from Git branches in terms of behavior during rewrites?
Click to reveal answer
Bookmarks automatically move to follow commits when they're rewritten (rebased, amended, etc.), whereas Git branches can become orphaned or point to old commit hashes after rewrites.
Question 4: What is the operation log and why is it important?
Click to reveal answer
The operation log records every command that modifies the repository, enabling undo/redo of any operation and providing lock-free concurrency. It makes every jj operation reversible.
# In your existing Git repo
jj git init --colocate
# Import existing Git history
jj git import
Create and Switch Between Commits:
# Create new commit based on main
jj new main
# Edit files - they're automatically in this commit
# Switch to different commit
jj new some-feature
# Your working copy changes were auto-committed to previous commit
Handle Conflicts:
# If rebase creates conflicts, jj stores them in the commit
jj rebase -d main
# Edit conflict markers in files, then:
jj describe -m "Resolved conflicts"
Manage History:
# View history
jj log
# Rewrite commit message
jj describe -r @- -m "Better message"
# Move commits around
jj rebase -r @ -d main
# Abandon unwanted commits
jj abandon badcommit
Sync with Git:
# Pull changes from Git remote
jj git fetch
# Push jj bookmarks to Git
jj git push
# Import new Git branches
jj git import
Complete Workflow Visualization:
sequenceDiagram
participant Dev as Developer
participant WC as Working Copy
participant Repo as jj Repository
participant OpLog as Operation Log
Note over Dev,OpLog: Common jj Workflow: Feature Development
Dev->>+Repo: jj new main
Repo-->>WC: Switch to new commit @ based on main
Repo->>OpLog: Record: "jj new main"
Note right of WC: Working copy now at new commit
Dev->>WC: Edit files (file1.js, file2.css)
WC-->>WC: Files automatically staged
Note right of WC: No 'git add' needed
Dev->>+Repo: jj describe -m "Add user authentication"
Repo-->>WC: Update commit message
Repo->>OpLog: Record: "jj describe"
Dev->>WC: Continue editing files
WC-->>WC: Changes auto-committed to @
Dev->>+Repo: jj bookmark create feature-auth
Repo-->>Repo: Create bookmark pointing to @
Repo->>OpLog: Record: "jj bookmark create"
Dev->>+Repo: jj rebase -d main
Repo-->>Repo: Move current commit to main
Repo-->>WC: Update working copy
Repo->>OpLog: Record: "jj rebase"
Note right of Repo: Automatic conflict resolution if needed
Dev->>+Repo: jj git push --bookmark feature-auth
Repo-->>Repo: Export to Git remote
Repo->>OpLog: Record: "jj git push"
Note over Dev,OpLog: All operations are reversible via operation log!
Question 1: After running jj git init --colocate
in an existing Git repo, what additional step is needed to access Git's history in jj?
Click to reveal answer
Run jj git import
to import the existing Git history as jj commits and bookmarks.
Question 2: When you run jj new main
and then edit files, where are those changes stored?
Click to reveal answer
The changes are automatically committed to the new working-copy commit (@) that was created based on main. No explicit commit command is needed.
Question 3: If you run jj new some-feature
after making changes, what happens to your uncommitted work?
Click to reveal answer
jj automatically commits your changes to the previous working-copy commit before switching to the new commit. You never lose work when switching commits.
Question 4: How does jj handle conflicts differently from Git during a rebase operation?
Click to reveal answer
jj stores conflicts as first-class objects within commits rather than blocking the operation. You can continue working and resolve conflicts later, or even commit conflicted states.
Question 5: What's the command equivalent to git push origin feature-branch
in jj?
Click to reveal answer
jj git push --bookmark feature-branch
(assuming you've created a bookmark named feature-branch pointing to your changes).
jj init --git
- Create new jj repo with Git backendjj git init --colocate
- Add jj to existing Git repojj status
- Show working copy statusjj log
- View commit history
jj new [REVISION]
- Create new commit (default: current commit)jj edit REVISION
- Switch to editing specific commitjj describe [-r REVISION] [-m MESSAGE]
- Change commit descriptionjj abandon REVISION
- Remove commits from history
jj rebase -r REVISION -d DESTINATION
- Move commitsjj squash
- Merge current commit into parentjj split
- Split commit into multiple commitsjj duplicate REVISION
- Create copy of commits
jj bookmark create NAME [REVISION]
- Create new bookmarkjj bookmark set NAME REVISION
- Move bookmark to commitjj bookmark list
- Show all bookmarksjj bookmark delete NAME
- Remove bookmark
jj git fetch [--remote REMOTE]
- Fetch from Git remotejj git push [--bookmark NAME]
- Push to Git remotejj git import
- Import Git refs as bookmarksjj git export
- Export jj changes to underlying Git repo
jj operation log
- View operation historyjj operation undo [OPERATION]
- Undo operationjj operation restore OPERATION
- Restore to specific operation
- Concepts: https://jj-vcs.github.io/jj/latest/
- CLI Reference: https://jj-vcs.github.io/jj/latest/cli-reference/
- Git Comparison: https://jj-vcs.github.io/jj/latest/git-comparison/
- Tutorial: https://jj-vcs.github.io/jj/latest/tutorial/
- Chris Krycho's "jj init": https://v5.chriskrycho.com/essays/jj-init/
- Steve Klabnik's Jujutsu Tutorial: https://steveklabnik.github.io/jujutsu-tutorial/
Note: Video URLs are current as of August 14, 2025, and may change over time.
- Chris Krycho's Jujutsu YouTube Series - Started March 2024, comprehensive coverage from an experienced user
- GitButler "Bits and Booze" - Jujutsu Episode - Educational walkthrough of Jujutsu concepts
- Martin von Zweigbergk's Git Merge 2022 Talk - Official presentation by Jujutsu's creator
For additional tutorials, search YouTube for "Jujutsu jj version control" or browse the official GitButler and GitHub channels.