A Short Guide to Jujutsu (Jj) for Git Users
Jujutsu (jj) is a modern, Git-compatible version control system from Google designed to be simple and powerful. It aims to make complex workflows effortless, especially cleaning up commit history. If you’ve ever felt that Git was hard or required too much discipline, jj
might be for you.
The jj
Philosophy
- Effortless History: With
jj
, you don’t need perfect commits from the start. Work freely, and clean up your history later with powerful commands likejj split
,jj squash
, andjj edit
. - No Staging Area: The working copy is always “live.” There is no need for
git add
orgit stash
. To work on something new, you just check out a different revision. - Free Checkpointing:
jj
records every operation. You can undo almost anything with the magicjj undo
command.
1. Installation and Configuration
First, install jj
on your system.
- Linux/macOS (Homebrew):
1
brew install jj
- Windows (Scoop/Winget):
1 2 3
scoop install jj # OR winget install --id Jujutsu.Jujutsu
- NixOS:
1 2 3
environment.systemPackages = with pkgs; [ jujutsu ]; # OR nix profile install nixpkgs#jujutsu
- For other methods, see the official installation guide.
After installing, configure your user details. This is a one-time setup.
|
|
2. Creating Repositories
- Clone a Git repo: This is the most common way to start. It creates a
jj
repo that is linked to the Git remote.1
> jj git clone https://github.com/user/repo.git
- Use
jj
in an existing Git repo:1 2
> cd my-existing-git-repo > jj git init --colocate
- Create a new repo:
1
> jj git init my-new-repo
3. The Core Workflow: Making Changes
The jj
workflow is different from Git’s. Instead of add -> commit
, you just do the work.
- Start a new change: Use
jj new
to create a new, empty revision to work on. Your changes will be automatically saved to it.1 2
> jj new # Now, edit your files
- Describe your change: When you’re ready, describe the revision. You can do this at any time.
1
> jj describe -m "My new feature"
- Check your status: Get in the habit of running these commands all the time to see what’s happening.
1 2 3
> jj st # See modified files > jj log # See the history of revisions > jj diff # See code changes in the current revision
4. Understanding Revision IDs vs. Commit IDs
This is the most important concept to grasp. Run jj log
to see them.
- Revision ID (e.g.,
wuloypwt
): A local, permanent ID for a set of changes. It never changes, even if you edit the commit. It’s how you refer to revisions injj
commands. - Commit ID (e.g.,
182d3ce4
): This is the Git SHA. It represents the entire state of the worktree. It will change every time you edit the revision (e.g., by rebasing or amending the message). This is what you see in GitHub.
5. Navigating and Editing History (The Magic)
jj
makes history manipulation safe and easy. There is no need for git stash
.
- Edit a past revision: Just use
jj edit
with the revision ID. Your working copy will update to that revision, and you can start making changes.Use1
> jj edit <revision-id> # e.g., jj edit wuloypwt
@
for the current revision,@-
for its parent, and@+
for a child. - Fixing Mistakes:
- The magic undo button: This reverts the last operation (a commit, a rebase, etc.). You can even run it multiple times.
1
> jj undo
- The operation log: To go further back in time, view the log of all operations and restore to a previous state.
1 2
> jj op log > jj op restore <operation-id>
- The magic undo button: This reverts the last operation (a commit, a rebase, etc.). You can even run it multiple times.
- Cleaning up commits:
- Split a commit: If a commit does too much, split it into smaller ones.
1
> jj split
- Combine commits: To merge a revision into its parent, use
jj squash
.1
> jj squash
- Split a commit: If a commit does too much, split it into smaller ones.
6. Branching and Remotes
In jj
, branches are just pointers (called “bookmarks”) to revisions.
- Start a new line of work:
1 2
# Creates a new revision on top of main > jj new main
- Do your work: Make some edits, describe the commit.
- Create a bookmark (branch): Name your branch before you push. The
-r @
flag means “give the name to the current revision.”1
> jj bookmark create my-feature -r @
- Pull latest changes: First, fetch from the remote. Then, rebase your stack of changes onto the main branch.
1 2
> jj git fetch > jj rebase -d origin/main
- Push your branch:
1 2
# The --allow-new flag is needed the first time you push a new branch > jj git push --branch my-feature --allow-new
7. Important Considerations & Downsides
- Force-Pushing is Normal:
jj
works by rewriting history, so it force-pushes changes. This can make reviewing a pull request commit-by-commit on GitHub difficult, as old commits will change. - State is Local: The undo history and the status of revisions are stored locally on your machine. If you clone your repo on a second computer, you won’t have the undo history from the first. A revision created on machine A will be “immutable” (you can’t use
jj split
, etc.) on machine B. Push your branches before switching computers to avoid losing work. - Using Git in Parallel: It’s safe to run read-only
git
commands (likegit status
). For any action that modifies history (commit
,rebase
,push
), use thejj
command to avoid confusion.
Also check out “The jj VCS Workshop” by Jimmy Koppel and of course the jj-vcs site