logo

Cheatsheet - jj

Jujutsu (jj) is a powerful, Git-compatible version control system designed to be more ergonomic and safe.

This cheatsheet is for users familiar with basic version control concepts and is especially helpful for those transitioning from Git.

How jj is Different

  • The Working-Copy Commit (@): Your working copy is not a separate state; it's a special, mutable commit (identified by @). Any changes you make to files are automatically part of this commit.
  • No Staging Area: There is no git add. All tracked files with changes are automatically included in the working-copy commit. You commit first and describe later.
  • Automatic Commits: jj frequently creates new, empty commits for you (e.g., after a jj pull). You just start working.
  • The Operation Log: Every action you take (commit, rebase, describe, etc.) is recorded. You can always go back using jj op log and jj undo. It's an incredibly powerful safety net.
  • Revsets: A powerful query language for selecting commits (e.g., jj log -r 'my-branch..@').

1. Setup & Configuration

# Initialize a new repo (defaults to a Git backend)
jj init my-new-project

# Use jj with an existing Git repo (colocated mode)
jj init --git-repo .

# Show the current configuration
jj config list

2. Everyday Workflow (Making Changes)

Viewing Status & History

# The main command to see what's going on.
# Shows the working-copy commit, its parent, and any conflicts.
jj status
# Git equivalent: A mix of git status and git log -n 1

# Show the history of the repository.
jj log
# Git equivalent: git log --oneline --graph

# Show the history of a specific file or directory
jj log -p path/to/file

# Show changes in the working-copy commit
jj diff
# Git equivalent: git diff HEAD

# Show changes between a specific revision and its parent(s)
jj show <revision>
# Git equivalent: git show <revision>

Creating & Modifying Commits

# Edit the commit message of the current working-copy commit (@)
# This also finalizes a commit if it was previously empty.
jj describe
# Git equivalent: git commit --amend

# Create a new, empty child commit and make it the working copy.
# Use this when you want to start a new, distinct piece of work.
jj new
# Git equivalent: Roughly git checkout -b <new-branch> then git commit (with an empty message)

# Edit an *existing* commit. Makes that commit the new working copy.
jj edit <revision-to-edit>
# Git equivalent: git checkout <revision>; git rebase -i (but much simpler)

# Go back to a previous commit (abandons the current working-copy commit)
jj abandon
# Git equivalent: git reset --hard HEAD~1 (if the commit was not pushed)

# Update the description of any commit, not just the working copy
jj describe <revision>

# Mark the current working-copy commit as immutable
# Useful for commits you are about to share.
jj immutable @

3. Undoing Things (The Safety Net)

# Show the log of all operations you've performed
jj op log

# Undo the very last operation (e.g., a bad rebase)
jj undo

# Restore a specific past state of the repo from the operation log
jj op restore <operation-id>

4. History Rewriting (Where jj Shines)

# Rebase a set of commits onto a new destination.
# Example: Move commits from 'my-feature' onto the latest 'main'
jj rebase -s 'my-feature' -d 'main'
# Git equivalent: git rebase main my-feature

# Interactively rebase a set of commits
jj rebase -r 'root()..@' -i # Rebase everything interactively

# Split a commit into multiple smaller ones.
jj split -r <revision>
# Git equivalent: git rebase -i and using the 'edit' command

# Squash a set of commits into a single commit.
# Squashes children into their parent.
jj squash -r 'my-branch~'
# Git equivalent: git rebase -i and using the 'squash' command

# Move changes from one commit to another
jj move --from <source-revision> --to <destination-revision>

# Abandon a commit (and all its descendants)
jj abandon <revision>

5. Branches & Remotes (Git Interop)

# Create a new branch pointing at the current commit
jj branch create my-new-branch

# Set an existing branch to point at a specific commit
jj branch set my-branch -r <revision>

# Delete a branch (doesn't delete the commits)
jj branch delete my-branch

# List all branches
jj branch list

# Fetch updates from a Git remote
jj git fetch

# Push committed changes to a Git remote
jj git push --all # Push all tracked branches
jj git push --branch my-branch # Push a specific branch

# To "pull" (fetch and rebase):
jj git fetch
jj rebase -s @ -d main@origin

**6. Revsets (Query Language)

Revsets are used in commands like jj log, jj diff, jj rebase, etc., with the -r or -s/-d flags.

Revset Expression Meaning
@ The current working-copy commit.
k@ or @- The parent of the working-copy commit.
<commit_id> A specific commit by its full or partial ID.
<branch_name> The commit pointed to by a branch.
root() The root commit of the repository.
x..y All commits in the range from x to y.
x~ or x- The parent(s) of commit x.
x+ Children of commit x.
all() All commits in the repository.
description("pattern") Commits whose description contains "pattern".
author("pattern") Commits by a specific author.

Practical Revset Examples:

# Log all commits from the 'main' branch to your current commit
jj log -r 'main..@'

# Log all commits that are not on the 'main' branch
jj log -r 'all() - main'

# Show the diff between your commit and the main branch
jj diff -r 'main'

# Find a commit by its description
jj log -r 'description("fix bug 123")'

7. Conflict Resolution

When a conflict occurs (e.g., after jj pull), jj status will show it clearly.

# List files with conflicts
jj resolve --list

# Edit a conflicted file to resolve the markers (<<<<<, =====, >>>>>), then...
# Mark the file as resolved (after removing conflict markers)
jj resolve path/to/conflicted/file

# To abandon your changes and take the other side of the conflict:
jj resolve --tool internal:other path/to/conflicted/file

# To take your changes and discard the other side:
jj resolve --tool internal:mine path/to/conflicted/file