CLI tool
spacedentist/spr avatar
spacedentist/spr

spr turns local commits into stacked GitHub pull requests

Submit pull requests for individual, amendable, rebaseable commits to GitHub

541 stars56 forksRustMIT

At a glance

What is it?
spr is a Rust command line tool for submitting and updating GitHub pull requests from local commits that may still be amended and rebased, and it stacks pull requests so a series of interdependent changes can be reviewed one after another. It suits teams reviewing large multi-commit work, and it replaces the push-to-a-fork-and-open-a-PR habit with something closer to a local workflow.
Who is it for?
Adopt spr if your review process involves series of interdependent commits that are amended and rebased while review is in progress, since spr maps each commit to its own pull request and updates it in place. Do not adopt it for a single-commit change, where gh pr create is faster to learn, and do not stay on 1.x expecting 2.0 behaviour, because the commit message fields became Git trailers, the Summary and Test Plan sections are gone, and spr no longer runs git at all.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The workflow spr replaces: fork, branch, pull request, rebase

spr describes itself as a command line tool for submitting and updating GitHub Pull Requests from local Git commits that may be amended and rebased, and it adds stacking so a series of code reviews of interdependent code is possible.

The problem it addresses is the standard pull request rhythm. You have three commits on a branch, two of which depend on the first. With plain git, that means either one pull request containing all three, which cannot be reviewed piecemeal, or three branches and three pull requests that must be kept in sync by hand every time the first commit is amended. Amend a commit at the bottom of the stack and the branches above it need rebasing, the pull requests need retargeting, and the reviewer is looking at a diff that no longer matches what they approved.

spr's answer is to keep the stack local. The commits stay on your branch, in order, exactly as you would write them, and spr opens one pull request per commit and keeps each one pointed at the commit below it.

The name is pronounced like the English word super, which the README notes, and the tool is written in Rust with a version of 2.0.0-beta.2 in the manifest and an MIT licence.

The three commands that cover the whole loop

The quickstart section of the README describes the loop in a handful of commands, and it is short enough to be the entire learning curve.

You run spr init inside a local checkout of a GitHub-backed git repository, and you are guided through authorising spr to use the GitHub API so it can create and merge pull requests. Then spr diff submits the current commit for review as a pull request.

If you want to make changes to the pull request, you amend your local commit, and/or rebase it, and call spr diff again. When spr updates an existing pull request it asks you for a short message describing the update, which becomes the note on the review thread rather than a new commit in the history.

For a branch with several commits, spr diff --all creates or updates a pull request for each of them, stacked on top of each other. And to land an approved pull request, spr land does it, squashing by default, with the merge method and stacking mode configurable.

The help system follows the same shape. spr help lists the commands and options, and spr help with a command name, for example spr help diff, covers a specific one.

What is interesting here is that spr diff is the pivot. Amending and rebasing are ordinary git operations that you already do, and spr re-reads the local history each time you call it, so the pull requests follow the commits rather than the other way around.

What changed in spr 2.0, and why the migration is not trivial

spr 2.0 is available as a pre-release, and the README lists the changes that may affect you coming from 1.x. They are worth reading before you upgrade rather than after.

The commit message fields are Git trailers now. Git treats Key: value lines in the last paragraph of a commit message as trailers, like Signed-off-by:, and tools can read them, for example with git log --format='%(trailers)'. spr 1.x wrote Pull Request:, Reviewers: and Reviewed By: fields, which were not trailers because keys cannot contain spaces. spr 2.0 writes Pull-request:, Reviewers: and Reviewed-by:, still recognises the old fields, and converts them the next time it updates a commit message.

The Summary and Test Plan sections are gone. The body of the commit message is the pull request description, as it is, and the option spr.requireTestPlan no longer exists. If your team relied on the test plan as a checklist reviewers ticked, that template now lives wherever you keep your own templates.

spr does not run git anymore. It fetches and pushes directly to the repository's HTTPS URL with its GitHub token, and pushing via SSH, for example with pushInsteadOf, still works. The option spr.githubRemoteName is gone. This is the change with the widest blast radius, because any tooling that inspected spr's git invocations, or that relied on local git credentials being picked up, has to be revisited.

The configuration options were renamed. The table maps spr.githubRepository and spr.githubMasterBranch onto spr.target, for example github:owner/repo:main, spr.githubAuthToken onto spr.auth.github.token with a host-specific variant for GitHub Enterprise, and the command line flags --github-repository and --github-master-branch onto --target, with --github-auth-token becoming --auth-token. spr still reads the old names for now and shows a note on how to replace them, and spr init replaces them in the repository's configuration.

Installing spr, and how to get a pre-release

There are several installation routes, and the README is explicit about which one gets you which version.

Homebrew is the shortest:

bash
brew install spr

Nix is available in nixpkgs:

bash
nix run nixpkgs#spr

And for the latest development version, the README points at the flake in the repository:

bash
nix run github:spacedentist/spr

If you have Cargo, the Rust build tool, spr installs from crates.io:

bash
cargo install spr

The pre-release rule is the part to note. Pre-releases are on GitHub and crates.io, while Homebrew, nixpkgs and a plain cargo install spr stay with the latest stable release. To install a pre-release you give its version, for example 2.0.0-beta.1:

bash
cargo install spr --version 2.0.0-beta.1
nix run github:spacedentist/spr/v2.0.0-beta.1

So a team that wants the 2.0 behaviour today has to install from crates.io with an explicit version or run the flake, while everyone on the package managers stays on the 1.x line until a stable 2.0 ships.

Building from source has its own prerequisites, which are listed separately: Rust 1.91 or newer, a C compiler, pkg-config, and the OpenSSL development files, with libssl-dev on Debian and Ubuntu, openssl-devel on Fedora, and openssl from Homebrew on macOS. libgit2 and libssh2 are built from source as part of the build unless matching versions are already installed on your system. Clone the repository and run cargo build --release, and the binary ends up in target/release. The tests run with cargo test.

How the repository is put together, and what the tests cover

The repository layout reflects a project that has been through a 1.x and a 2.x, and the Cargo manifest says more about it than the file list does.

The workspace has two members, the root package and livetest/. The comment explains why: the live tests are a separate crate so that building, packaging and installing spr does not involve them, and plain cargo build and cargo test only build spr itself, while --workspace covers everything. That is a deliberate separation, and it is a good sign for release tooling, since the live tests are the part that needs real credentials and network access.

The dependency list is where the architecture shows. git2 with the https and ssh features, plus git2-ext for the bits libgit2 does not expose, covers repository access. octocrab with the opentls, default-client, tokio and jwt-rust-crypto features is the GitHub client, and graphql_client sits alongside it, which indicates the API is not purely REST. secrecy wraps the token handling so it is not accidentally logged, console and dialoguer provide the interactive prompts, and textwrap handles the terminal layout. open is there for opening a pull request in a browser.

The vendored feature is worth noting for anyone producing release binaries:

toml
vendored = ["git2/vendored-libgit2", "git2/vendored-openssl"]

That builds OpenSSL and libgit2 from source and links them statically, instead of using the system's, which the comment ties to self-contained release binaries.

The rest of the tree is documentation and process. There is a docs/ directory served by mdBook, a book.toml, a CHANGELOG.md, a release_checklist.md, a CodingGuidelines.md, an AGENTS.md, a .pre-commit-config.yaml, a flake.nix and shell.nix for the Nix side, and a rustfmt.toml. The CI checks described in the README are cargo fmt --all --check, cargo clippy --workspace --all-targets --all-features with no warnings allowed, and cargo test --workspace.

Where spr is the wrong tool, and what the alternative approach costs

There are clear cases where spr is the wrong choice, and one comparison worth drawing.

If your change is a single commit, spr is overhead. The whole point is a stack, and a stack of one is a pull request you could open with gh pr create in less time than it takes to learn the commands and the configuration.

If your team does not amend and rebase during review, the value drops sharply. spr's advantage appears when the bottom of a stack changes after the top has been reviewed, and if that never happens then the ordinary pull request workflow already works.

There is also a constraint the README states plainly: spr talks to GitHub. The quickstart says to run spr init inside a local checkout of a GitHub-backed git repository, the authorisation step is for the GitHub API, and the GraphQL client in the dependency list points the same way. This is not a general git-to-forge tool, and a team on a different forge is not served by it.

The alternative approaches differ in kind rather than degree. The GitHub CLI opens pull requests from an existing branch, so it leaves the branch in your remote and asks you to manage it. The stacked pull request tools built on top of git, such as those built around the stacked-diff concept that the repository topics list, push each commit to its own branch in the remote and rebase those branches when the stack changes. spr keeps the stack local and lets GitHub's own pull request mechanism carry the dependency: each pull request targets the branch of the commit below it, and the local history stays the single source of truth.

That difference is what makes spr's approach interesting for review-heavy workflows, and also what makes it demanding. The cost is that your local commits become the thing reviewers see, so the discipline of writing good commit messages and keeping the stack clean moves onto you rather than onto a tool.

Editorial conclusion

Adopt spr if your review process involves series of interdependent commits that are amended and rebased while review is in progress, since spr maps each commit to its own pull request and updates it in place. Do not adopt it for a single-commit change, where gh pr create is faster to learn, and do not stay on 1.x expecting 2.0 behaviour, because the commit message fields became Git trailers, the Summary and Test Plan sections are gone, and spr no longer runs git at all. Before you upgrade, read the CHANGELOG.md and the migration notes, because spr init rewrites the old configuration option names in the repository, and check that you have Rust 1.91 or newer since building the 2.0 line needs it. The licence is MIT, the latest release is v2.0.0-beta.1 from 2026-10-12, and the last push was on 2026-10-17.

Frequently asked questions

What is spr and what problem does it solve?

spr is a command line tool for submitting and updating GitHub pull requests from local Git commits that may be amended and rebased. Pull requests can be stacked, which allows a series of code reviews of interdependent code instead of one large diff.

How do I install spr?

You can use brew install spr, nix run nixpkgs#spr, the flake in the repository with nix run github:spacedentist/spr, or cargo install spr. Homebrew, nixpkgs and a plain cargo install stay with the latest stable release, so a pre-release needs an explicit version such as cargo install spr --version 2.0.0-beta.1.

How do I submit a pull request with spr?

Run spr init once inside a local checkout of a GitHub-backed git repository to authorise the tool, then run spr diff to submit the current commit as a pull request. On a branch with several commits, spr diff --all creates or updates one pull request per commit, stacked on top of each other.

What changed between spr 1.x and spr 2.0?

The commit message fields became Git trailers, so spr 2.0 writes Pull-request:, Reviewers: and Reviewed-by: instead of the old Pull Request:, Reviewers: and Reviewed By: fields, the Summary and Test Plan sections and the spr.requireTestPlan option are gone, spr no longer runs git and talks to the repository's HTTPS URL directly, and the configuration options were renamed to spr.target, spr.auth.github.token and the --target and --auth-token flags.

How do I update an existing pull request with spr?

Amend your local commit, and/or rebase it, and call spr diff again. When spr updates an existing pull request it asks you for a short message describing the update. To land an approved pull request, run spr land, which squash-merges by default.

What do I need to build spr from source?

Rust 1.91 or newer, a C compiler, pkg-config and the OpenSSL development files, with libssl-dev on Debian and Ubuntu, openssl-devel on Fedora, or openssl from Homebrew on macOS. Then clone the repository and run cargo build --release, and run the tests with cargo test.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. spacedentist/spr on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/spacedentist-spr.svg)](https://hysenlabs.com/projects/spacedentist-spr)

Was this useful?