Skip to main content

to navigate · Press ? for help

Branching and Checkout

Branches in jj work differently than in git—they're just names for commits, not moving pointers.

Git's Branch Model

In git, a branch is a moving pointer that advances when you commit.

git checkout main  # Move HEAD to main
git commit         # main pointer advances

jj's Branch Model

In jj, a branch is a name pointing to a specific commit. The @ commit is what matters, not which branch you're "on".

# Create a branch pointing to current @
jj branch create my-feature

# @ doesn't change—just created a name
jj status

Creating Branches

git
git branch feature
git checkout -b feature
jj
jj branch create feature
Command comparison: git commands on the left, jj commands on the right
gitjj
git branch featurejj branch create feature
git checkout -b feature

Switching Branches

git
git checkout main
jj
jj checkout main
Command comparison: git commands on the left, jj commands on the right
gitjj
git checkout mainjj checkout main
NOTE:

In jj, jj checkout creates a new working copy (@) from the target commit. It doesn't "move" anything—commits are immutable.

Listing Branches

git
git branch
jj
jj branch list
# Or abbreviated
jj branch
Command comparison: git commands on the left, jj commands on the right
gitjj
git branchjj branch list

The @ vs Branches

The key insight: @ is your working copy, regardless of branches.

# Current state
jj status
Working copy: @
Parent commit: xyzk

# Create branch pointing to @
jj branch create my-work
my-work: xyzk

# @ hasn't changed
jj status
Working copy: @
Parent commit: xyzk

Practical Example

Let's create a feature branch and work on it:

# 1. Start on main
jj checkout main

# 2. Create a branch for your work
jj branch create feature-auth

# 3. Make changes (these go into @)
echo "auth code" > auth.js

# 4. Name the @ commit
jj describe -m "Add auth"

# 5. Move branch to point to @
jj branch set feature-auth

# 6. Create new @ for next work
jj new

Updating Branches

When you want a branch to point to your current @ commit:

# Make changes
jj describe -m "New feature"

# Move branch to @
jj branch set my-branch

# Verify
jj branch list
my-branch: xyzk  # Now points to @

Deleting Branches

git
git branch -d old-feature
jj
jj branch delete old-feature
Command comparison: git commands on the left, jj commands on the right
gitjj
git branch -d old-featurejj branch delete old-feature

Branch vs Commit

In jj, you don't need branches to track work. You can work directly with commits:

# Create a commit and remember its change ID
jj describe -m "Experiment"
jj new
# Change ID: abc123

# Later, come back to it
jj checkout abc123

# Create new work from there
jj describe -m "Continuing experiment"
jj new
NOTE:

In jj, change IDs are more stable than branch names. They survive rebases and can be used to track work across history rewrites.

Workflow Comparison

Feature branch workflow:

git
git checkout main
git checkout -b feature
vim app.js
git add app.js
git commit -m "Add feature"
git checkout main
git merge feature
jj
jj checkout main
jj new
vim app.js
jj describe -m "Add feature"
jj branch create feature
jj checkout main
jj new
jj merge feature
Command comparison: git commands on the left, jj commands on the right
gitjj
git checkout mainjj checkout main
git checkout -b featurejj new
vim app.jsvim app.js
git add app.jsjj describe -m "Add feature"
git commit -m "Add feature"jj branch create feature
git checkout mainjj checkout main
git merge featurejj new

Abandoning Work

Instead of deleting branches, in jj you abandon commits:

# Made a mistake on @
jj describe -m "Bad idea"

# Change your mind
jj abandon
# @ is removed, parent becomes @

jj status
# @ now points to previous commit

Try It Yourself

# Create a branch
jj branch create test-branch

# Make changes
echo "test" > test.txt
jj describe -m "Test commit"

# Update branch to point here
jj branch set test-branch

# Verify
jj branch list

# Go back to main
jj checkout main

# List branches again
jj branch list

Key Takeaways

  • Branches are names for commits, not moving pointers
  • @ is your working copy, independent of branches
  • jj branch create creates a name for current @
  • jj branch set moves a branch to point to current @
  • jj checkout creates a new @ from target commit
  • Change IDs are more stable than branch names

Next Steps

Now let's look at how jj handles viewing history and diffs.

Try It Yourself

Loading terminal...

Progress stored locally · No account needed · Open source