A command-line tool for submitting and updating GitHub Pull Requests from local Jujutsu changes. Built for Jujutsu's workflow of working with changes (not branches), jj-spr makes it natural to send individual changes for review and land them independently or in stacks.
Key features:
- 📝 Review changes, not branches: Each Jujutsu change becomes a PR, aligned with Jujutsu's branch-free philosophy
- 🥞 Powerful stacking: Create dependent PRs that can be reviewed and landed independently, with automatic rebase handling
- 🔄 Amend-friendly: Update PRs by amending local changes - stable change IDs mean your PRs stay linked even through rebases
- ⚡ Streamlined workflow: Simple commands that work with Jujutsu's natural change-based model
Designed to be run as a Jujutsu subcommand: jj spr <command>.
This project is a fork of the original spr tool, specifically building upon the Jujutsu integration work started by sunshowers.
This fork is a fork of a fork of spr which was then forked by sunshowers.
This fork continues the sunshowers fork but tries to integrate fully with jujutsu rather than be based fully on git with a few jj parts.
git clone https://github.com/LucioFranco/jj-spr.git
cd jj-spr
cargo install --path sprThis will install the jj-spr binary to your ~/.cargo/bin directory.
To use jj-spr as a Jujutsu subcommand (enabling jj spr <command>), add the following to your Jujutsu configuration:
jj config set --user aliases.spr '["util", "exec", "--", "jj-spr"]'Add this to your Jujutsu config file (~/.jjconfig.toml or .jj/repo/config.toml):
[aliases]
spr = ["util", "exec", "--", "jj-spr"]If you prefer to configure the binary path directly:
[aliases]
spr = ["util", "exec", "--", "/path/to/jj-spr"]After configuration, you can use commands like:
jj spr diff # Create/update a PR for the current change
jj spr diff -r @- # Create/update a PR for a specific change
jj spr land # Land (merge) a PR
jj spr list # List open PRs-
Initialize in your repository:
cd your-jujutsu-repo jj spr init -
Provide your GitHub Personal Access Token when prompted. This allows jj-spr to create and manage pull requests via the GitHub API.
The recommended workflow keeps you on an empty working copy (@) while your PR changes are at @-:
-
Create a change:
jj new main@origin echo "new feature" > feature.txt jj describe -m "Add new feature Test Plan: Tested locally"
-
Move to empty working copy:
jj new # Your PR change is now at @- -
Submit for review:
jj spr diff # Defaults to @-, your PR change -
Make changes and update:
echo "updated feature" > feature.txt jj squash # Squash changes into @- jj spr diff -m "Updated implementation"
-
Land the PR:
jj spr land -r @- # Must specify @- since land defaults to @ -
Rebase after landing:
jj git fetch jj rebase -r @ -d main@origin
Key Concepts:
@= your working copy (where you make edits)@-= parent of working copy (your PR change)jj spr diffdefaults to@-jj spr landdefaults to@
jj-spr excels at handling stacked PRs for related changes:
# Create first change
jj new main@origin
# ... make changes ...
jj describe -m "Foundation change"
# Create dependent change on top
jj new
# ... make changes ...
jj describe -m "Building on foundation"
# Move to empty working copy
jj new
# Create PRs for entire stack
jj spr diff --all # Creates PR #1 and PR #2 (stacked)
# Update just the second change
jj squash --into <change-id-of-second>
jj spr diff -r <change-id-of-second>For more details on stacking, see the documentation.
jj spr diff- Create or update a pull request for the current changejj spr land- Land (squash-merge) an approved pull requestjj spr list- List open pull requests and their statusjj spr close- Close a pull requestjj spr amend- Update local commit message with content from GitHub
Most commands support revision selection:
jj spr diff -r @- # Specific revision
jj spr diff -r main..@ # Range of revisions (like --all)
jj spr diff -a --base trunk # All changes from trunk to currentFor detailed help on any command:
jj spr help <command>jj-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
# Require test plan in commit messages
git config spr.requireTestPlan true- Jujutsu: A working Jujutsu installation with a colocated Git repository
- GitHub Access: A GitHub Personal Access Token with appropriate permissions
- Git Repository: Your Jujutsu repository must be colocated with Git (
jj git init --colocate)
- Change ID Handling: Works with Jujutsu's change IDs instead of Git commit hashes
- Commit Identity Preservation: Uses
jj describeto maintain commit identity when updating messages - Native Jujutsu Commands: Integrates with
jj log,jj commit, and other Jujutsu operations
- Fixed Parent Immutability: Stacked changes no longer make parent commits immutable
- Proper Base Branches: Correctly creates base branches for stacked PRs
- Clean Diffs: GitHub shows only child changes, not cumulative diffs
- Per-Command Revisions:
jj spr diff -r <rev>instead of global revision flags - Range Support:
jj spr diff -r main..@automatically enables multi-commit mode - Better Defaults:
jj spr diffdefaults to@-(parent of working copy - your PR change)jj spr landdefaults to@(working copy)- Works seamlessly with the recommended empty-working-copy workflow
Contributions are welcome! Please:
- Check existing issues before starting work
- Add tests for new functionality
- Follow the existing code style (run
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 --checkThis project is MIT licensed. See LICENSE for details.
- Original spr by the Cord team
- Jujutsu integration foundation by sunshowers
- Jujutsu project by martinvonz and contributors