Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How I stack PRs

This is the loop I use most: turn one idea into a stack of small PRs, push them before they are polished, and keep coding while review catches up.

The example uses this book as the work item. Imagine I want to build it as three small pull requests:

  1. Create the mdBook skeleton.
  2. Add the mental model and aliases.
  3. Add common workflow examples.

The stack will look like this:

@ empty working-copy change
docs: add common jj workflow examples
docs: explain mental model and aliases
docs: create mdbook skeleton
main

Stack

A stack is a line of small commits where each commit builds on the one below it. In this guide, I usually turn each commit into its own small PR.

Trunk

In this book, main is trunk: the shared branch I keep my work based on.

For this example I start from a clean repo with main fetched. The files are from this book, but the command loop is the part to copy.

Start from main

I fetch remote changes and create a new empty change on top of main:

jj git fetch
jj new main

This creates an empty working-copy change. In jj, the current working-copy change is @.

@

@ is the current working-copy change. It exists in the jj graph even before I commit it.

Before editing, I like to check that I am starting clean:

jj status

First PR: create the book

First I make the smallest useful piece: the book exists and has a table of contents.

book.toml
src/SUMMARY.md
src/introduction.md

This is the small loop I repeat all day: look, commit, look again, push.

jj diff
jj commit -m "docs: create mdbook skeleton"
jj diff -r @-
jj git push -c @-

jj diff -r @- is the check I care about here. I want to review the change I just committed before I push it.

@-

@- means the parent of @. Right after jj commit, that is usually the change I just committed.

jj creates a temporary bookmark with a generated name like push-abc.... That is the branch name GitHub sees.

Bookmark

A bookmark is the jj name that maps to a branch. For review, the important part is that GitHub has a branch name to point at.

I do not need to name it perfectly. I just need a small PR my team can review.

I usually look at the graph after pushing:

jj log

I expect to see the new push-* bookmark on the commit I just pushed and an empty @ above it.

Second PR: explain the model

After jj commit, @ is already an empty child of the first PR. I can keep writing, and the next commit naturally stacks on top.

I edit the next logical unit:

src/mental-model.md
src/config-and-aliases.md

Then I repeat the same loop:

jj diff
jj commit -m "docs: explain mental model and aliases"
jj diff -r @-
jj git push -c @-

Now I have two push-* bookmarks, one for each PR in the stack.

Each PR has one job. Reviewers can look at the book skeleton first, then the model, then the examples.

Third PR: add common workflows

I edit the workflow examples:

src/common-things.md
src/wip-private-commits.md
src/conflict-resolution.md
src/reviewing-teammate-work.md

Then I repeat the loop again:

jj diff
jj commit -m "docs: add common jj workflow examples"
jj diff -r @-
jj git push -c @-

The stack has three pushed PR branches now.

At this point the work is visible. It does not have to be final.

Inspect the stack

I check the local stack:

jj log -r main..@

I check the pushed temporary branch bookmarks:

jj log -r 'bookmarks("push-*")'

The shape should be roughly:

@ empty working-copy change
push-c... docs: add common jj workflow examples
push-b... docs: explain mental model and aliases
push-a... docs: create mdbook skeleton
main

bookmarks("push-*") is my quick way to see the review branches jj created for this stack.

Then I keep moving

At this point the interesting thing has already happened: I split one idea into reviewable pieces, pushed them early, and kept the local graph easy to read.

Once review starts, the loop is the same shape: fetch, rebase the pushed stack when needed, edit the change that needs feedback, and push the push-* bookmarks again.

The next chapters add my small config layer and then show how I keep the open PRs moving.