The power tool for Jujutsu + GitHub workflows. Single PRs with amend support. Stacked PRs without the complexity.
A command-line tool that bridges Jujutsu's change-based workflow with GitHub's pull request model. Amend freely in your local repository while keeping reviewers happy with clean, incremental diffs.
⚠️ Important: Write Access RequiredDue 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.
- 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
- 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.
git clone https://github.com/LucioFranco/jj-spr.git
cd jj-spr
cargo install --path sprThis installs the jj-spr binary to your ~/.cargo/bin directory.
Configure jj spr as a subcommand:
jj config set --user aliases.spr '["util", "exec", "--", "jj-spr"]'Alternative configuration methods
Manual Configuration:
Add to your Jujutsu config (~/.jjconfig.toml or .jj/repo/config.toml):
[aliases]
spr = ["util", "exec", "--", "jj-spr"]Direct Binary Path:
[aliases]
spr = ["util", "exec", "--", "/path/to/jj-spr"]-
Initialize in your repository:
cd your-jujutsu-repo jj spr init -
Provide your GitHub Personal Access Token when prompted.
The recommended workflow keeps an empty working copy (@) with PR changes at @-:
# 1. Create a change
jj new main@origin
echo "new feature" > feature.txt
jj describe -m "Add new feature"
# 2. Move to empty working copy
jj new # Your PR change is now at @-
# 3. Submit for review
jj spr diff # Creates PR for @-
# 4. Amend based on feedback
echo "updated feature" > feature.txt
jj squash # Squash changes into @-
jj spr diff # Updates PR with new commit (reviewers see clean diff)
# 5. Land when approved
jj spr land -r @-
# 6. Rebase after landing
jj git fetch
jj rebase -r @ -d main@origin@= your working copy (where you make edits)@-= parent of working copy (your PR change)jj spr diffdefaults to@-(your completed change)jj spr landdefaults to@(working copy)- Change IDs remain stable through rebases, keeping PRs linked
-
jj spr diff- Create or update a pull request- Updates create new commits on GitHub (reviewers see clean diffs)
- Supports single changes or ranges:
-r @-,-r main..@,--all - Cherry-pick mode:
--cherry-pickfor independent PRs
-
jj spr land- Land (squash-merge) an approved pull request- Supports cherry-pick mode for landing PRs in any order
- Requires manual rebase after landing (see docs)
-
jj spr list- List open pull requests and their status -
jj spr close- Close a pull request -
jj spr amend- Update local commit message from GitHub
# Single PR workflow
jj spr diff # Create/update PR for @-
jj spr land -r @- # Land the PR
# Stacked PRs (dependent)
jj spr diff --all # Create PRs for all changes
jj spr land -r <change-id> # Land bottom of stack
# Independent PRs
jj spr diff --cherry-pick # Create independent PR
jj spr land --cherry-pick -r <id> # Land in any order
# Working with specific changes
jj spr diff -r <change-id> # Update specific change
jj spr diff -r main..@ # Update range of changesSPR excels at handling stacked PRs with two approaches:
Use --cherry-pick for changes that don't strictly depend on each other:
- Land in any order
- Simpler workflow
- Best for most use cases
For true dependencies where one change requires another:
- Automatic base branch handling
- Changes must land in order (parent → child)
- More complex but handles true dependencies
See the stacking documentation for detailed workflows.
SPR stores configuration in your repository's git config:
# Set GitHub repository (if not auto-detected)
git config spr.githubRepository "owner/repo"
# Set branch prefix for generated branches
git config spr.branchPrefix "yourname/spr/"
# Require approval before landing
git config spr.requireApproval true- Repository Write Access: You must have write permissions (collaborator status) on the target GitHub repository
- Jujutsu: Colocated Git repository (
jj git init --colocate) - GitHub Access: Personal Access Token with
reposcope permissions - Git: Git binary in PATH
Full documentation is available at luciofranco.github.io/jj-spr
Quick links:
- Installation - Detailed installation instructions
- Setup - Initial configuration
- Simple PR Workflow - Single PR workflow guide
- Stacked PRs - Multi-PR workflows and stacking
- Commit Messages - Message format and sections
- Commands Reference - Complete command reference
- Configuration - All configuration options
Contributions welcome! Please:
- Check existing issues before starting work
- Add tests for new functionality
- Follow existing code style (
cargo fmtandcargo clippy) - Update documentation as needed
# Run unit tests
cargo test
# Run integration tests (requires jj and git)
cargo test --test '*'
# Check code quality
cargo clippy --all-features --all-targets
cargo fmt --checkSuper Pull Requests builds on the foundation of:
- Original spr by the Cord team
- Jujutsu integration by sunshowers
- Jujutsu by Martin von Zweigbergk and contributors
MIT License - see LICENSE for details.