Introduction
Super Pull Requests (SPR) is the power tool for Jujutsu + GitHub workflows. It enables amend-friendly single PRs and effortless stacked PRs, bridging the gap between Jujutsu’s change-based workflow and GitHub’s pull request model.
⚠️ Important: Write Access Required
Due to GitHub API limitations, SPR requires write access to the repository. You must be a collaborator or have write permissions to use SPR. This is a GitHub platform constraint - the API does not support creating PRs from forks without write access to the target repository.
If you’re contributing to a project where you don’t have write access, you’ll need to use the standard fork + PR workflow through the GitHub web interface.
Why SPR?
For Everyone: Amend-Friendly PRs
- Amend freely: Use Jujutsu’s natural
jj squashandjj describeworkflow - Review cleanly: Reviewers see clear incremental diffs, not confusing force-push history
- Update naturally: Each update creates a new commit on GitHub, preserving review context
- Land cleanly: Everything squashes into one perfect commit on merge
For Power Users: Effortless Stacking
- Stack with confidence: Create dependent or independent PRs with automatic rebase handling
- Land flexibly: Use
--cherry-pickto land PRs in any order - Rebase trivially: Jujutsu’s stable change IDs survive rebases
- Review independently: Each PR shows only its changes, not the cumulative stack
The Problem SPR Solves
Jujutsu encourages amending changes. GitHub’s review UI breaks with force pushes. SPR bridges this gap by maintaining an append-only PR branch on GitHub while you amend freely locally.
When you update a PR with SPR:
- Locally: You amend using Jujutsu’s natural workflow
- On GitHub: SPR creates a new commit showing your changes
- For reviewers: They see clean “what changed since last review” diffs
- At landing: Everything squashes into one commit on main
What’s Next?
- New to SPR? Start with Installation and Setup
- Ready to create PRs? Check out the Single PR Workflow
- Want to stack PRs? Learn about Stacked PRs
- Need configuration help? See the Configuration Reference
Repository
SPR is open source and available at github.com/LucioFranco/jj-spr.
Credits
Super Pull Requests builds on the foundation of:
- Original spr by the Cord team
- Jujutsu integration by sunshowers
- Jujutsu by Martin von Zweigbergk and contributors
Installation
Prerequisites
Before installing jj-spr, you need to have Jujutsu (jj) installed on your system. See the Jujutsu installation guide for instructions.
Installation Methods
From Source (Recommended)
jj-spr is written in Rust. You need a Rust toolchain to build from source. See rustup.rs for information on how to install Rust if you don’t have it already.
Using cargo install (easiest):
git clone https://github.com/LucioFranco/jj-spr.git
cd jj-spr
cargo install --path spr
This will install the jj-spr binary to your ~/.cargo/bin directory.
Verify Installation
After installation, verify that jj-spr is available:
jj-spr --version
Next Steps
After installation, you’ll need to:
-
Set up the Jujutsu alias to use jj-spr as a subcommand:
jj config set --user aliases.spr '["util", "exec", "--", "jj-spr"]' -
Initialize in your repository:
cd your-jujutsu-repo jj spr init
See the Setup Guide for detailed configuration instructions.
Set up jj-spr
In the Jujutsu repo you want to use jj-spr in, run jj spr init; this will ask you several questions.
GitHub Authentication
jj-spr needs to authenticate with GitHub to create and manage pull requests on your behalf. There are two authentication methods available:
Option 1: GitHub CLI (Recommended)
If you have the GitHub CLI (gh) installed and authenticated, jj-spr can use it automatically:
-
Install and authenticate with GitHub CLI:
gh auth login -
Run
jj spr initand select “Yes” when asked to use GitHub CLI authentication
This is the recommended approach because:
- No need to manually create tokens
ghhandles token management and renewal- More secure - tokens are managed by GitHub’s official tool
Option 2: Personal Access Token (Manual)
If you prefer not to use the GitHub CLI, you can manually create a personal access token:
Required token scopes:
repo- Full control of private repositories (required for creating and updating PRs)workflow- Update GitHub Actions workflow files (required only if your changes include files in.github/workflows/)
Setup steps:
- Create a new token (this link pre-selects the correct scopes)
- Copy the generated token
- Run
jj spr initand paste the token when prompted
Security note: The token will be stored in your repository’s git config (.git/config). Make sure this file is not accidentally committed or shared.
For more details on creating tokens, see the GitHub documentation.
Running jj spr init
The rest of the settings that jj spr init asks for have sensible defaults, so almost all users can simply accept the defaults. The most common situation where you would need to diverge from the defaults is if the remote representing GitHub is not called origin.
See the Configuration reference page for full details about the available settings.
Updating Configuration
After running jj spr init, your settings are stored and you’re ready to go. If you need to change settings later:
Easiest method - Rerun init:
jj spr init
The defaults will be your current settings, so you can easily update what you need.
Alternative - Use git config:
# View current settings
git config --list | grep spr
# Update individual settings
git config spr.githubAuthToken "your-new-token"
For detailed configuration options, see the Configuration Reference.
Create and Land a Simple PR
This section details the process of putting a single commit up for review, and landing it (pushing it upstream). It assumes you don’t have multiple reviews in flight at the same time. That situation is covered in another guide, but you should be familiar with this single-review workflow before reading that one.
Understanding @ and @-
Before diving into the workflow, it’s crucial to understand Jujutsu’s revision symbols:
@= your working copy (the current state where you make edits)@-= the parent of your working copy (typically your last committed change)
After running jj commit:
- Your committed change moves to
@- - Your working copy
@becomes empty (ready for new work)
Why this matters for jj-spr:
jj spr diffdefaults to operating on@-(your completed change)jj spr landdefaults to operating on@(your working copy)
This means after jj commit, you’ll typically:
- Run
jj spr diff(no args needed - creates PR for@-) - Run
jj spr land -r @-(must specify@-since land defaults to@)
When in doubt: Run jj log to see your revision history and where you are.
Example jj log output:
@ qpvuntsm you@example.com 2024-01-15 12:00:00 (empty)
│ (no description set)
○ kmkuslkw you@example.com 2024-01-15 11:30:00
│ Add authentication feature
◆ main@origin
In this example:
@is empty (ready for new work)@-is the “Add authentication feature” commit (what you’d create a PR for)
Basic Workflow with Jujutsu
-
Fetch the latest changes from upstream:
jj git fetch -
Create a new change for your work:
jj new main@origin -
Make your changes and describe them:
# Edit your files... # ... make your changes ... # Describe the change jj describe -m "Add user authentication This implements basic user authentication using JWT tokens."See this guide for what to put in your commit message.
-
Create a new empty change on top, so your PR change moves to
@-:jj newThis creates an empty working copy at
@, with your PR change now at@-. This is the recommended workflow becausejj spr diffdefaults to operating on@-. -
Run
jj spr diffto create a PR for your change:jj spr diffNote: By default,
diffoperates on@-(the parent of your working copy). Since we just ranjj new, your completed change is now at@-, sojj spr diffwill correctly target it. -
Wait for reviewers to approve. If you need to make changes:
-
Make your edits in your working copy (
@). Jujutsu automatically tracks the changes. -
When ready, squash the changes into your PR change at
@-:jj squash -
Update the description if needed:
jj describe -r @- -
Run
jj spr diffto update the PR. If you changed the commit message, add the--update-messageflag:jj spr diff --update-messageThis will update the PR with the new version of your change. jj-spr will prompt you for a short message that describes what you changed. You can also pass the update message on the command line using the
--message/-mflag.
-
-
Once your PR is approved, land it:
jj spr land -r @-Note: By default,
landoperates on@(your working copy). Since your PR change is at@-, you must specify-r @-. -
🚨 CRITICAL: After landing, you MUST manually rebase your working copy:
jj git fetch jj rebase -r @ -d main@origin⚠️ IMPORTANT - DO NOT SKIP THIS STEP: jj-spr currently requires manual rebasing after every
jj spr land. Thelandcommand merges your PR on GitHub but does not automatically update your local Jujutsu state.What happens if you skip this:
- Your working copy will still be based on old
main - Future changes will be based on outdated code
- You’ll face conflicts and confusion later
- Your stack will be out of sync with GitHub
This is a known limitation that may be automated in future versions. For now, always run the rebase commands immediately after landing.
Pro tip: Create a shell alias (see Troubleshooting) to combine landing and rebasing into one command.
- Your working copy will still be based on old
Working with Change IDs
In Jujutsu, every change has a stable change ID (like qpvuntsm). You can use these IDs to refer to specific changes:
# Create a PR for a specific change
jj spr diff -r qpvuntsm
# Land a specific change
jj spr land -r qpvuntsm
When you update
When you run jj spr diff to update an existing PR, your update will be added to the PR as a new commit, so that reviewers can see exactly what changed. The new commit’s message will be what you entered when prompted.
The individual commits that you see in the PR are solely for the benefit of reviewers; they will not be reflected in the commit history when the PR is landed. The commit that eventually lands on upstream main will always be a single commit, whose message is the title and description from the PR.
Updating before landing
Unlike Git, Jujutsu automatically maintains your change’s identity even when rebasing. However, you must still run jj spr diff to update the PR before landing if you’ve rebased onto new upstream changes, or else jj spr land will fail.
This is because jj spr land checks to make sure that the PR content matches what will be landed.
Conflicts on landing
jj spr land may fail with conflicts if there have been new changes pushed to upstream main since you last fetched. In this case:
-
Fetch and rebase your change onto latest upstream
main:jj git fetch jj rebase -r @ -d main@origin -
Resolve any conflicts:
# Jujutsu will mark conflicts in the files # Edit the files to resolve conflicts jj resolve -
Run
jj spr diffto update the PR:jj spr diff -
Run
jj spr landagain:jj spr land
Note that even if your change is not based on the latest upstream main, landing will still succeed as long as there are no conflicts with the actual latest upstream main.
Common Scenarios
Landing without specifying revision
# These commands operate on different revisions by default:
jj spr diff # operates on @- (parent of working copy)
jj spr land # operates on @ (working copy)
Following the recommended workflow where you keep an empty working copy at @, your PR change will be at @-, so you must specify it when landing:
jj new main@origin
# ... make changes ...
jj describe -m "My change"
jj new # Moves PR change to @-
jj spr diff
jj spr land -r @- # Must specify @- since land defaults to @
Quick workflow
# 1. Create a new change and make your edits
jj new main@origin
# ... make changes ...
# 2. Describe your change
jj describe -m "Add feature"
# 3. Create a new empty change on top (moves your PR change to @-)
jj new
# 4. Create PR (operates on @-, your completed change)
jj spr diff
# 5. Make updates if needed
# ... edit files ...
jj squash # Squash changes into @-
jj spr diff # Update the PR
# 6. After approval, land it
jj spr land -r @-
# 7. Rebase your working copy
jj git fetch
jj rebase -r @ -d main@origin
Troubleshooting
“I ran jj spr diff but nothing happened” or “No changes to diff”
Cause: Your change might be at a different revision than @- (the default).
Solutions:
-
Check where your changes are:
jj log -
If your change is at
@(working copy is not empty):jj spr diff -r @ -
If you forgot to run
jj newafter describing your change:jj new # Creates empty change on top, moving your PR change to @- jj spr diff # Now operates on @- (your completed change)
“I forgot to rebase after landing”
Problem: After jj spr land, you must manually rebase your working copy onto the updated main@origin.
Solution:
jj git fetch
jj rebase -r @ -d main@origin
Why this matters: If you don’t rebase, your future changes might be based on outdated code, leading to conflicts later.
“I landed the wrong change”
Problem: You landed a change you didn’t mean to land.
Solution: Unfortunately, once landed, the PR is merged on GitHub. You’ll need to:
- Revert the change on GitHub or locally
- Create a new PR with the revert
Prevention: Always double-check which change you’re landing:
jj log -r @- # Check what you're about to land
jj spr land -r @-
“jj spr land failed with conflicts”
Cause: Upstream main has changed since your last fetch, causing conflicts.
Solution:
-
Fetch and rebase onto latest main:
jj git fetch jj rebase -r @- -d main@origin -
Resolve any conflicts (Jujutsu will mark them in files):
# Edit conflicted files # Jujutsu automatically tracks resolution -
Update the PR with resolved conflicts:
jj spr diff -
Try landing again:
jj spr land -r @-
“The PR content doesn’t match what will be landed”
Cause: You’ve made local changes (like rebasing) without updating the PR.
Solution:
jj spr diff # Update the PR to match local state
jj spr land -r @- # Now landing will work
“I can’t find my change ID”
Problem: The docs reference change IDs like qpvuntsm but you don’t know yours.
Solution:
# Show recent changes with their IDs
jj log
# Show only your changes since main
jj log -r 'main@origin..'
# The first column shows the change ID
# Example output:
# @ qpvuntsm you@example.com 2024-01-15
# │ Add feature
Stack Multiple PRs
The differences between jj-spr’s commit-based workflow and GitHub’s default branch-based workflow are most apparent when you have multiple reviews in flight at the same time.
This guide assumes you’re already familiar with the workflow for simple, non-stacked PRs.
Two Approaches: Independent vs Dependent
When working with multiple PRs, you have two main approaches:
-
Independent changes with
--cherry-pick(recommended for most cases)- Changes can be landed in any order
- Simpler workflow, fewer manual steps
- Best when changes don’t strictly depend on each other
- Example: Bug fix + new feature in same codebase area
-
Dependent stacks (for true dependencies)
- Changes must be landed in order (parent → child)
- More complex workflow with manual rebasing
- Only use when second change literally won’t work without first
- Example: Add database table → Add API endpoints using that table
Not sure which to use? Start with --cherry-pick. You can always switch to dependent stacks if needed.
In Jujutsu, managing stacked changes is much simpler than in Git because Jujutsu maintains stable change IDs and automatically handles rebasing operations.
Independent Changes with –cherry-pick (Recommended)
For most users, this is the workflow you want. It’s simpler and more flexible than dependent stacks.
Creating Independent Changes
-
Create your first change:
jj new main@origin # Make changes... jj describe -m "Add authentication module" jj new # Move to empty working copy, PR change at @- jj spr diff # Create PR #123 -
Create your second change (also based on main):
jj new main@origin # Make changes... jj describe -m "Fix login bug" jj new # Move to empty working copy, PR change at @- jj spr diff --cherry-pick # Create PR #124 as independent
The --cherry-pick flag tells jj-spr to create the PR as if the change were based directly on main@origin, even if locally you have both changes in a stack.
Landing Independent Changes
You can land these in any order:
# Land either one first
jj spr land --cherry-pick -r <change-id>
# Then the other
jj spr land --cherry-pick -r <other-change-id>
After landing, you still need to rebase:
jj git fetch
jj rebase -r @ -d main@origin
Benefits:
- ✅ Land in any order
- ✅ Simpler workflow
- ✅ Less chance of breaking your stack
- ✅ Reviewers see clean, focused PRs
Dependent Stacks (Advanced)
Only use this if your changes truly depend on each other. The workflow is more complex.
Creating Dependent Changes
This is for when the second change literally won’t work without the first.
-
Create your first change on top of
main:jj new main@origin # Make changes... jj describe -m "Add authentication module" -
Create your second change on top of the first:
jj new # Make changes that depend on the authentication module... jj describe -m "Add user profile endpoints" -
Create an empty working copy on top:
jj newNow your stack looks like:
@= empty working copy@-= “Add user profile endpoints” (second PR change)@--= “Add authentication module” (first PR change)
-
Run
jj spr diff --allto create PRs for all changes in your stack:jj spr diff --allThis is equivalent to calling
jj spr diffon each change in your stack from@-back tomain@origin.
Understanding Your Stack
Use jj log to visualize your stack:
jj log -r 'main@origin..'
Example output:
@ qpvuntsm you@example.com 2024-01-15 12:00:00
│ (empty)
○ kmkuslkw you@example.com 2024-01-15 11:30:00
│ Add user profile endpoints
○ rlvkpnrw you@example.com 2024-01-15 11:00:00
│ Add authentication module
◆ main@origin
In this example:
@= empty working copykmkuslkw= second change (depends on first)rlvkpnrw= first change (base of stack)- Change IDs are in the first column
This shows all your changes that are descendants of main@origin.
Visual: Local Stack vs GitHub PRs
Here’s what the above stack looks like locally vs on GitHub:
Local Jujutsu State: GitHub State:
@ qpvuntsm (empty)
│
○ kmkuslkw → PR #124: "Add user profile endpoints"
│ Add user profile endpoints base: jj-spr-rlvkpnrw (PR #123's branch)
│ branch: jj-spr-kmkuslkw
○ rlvkpnrw → PR #123: "Add authentication module"
│ Add authentication module base: main
│ branch: jj-spr-rlvkpnrw
◆ main@origin
Key points:
- Each change has a unique ID (
rlvkpnrw,kmkuslkw) - jj-spr creates GitHub branches automatically (
jj-spr-{change-id}) - Stacked PRs: PR #124 is based on PR #123’s branch
- When PR #123 lands, PR #124 automatically updates to be based on
main
Updating Changes in the Stack
Suppose you need to update the first change (authentication module with ID rlvkpnrw) in response to review feedback.
Step 1: Find the change ID
First, identify which change you want to edit:
jj log -r 'main@origin..'
Output:
@ qpvuntsm (empty)
○ kmkuslkw Add user profile endpoints
○ rlvkpnrw Add authentication module ← This is the one we want to update
◆ main@origin
Method 1: Squash from working copy (Recommended)
This is the recommended approach that aligns with the standard workflow:
-
Make your changes in your working copy (
@):# You're already at @ (empty working copy) # Make your edits... -
Squash the changes into the target change:
jj squash --into rlvkpnrw # Use the actual change ID -
Update the PR:
jj spr diff -r rlvkpnrw
Method 2: Direct editing (jj edit)
Alternatively, edit the change directly:
-
Edit the change directly:
jj edit rlvkpnrw # Use the actual change ID # Make your changes... -
The changes are automatically absorbed. Jujutsu will automatically rebase descendant changes.
-
Update the PR for that specific change:
jj spr diff -r @ # @ is now rlvkpnrw since we edited it -
Return to your empty working copy:
jj new qpvuntsm # Creates new working copy on top of qpvuntsm
Which method to use?
- Use
jj squash(Method 1) for consistency with the standard workflow - Use
jj edit(Method 2) if you want to work directly on the change
Landing Stacked Changes
🚨 CRITICAL WARNINGS FOR STACKED LANDING:
Landing order matters: Always land changes in order (parent before child). Landing out of order will cause merge conflicts and break your stack.
Manual rebasing required: After every
jj spr land, you must manually rebase both your working copy AND any remaining changes in the stack. This is error-prone and easy to forget.
Landing Process (Parent Change)
Using our example stack where rlvkpnrw (auth module) is the parent and kmkuslkw (user profiles) is the child:
Before landing:
○ kmkuslkw Add user profile endpoints (PR #124)
○ rlvkpnrw Add authentication module (PR #123) ← Land this first
◆ main@origin
Step-by-step:
-
Land the parent change:
jj spr land -r rlvkpnrw # Use the actual change ID -
REQUIRED - Fetch and rebase working copy:
jj git fetch jj rebase -r @ -d main@origin -
REQUIRED - Rebase child changes onto new main:
# Check what needs rebasing jj log -r 'main@origin..' # Rebase the child change jj rebase -s kmkuslkw -d main@origin # kmkuslkw is now based on main -
REQUIRED - Update remaining PRs:
jj spr diff --all # Updates PR #124 to be based on main instead of PR #123
After landing:
○ kmkuslkw Add user profile endpoints (PR #124, now based on main)
◆ main@origin (now includes rlvkpnrw)
This is 4 commands just to land ONE change. If you skip any step, your stack will be broken.
Best Practices
- ✅ Always land in order: Parent → Child → Grandchild
- ✅ Double-check change IDs before landing (use
jj log) - ✅ If changes aren’t truly dependent, use
--cherry-pickinstead (see above) - ❌ Never land out of order unless you’re prepared to manually fix merge conflicts
Rebasing the Whole Stack
One of the major advantages of Jujutsu is that rebasing your entire stack onto new upstream changes is trivial:
-
Fetch the latest changes:
jj git fetch -
Rebase your stack:
jj rebase -s <root-change-id> -d main@originWhere
<root-change-id>is the first change in your stack. -
Update all PRs:
jj spr diff --all
Working with Revsets
Jujutsu’s revset language makes it easy to work with stacks:
# Show all your changes not yet in main
jj log -r 'mine() & ~main@origin'
# Create PRs for all your ready changes
jj spr diff --all -r 'ready() & ~main@origin'
# Show changes that have PRs
jj log -r 'description(regex:"#[0-9]+")'
Tips for Stack Management
-
Keep changes focused: Each change should represent one logical unit of work.
-
Use descriptive commit messages: This helps when navigating your stack.
-
Leverage change IDs: Unlike Git commits, Jujutsu change IDs remain stable through rebases.
-
Use
jj splitwhen needed: If a change gets too large, split it:jj split -r <change-id> -
Monitor your stack: Regularly run
jj logto understand your stack’s structure.
The Jujutsu + jj-spr workflow makes stacked PRs feel natural and eliminates much of the complexity found in traditional Git-based stacking workflows.
Format and Update Commit Messages
In Jujutsu, commit messages (called “descriptions”) follow a similar format to traditional Git commits, but with some jj-specific considerations.
Message Format
You should format your change descriptions like this:
One-line title
Then a description, which may be multiple lines long.
This describes the change you are making with this commit.
Reviewers: github-username-a, github-username-b
The first line will be the title of the PR created by jj spr diff, and the rest of the lines except for the Reviewers line will be the PR description (i.e. the content of the first comment). The GitHub users named on the Reviewers line will be added to the PR as reviewers.
Working with Jujutsu Descriptions
Set or update a change description:
# Interactive editor (recommended for multi-line descriptions)
jj describe
# Or set directly from command line
jj describe -m "Add feature
This is a really cool feature!"
View the current description:
jj log --no-graph -r @
Updating the PR Title and Description
When you create a PR with jj spr diff, the PR becomes the source of truth for the title and description. When you land a change with jj spr land, its description will be updated to match the PR’s title and description.
If you want to update the title or description, there are two ways:
-
Modify the PR through GitHub’s UI (simplest method)
-
Update locally and push:
# Edit the description jj describe # Push the update to the PR jj spr diff --update-messageNote: This does not update reviewers; that must be done in the GitHub UI.
If you want to sync your local description with the PR’s current title and description:
jj spr amend
Fields Added by jj spr
At various stages, jj spr will add metadata to your change description:
-
After creating a PR,
jj spr diffadds:Pull Request: https://github.com/example/project/pull/123This line tells
jj sprthat a PR exists for this change. -
After landing,
jj spr landadds:Reviewed By: github-username-aThis lists the GitHub users who approved the PR.
Example Lifecycle
Initial description:
Add user authentication
Implements JWT-based authentication for the API.
Reviewers: alice, bob
After jj spr diff:
Add user authentication
Implements JWT-based authentication for the API.
Reviewers: alice, bob
Pull Request: https://github.com/example/api/pull/456
After jj spr land (with bob’s approval):
Add user authentication
Implements JWT-based authentication for the API.
Reviewers: alice, bob
Reviewed By: bob
Pull Request: https://github.com/example/api/pull/456
Jujutsu-Specific Tips
-
Change IDs are stable: Unlike Git commit hashes, Jujutsu change IDs remain the same even when you modify the description.
-
Description templates: You can set up a description template:
# In .jj/repo/config.toml [templates] draft_commit_description = ''' Reviewers: ''' -
Bulk operations: Update multiple descriptions at once:
# Reword multiple changes interactively jj reword -r 'mine() & ~main@origin'
Reformatting
jj spr format reformats your current change’s description to match the canonical format:
jj spr format
This is purely local and doesn’t touch GitHub. It’s useful for cleaning up formatting before running jj spr diff.
Configuration
The recommended way to configure jj-spr is to run jj spr init, rather than setting config values manually. You can rerun jj spr init to update config at any time.
Configuration Storage
ℹ️ Hybrid Configuration System: jj-spr uses a dual-layer configuration approach that bridges Git and Jujutsu config systems.
How it works:
jj spr initwrites configuration to your repository’s git config (.git/config)- At runtime, jj-spr reads from Jujutsu config first, then falls back to git config
Configuration is stored in git config but jj-spr reads from Jujutsu config first, then falls back to git config.
Configuration priority (highest to lowest):
- Command-line flags (e.g.,
--github-repository) - Jujutsu user config (
~/.jjconfig.toml) - Jujutsu repository config (
.jj/repo/config.toml) - Git repository config (
.git/config) ← wherejj spr initwrites - Environment variables (e.g.,
GITHUB_TOKEN) - Built-in defaults
This design allows:
- Easy initial setup via
jj spr init(writes to git config) - Flexibility to override settings in Jujutsu config if preferred
- Compatibility with both git-based and jj-native workflows
Configuration Values
jj-spr uses the following configuration values:
| config key | CLI flag | description | default1 | default in jj spr init2 |
|---|---|---|---|---|
githubAuthToken | --github-auth-token3 | The GitHub PAT (personal authentication token) to use for accessing the GitHub API. | ||
githubRemoteName | Name of the git remote in this local repository that corresponds to GitHub | origin | origin | |
githubRepository | --github-repository | Name of repository on github.com in owner/repo format | extracted from the URL of the GitHub remote | |
githubMasterBranch | The name of the centrally shared branch into which the pull requests are merged | main | taken from repository configuration on GitHub | |
branchPrefix | --branch-prefix | String used to prefix autogenerated names of pull request branches | jj-spr/GITHUB_USERNAME/ | |
requireApproval | If true, jj spr land will refuse to land a pull request that is not approved | false | true |
Notes:
- All config keys are in the
sprsection; for example,spr.githubAuthToken. - Values passed on the command line take precedence over values set in configuration.
Setting Configuration
Option 1: Using jj spr init (Recommended)
The easiest way to configure jj-spr:
jj spr init
This writes settings to git config (.git/config).
Option 2: Using git config commands
Since jj spr init writes to git config, you can modify settings with git commands:
# Set configuration values
git config spr.githubAuthToken "your-token"
git config spr.branchPrefix "my-prefix/"
Option 3: Using jj config set
If you prefer Jujutsu’s native config, you can override git config settings:
# Set repository-specific config (highest priority)
jj config set --repo spr.githubAuthToken "your-token"
# Set user-specific config (applies to all repos)
jj config set --user spr.branchPrefix "my-prefix/"
Option 4: Editing config files directly
Git config (.git/config) - where jj spr init writes:
[spr]
githubAuthToken = "ghp_..."
githubRepository = "owner/repo"
githubRemoteName = "origin"
githubMasterBranch = "main"
branchPrefix = "jj-spr/username/"
requireApproval = true
Jujutsu config (.jj/repo/config.toml) - overrides git config:
[spr]
# Any values here override git config
githubAuthToken = "ghp_..."
Jujutsu-Specific Configuration
In addition to jj-spr settings, you may want to configure Jujutsu itself for optimal workflow:
# Recommended Jujutsu settings for jj-spr workflow
[ui]
default-command = "log"
pager = "less -FRX"
[git]
# Prefix for branches pushed to GitHub
push-branch-prefix = "jj-spr/"
[revset-aliases]
# Useful revsets for jj-spr workflow
'mine' = 'author(exact:"your.email@example.com")'
'ready' = 'mine & description(regex:"^(?!wip:)")'
'has-pr' = 'mine & description(regex:"Pull Request:")'
[templates]
# Custom log format showing PR numbers
'log' = '''
label(if(current_working_copy, "bold"),
concat(
separate(" ",
label("cyan", change_id.shortest(8)),
label("magenta", if(description, description.first_line(), "(no description)"))
),
if(description.match("Pull Request: .*(#\\d+)"),
label("green", " " ++ description.match("Pull Request: .*(#\\d+)")))
)
)
'''
Environment Variables
jj-spr also respects certain environment variables:
GITHUB_TOKEN: Can be used instead of configuringgithubAuthTokenJJ_SPR_BRANCH_PREFIX: Override forbranchPrefixconfig
-
Value used by
jj sprif not set in configuration. ↩ -
Value suggested by
jj spr initif not previously configured. ↩ -
Be careful using this: your auth token will be in your shell history. ↩
Commands Reference
This page provides a complete reference for all SPR commands.
Global Options
All commands support the following global options:
-h, --help- Show help information-V, --version- Show version information
Commands
jj spr init
Initialize SPR in the current repository. This command prompts for your GitHub Personal Access Token and configures the repository.
Usage:
jj spr init
What it does:
- Detects GitHub repository from git remotes
- Prompts for GitHub Personal Access Token
- Stores configuration in git config
jj spr diff
Create or update a pull request for one or more changes.
Usage:
jj spr diff [OPTIONS]
Options:
-r, --revision <REV>- Revision(s) to operate on (default:@-)- Single revision:
-r @-,-r <change-id> - Range:
-r main..@,-r a::c
- Single revision:
-a, --all- Create/update PRs for all changes from base to current--base <REV>- Base revision for--allmode (default: trunk)-m, --message <MSG>- Message for PR update commits--update-message- Update PR title/description from local commit--draft- Create PR as draft--cherry-pick- Create PR as if cherry-picked onto main
Examples:
# Create PR for parent of working copy (default)
jj spr diff
# Create PR for specific change
jj spr diff -r <change-id>
# Create PRs for all changes in range
jj spr diff -r main..@
# Create independent PR
jj spr diff --cherry-pick
# Update PR with new changes and message
jj spr diff -m "Address review comments"
jj spr land
Land (squash-merge) an approved pull request.
Usage:
jj spr land [OPTIONS]
Options:
-r, --revision <REV>- Revision to land (default:@)--cherry-pick- Land PR independently (for use with stacks)
Examples:
# Land PR for parent of working copy
jj spr land -r @-
# Land specific change
jj spr land -r <change-id>
# Land independently (with --cherry-pick)
jj spr land --cherry-pick -r <change-id>
Important: After landing, you must manually rebase your working copy:
jj git fetch
jj rebase -r @ -d main@origin
jj spr list
List open pull requests and their status.
Usage:
jj spr list
Output includes:
- PR number and title
- Current state (open, draft, etc.)
- Review status (approved, changes requested, etc.)
- CI status
jj spr close
Close a pull request without merging.
Usage:
jj spr close [OPTIONS]
Options:
-r, --revision <REV>- Revision whose PR to close (default:@)
Examples:
# Close PR for current working copy
jj spr close
# Close PR for specific change
jj spr close -r <change-id>
jj spr amend
Update local commit message with content from GitHub PR.
Usage:
jj spr amend [OPTIONS]
Options:
-r, --revision <REV>- Revision to update (default:@)
Use case: When PR title/description has been updated on GitHub and you want to sync those changes back to your local commit.
Revision Syntax
SPR supports Jujutsu’s revision syntax:
@- Current working copy@-- Parent of working copy<change-id>- Specific change by ID (e.g.,qpvuntsm)main@origin- Remote tracking branchmain..@- Range from main to currenta::c- Inclusive range from a to c
See Jujutsu revset documentation for more details.