spr:GitHub上的堆叠拉取请求
摘要
spr 是一个 CLI 工具,可将 Git 分支上的每个提交转换为 GitHub 上的独立拉取请求,无需手动管理分支即可实现堆叠式 PR。
查看缓存全文
缓存时间: 2026/05/18 04:26
ejoffe/spr
来源:https://github.com/ejoffe/spr 徽标 许可证:MIT (https://opensource.org/licenses/MIT) 构建状态 (https://github.com/ejoffe/spr/actions/workflows/ci.yml) 发布页面 (https://GitHub.com/ejoffe/spr/releases/)
每个提交都变成一个拉取请求。别再折腾分支了。
git spr 管理 GitHub 上的堆叠拉取请求,您无需再手动操作。只需在单个分支上编写提交,spr 就会将每个提交转为其自己的拉取请求——保持同步、顺序正确且随时可合并。
终端录屏
为什么要用堆叠 PR?
- 小型 PR 审核更快。 50 行变更能获得有意义的反馈;500 行变更只能得到“看起来不错”。
- 不再有分支体操。 别再创建
feature-part-1、feature-part-2,再在它们之间变基和解决冲突了。 - 增量交付。 今天部署数据库迁移,明天部署 API,后天部署 UI——每个都独立审核和合并。
- 原生 GitHub 体验。 无需额外服务,无需自定义合并机器人。只需拉取请求和分支,spr 为您管理。
快速开始
通过 brew、nix 或下载二进制文件 (https://github.com/ejoffe/spr/releases) 安装:
brew install ejoffe/tap/spr # macOS/Linux
nix profile install github:ejoffe/spr # Nix
然后像普通 git 一样使用——只需把 git push + 手动创建 PR 替换为 git spr update:
git commit -m "添加用户认证"
git commit -m "添加登录页面"
git commit -m "添加会话管理"
git spr update # 创建 3 个按顺序堆叠的拉取请求
git spr status # 显示堆叠状态
git spr merge # 合并所有已就绪的 PR
就是这样。每个提交就是一个 PR。修改一个提交后再次运行 git spr update 即可同步变更。
命令
| 命令 | 别名 | 描述 |
|---|---|---|
git spr update | u, up | 为堆叠中的提交创建并更新拉取请求 |
git spr status | s, st | 显示打开的拉取请求的状态 |
git spr merge | 合并所有可合并的拉取请求 | |
git spr amend | a | 修改堆叠中的一个提交 |
git spr edit | e | 编辑堆叠中的一个提交(交互式变基) |
git spr sync | 将本地堆叠与远程同步 | |
git spr check | 运行合并前检查(由 mergeCheck 配置) | |
git spr version | 显示版本信息 |
全局标志: --detail(显示状态位标题)、--verbose(记录 git 命令和 GitHub API 调用)、--debug、--profile
安装
Brew
brew tap ejoffe/homebrew-tap
brew install ejoffe/tap/spr
Nix
nix profile install github:ejoffe/spr
或者不安装直接运行:
nix run github:ejoffe/spr
Apt
echo "deb [trusted=yes] https://apt.fury.io/inigolabs/ /" | sudo tee /etc/apt/sources.list.d/inigolabs.list
sudo apt update
sudo apt install spr
二进制文件
从发布页面 (https://github.com/ejoffe/spr/releases) 下载预编译的二进制文件。
从源码构建
make bin # 需要 goreleaser;二进制文件输出到 dist/
使用指南
工作流
像平常一样将更改提交到分支。每个提交都会变成一个拉取请求。
git add feature_1.go
git commit -m "功能 1"
git add feature_2.go
git commit -m "功能 2"
git add feature_3.go
git commit -m "功能 3"
git spr update
提交标题成为 PR 标题;提交正文成为 PR 描述。无需创建分支或调用 git push——git spr update 会处理一切。
进行中的工作: 在提交消息前加上 WIP 前缀可跳过该提交的 PR 创建。准备好后移除前缀即可。
更新拉取请求
运行 git spr update 以同步整个堆叠。新提交会获得新 PR;已修改的提交会自动更新现有 PR。
> git spr update
[⌛❌✅❌] 60: 功能 3
[✅✅✅✅] 59: 功能 2
[✅✅✅✅] 58: 功能 1
| 标志 | 别名 | 描述 |
|---|---|---|
--count | -c | 仅更新堆叠底部指定数量的 PR |
--reviewer | -r | 为新建的拉取请求添加审核者 |
--no-rebase | --nr | 禁用变基(也支持 SPR_NOREBASE 环境变量) |
修改提交
暂存更改,然后使用 git spr amend 选择要修改的提交:
> git add feature_2.go
> git spr amend
3 : 5cba235d : 功能 3
2 : 4dc2c5b2 : 功能 2
1 : 9d1b8193 : 功能 1
要修改的提交 [1-3]: 2
使用 --update(-u)可在修改后自动运行 git spr update。
编辑提交
使用 git spr edit 在特定提交上启动交互式变基会话:
> git spr edit
3 : 5cba235d : 功能 3
2 : 4dc2c5b2 : 功能 2
1 : 9d1b8193 : 功能 1
要编辑的提交 [1-3]: 2
完成后使用 git spr edit --done(添加 -u 也会更新)。取消使用 git spr edit --abort。
同步
使用 git spr sync 将远程更改拉取到本地堆叠。在 PR 在 GitHub 上被合并或更新后很有用。
合并
使用 git spr merge 代替 GitHub UI 以按正确顺序合并:
> git spr merge
MERGED #58 功能 1
MERGED #59 功能 2
MERGED #60 功能 3
[✅❌✅✅] 61: 功能 4
spr 会找到堆叠中最顶部的可合并 PR,将该 PR 之前的所有提交整合到一个 PR 中,合并它,并关闭中间的 PR。这避免了触发多余的 CI 运行。
使用 --count N 仅合并底部 N 个拉取请求。
合并状态位
每个 PR 显示四个状态位:
[✅❌✅✅] 61: 功能 4
│ │ │ └─ 堆叠:下方所有 PR 均已就绪
│ │ └──── 冲突:无合并冲突
│ └─────── 审批:PR 已获批
└────────── 检查:CI 检查通过
| 位 | ⌛ | ❌ | ✅ | ➖ |
|---|---|---|---|---|
| 检查 | 待定 | 失败 | 通过 | 不必须 |
| 审批 | – | 未获批 | 已获批 | 不必须 |
| 冲突 | – | 有冲突 | 无冲突 | – |
| 堆叠 | – | 下方被阻塞 | 全部畅通 | – |
通过 .spr.yml 中的 requireChecks、requiredChecks 和 requireApproval 配置检查和审批要求。当 requiredChecks 列出了特定的检查名称时,仅评估这些检查——忽略所有其他检查。当可选检查(如 linter、部署预览)会导致状态显示为失败时,此功能很有用。
开始新堆叠
从最新的推送状态创建新分支:
git checkout -b new_stack @{push}
配置
配置在首次运行时自动创建。仓库配置位于仓库根目录的 .spr.yml;用户配置位于 ~/.spr.yml。
仓库配置 (.spr.yml)
| 设置 | 类型 | 默认值 | 描述 |
|---|---|---|---|
requireChecks | bool | true | 要求检查通过才能合并 |
requiredChecks | list | 必须通过的检查名称列表。设置后仅评估这些检查,其他忽略 | |
requireApproval | bool | true | 要求 PR 获批才能合并 |
githubRepoOwner | str | GitHub 所有者(从 git 远程自动检测) | |
githubRepoName | str | GitHub 仓库名称(从 git 远程自动检测) | |
githubRemote | str | origin | 使用的 git 远程名称 |
githubBranch | str | main | 拉取请求的目标分支 |
githubHost | str | github.com | GitHub 主机(用于 GitHub Enterprise 时更新) |
mergeMethod | str | rebase | 合并方法:rebase、squash 或 merge |
mergeQueue | bool | false | 使用 GitHub 合并队列 |
prTemplateType | str | stack | PR 模板:stack、basic、why_what 或 custom |
prTemplatePath | str | 自定义 PR 模板文件路径(自动将类型设为 custom) | |
prTemplateInsertStart | str | 自定义模板中用于插入提交正文的起始标记 | |
prTemplateInsertEnd | str | 自定义模板中用于插入提交正文的结束标记 | |
mergeCheck | str | 在 git spr check 时运行的命令(合并前) | |
forceFetchTags | bool | false | 在 git spr update 时获取标签 |
showPrTitlesInStack | bool | false | 在 PR 正文的堆叠描述中显示 PR 标题 |
branchPushIndividually | bool | false | 逐个推送分支而不是原子推送 |
defaultReviewers | list | 每个新拉取请求要添加的审核者 |
.spr.yml 示例:
requireChecks: true
requiredChecks:
- "ci/test"
- "ci/build"
requireApproval: true
mergeMethod: squash
defaultReviewers:
- 队友
用户配置 (~/.spr.yml)
| 设置 | 类型 | 默认值 | 描述 |
|---|---|---|---|
showPRLink | bool | true | 显示完整拉取请求 URL |
shortPRLink | bool | false | 显示可点击的 PR- 而非完整 URL |
showCommitID | bool | false | 显示提交哈希的前 8 个字符 |
logGitCommands | bool | false | 将 git 命令记录到标准输出 |
logGitHubCalls | bool | false | 将 GitHub API 调用记录到标准输出 |
statusBitsHeader | bool | true | 显示状态位类型标题 |
statusBitsEmojis | bool | true | 使用表情符号状态位 |
createDraftPRs | bool | false | 将新 PR 创建为草稿 |
preserveTitleAndBody | bool | false | 更新时不要覆盖 PR 标题和正文 |
noRebase | bool | false | 在 git spr update 时跳过变基 |
deleteMergedBranches | bool | false | PR 合并后删除分支 |
branchPrefix | str | spr | spr 管理分支名称的前缀 |
对比
spr 与 Graphite (https://graphite.dev)、ghstack (https://github.com/ezyang/ghstack) 和 Gerrit (https://www.gerritcodereview.com/) 的堆叠审查模型类似——但它纯粹基于 GitHub 的原生拉取请求。无需额外服务、无需自定义合并机器人、无锁定。
贡献
发现 bug?请在 issue 中提出。(https://github.com/ejoffe/spr/issues)
欢迎拉取请求。如果您觉得 spr 有用,点个星标可以帮助其他人发现它。
许可证
相似文章
Show HN: Haystack – 审查需要人工关注的PR
Haystack 是一个新工具,它用队列取代了 GitHub 的 PR 审查系统,将拉取请求分类为可安全合并、需要修复或需要人工审查三个类别,帮助团队应对来自编码代理的 PR 激增。
在$dayjob审查所谓的Pull Requests
一位开发者描述了他使用git命令(如range-diff和log -p)来审查pull requests的工作流程,以规避基于Web的UI的缺陷。
@ycombinator: Stage 是一个专为帮助工程师理解 AI 生成代码而设计的代码审查平台。你的团队正被海量的代码审查请求淹没……
Stage 是一个代码审查平台,它通过将变更分组为逻辑章节,帮助工程师更快地审查 AI 生成的拉取请求,旨在减少拉取请求的积压。
[P] 我构建了一个系统,让你可以对任何GitHub仓库提问,并获得基于实际源代码的答案 [P]
GitRAG 是一个工具,允许用户粘贴任何公开的 GitHub URL,并询问关于代码库的问题,返回基于源代码的答案,带有精确的文件路径和行号,使用了AST感知的切分、混合搜索(稠密检索 + BM25)、重新排序以及用于生成的语言模型。
Haystack
Haystack 是一个工具,帮助开发者审查拉取请求,通过过滤掉那些不需要人工关注的请求,从而简化代码审查流程。