Skip to main content
jj-git

Branching and Checkout

Step 4 of 12

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

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

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

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

Listing Branches

jj
jj branch list
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 edit 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

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 edit 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:

jj
jj edit main
jj new
vim app.js
jj describe -m "Add feature"
jj branch create feature
jj edit main
jj new
Command comparison: git commands on the left, jj commands on the right
gitjj
git checkout mainjj edit 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 edit 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

$
$
$
$
$

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 edit 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.