面向 GitHub PR 與 GitLab MR patch 串流的 Rust CLI

Patchsplit

逐 commit 下載 GitHub Pull Request 或 GitLab merge request 的 patch,透過 --squash 匯出最終變更的一份 diff,或用 --commit 按雜湊取得單個 commit。無需複製來源倉庫,即可審閱、分享或套用變更。

$ patchsplit openai codex 42 -o pr-42-patches
downloaded https://github.com/openai/codex/pull/42.patch
wrote 2 patch file(s)
pr-42-patches/0001-add-parser.patch
pr-42-patches/0002-wire-cli.patch
v1.3.0最新版本
1 個 PR/MR輸入
N / 1patch 檔案數
curl執行期依賴

Patchsplit

為 patch 級 review 工作流而寫

它把流程保持得很明確:拉取 PR 或 MR 的 patch,依 commit 邊界拆分,並寫出可預測且不會意外覆蓋的檔案。

01

GitHub 與 GitLab 雙平台

下載 GitHub pull request 和 commit,或透過 --gitlab 從 gitlab.com 下載 merge request 和 commit,支援含子群組的專案路徑。

02

三種補丁模式

逐 commit 保留 patch,用 --squash 將 PR 的最終變更匯出為 pr-<pr-number>.patch,或透過 --commit <hash> 下載單個 commit。

03

可預測檔名

每個檔案使用四位序號加清理後的 commit subject,例如 0001-add-parser.patch。

04

預設拒絕覆蓋

已存在的輸出檔案預設會被保護。只有明確傳入 --force 時才會替換。

05

克制的依賴面

系統 curl 負責下載,thiserror 2 提供 Rust 錯誤型別。原始碼建構需要 Rust 和 Cargo;套用 patch 和執行 Unix 測試需要 Git。

i18n

CLI 輸出本地化

使用者可見的 CLI 文字現在透過基於 PO 的 i18n 層處理。簡體中文翻譯已內建,也可以在執行期載入外部 UTF-8 .po catalog。

Locale 選擇

Patchsplit 會依序檢查 PATCHSPLIT_LANGUAGE、LANGUAGE、LC_ALL、LC_MESSAGES、LANG,並使用第一個符合的 locale。

Catalog 位置

可以設定 PATCHSPLIT_LOCALEDIR,也可以把 .po catalog 放在可執行檔旁邊的 locale/、po/ 或 ../share/locale。

刷新模板

執行 scripts/update-pot.sh,可從 po/POTFILES.in 列出的源碼檔案重新產生 po/patchsplit.pot。

PATCHSPLIT_LANGUAGE=zh_CN patchsplit openai codex 42
scripts/update-pot.sh

Flow

從 PR 到 patch 集

01

指向 Pull Request

Patchsplit 根據倉庫和 PR/MR 編號拼出 GitHub 或 GitLab 的 .patch URL。

02

下載 patch 串流

curl 會跟隨跳轉、在 HTTP 錯誤時失敗,並帶上 patchsplit 版本作為 user agent。

03

依 commit 拆分

mail patch 中的 From 標記定義 commit 邊界;原始單 patch 會保留為一個檔案。

04

寫出可移植檔案

預設輸出到 patches/,也可以透過 --out 指定目錄。

CLI

用法

GitHub 與 GitLab 命令共享相同的參數:預設逐 commit 輸出,--squash 匯出最終 diff,--commit 下載單個 commit。套用 patch 時,請在目標倉庫中切換至相容的基線。

倉庫簡寫

patchsplit <owner/repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit rust-lang/rust 12345

拆開 owner 和 repo

patchsplit <owner> <repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit openai codex 42 -o pr-42-patches

單個 commit

patchsplit <owner/repo> --commit <hash> [--out <dir>] [--force]
patchsplit zitzhen/patchsplit --commit b430113
patchsplit zitzhen patchsplit -commit b430113

GitLab merge request

patchsplit --gitlab <namespace/project> <mr-number> [--out <dir>] [--force] [--squash]
patchsplit --gitlab zitzhen/patchsplit 1
patchsplit --gitlab group/subgroup/project 1 --squash -o mr-1-patches

逐 commit 的 patch

帶序號的郵件格式 patch 保留提交訊息與作者身分。在目標倉庫內使用 git am 套用。

patchsplit openai/codex 42 -o pr-42-patches
git am /path/to/pr-42-patches/*.patch

一份合併 diff

下載從 merge base 到 head 的最終 .diff,合併重複修改,消除已撤銷的變更。GitHub 輸出 pr-<pr-number>.patch,GitLab 輸出 mr-<number>.patch,均不含提交訊息和作者身分,使用 git apply 套用。

patchsplit openai/codex 42 --squash -o pr-42-patches
patchsplit --gitlab zitzhen/patchsplit 1 --squash -o mr-1-patches
git apply --check /path/to/pr-42-patches/pr-42.patch
git apply /path/to/pr-42-patches/pr-42.patch

單個 commit 的補丁

不傳 PR 編號,改用 --commit <hash> 傳入短雜湊或完整雜湊。該 commit 的郵件格式補丁會原樣儲存為 <hash>.patch,保留提交訊息與作者身分,且不能與 --squash 同時使用。

patchsplit zitzhen/patchsplit --commit b430113 -o commit-patches
git am /path/to/commit-patches/b430113.patch

GitLab merge request

透過 --gitlab 從 gitlab.com 取得 merge request 並拆分為帶序號的郵件格式 patch,保留提交訊息與作者身分,專案路徑可包含子群組。使用 git am 套用。

patchsplit --gitlab zitzhen/patchsplit 1 -o mr-1-patches
git am /path/to/mr-1-patches/*.patch

最終 diff 為空時會報錯且不寫入檔案。二進位內容受限於平台 diff 提供的資料。合併輸出不是可供 git am 使用的郵件格式。

參數

-o, --out <dir>
指定拆分後 patch 檔案的輸出目錄,預設是 patches/。
-f, --force
允許覆蓋已存在的 patch 檔案。
-h, --help
顯示說明。
-s, --squash
將 Pull Request 的最終 diff 寫成一個 patch,配合 git apply 使用。
--gitlab
從 gitlab.com 下載 merge request 或單個 commit。
--commit <hash>
下載單個 commit 的 .patch,接受短雜湊或完整雜湊,不能與 --squash 同時使用。
-V, --version
顯示版本。

Packages

安裝 Patchsplit

可以透過 Ubuntu PPA、發行版套件、預建封存檔或原始碼安裝。執行時需確保 PATH 中有 curl。

Linux

下載 Linux (x86_64)
tar -xzf patchsplit-linux-x86_64.tar.gz
chmod +x patchsplit
sudo install -m 755 patchsplit /usr/local/bin/patchsplit
patchsplit --version

Debian

下載 Debian (x86_64)
curl -fLO https://github.com/zitzhen/patchsplit/releases/download/v1.3.0/patchsplit_1.3.0-1.ubuntu26.04.1_amd64.deb
sudo apt install ./patchsplit_1.3.0-1.ubuntu26.04.1_amd64.deb
patchsplit --version

Debian / Ubuntu:本次附件是 Ubuntu 26.04 建構,請確認與發行版相容。apt 會處理宣告的 curl 依賴。

Fedora

下載 Fedora (x86_64)
curl -fLO https://github.com/zitzhen/patchsplit/releases/download/v1.3.0/patchsplit-1.3.0-1.fc44.x86_64.rpm
sudo dnf install ./patchsplit-1.3.0-1.fc44.x86_64.rpm
patchsplit --version

Fedora / RHEL:本次附件面向 Fedora 44,請在相容系統上使用。選擇主套件,不要選擇 debuginfo 或 debugsource。

macOS

下載 macOS (x86_64)
tar -xzf patchsplit-macos-x86_64.tar.gz
chmod +x patchsplit
sudo install -m 755 patchsplit /usr/local/bin/patchsplit
patchsplit --version

如果 macOS 阻止已驗證且可信的二進位檔,可移除隔離屬性:xattr -d com.apple.quarantine /usr/local/bin/patchsplit

Windows

下載 Windows (x86_64)
Expand-Archive .\patchsplit-windows-x86_64.zip -DestinationPath .\patchsplit
.\patchsplit\patchsplit.exe --version

將解壓縮目錄加入使用者 Path 後可全域使用。還需確保 curl.exe 位於 Path 中。

Ubuntu(PPA)

加入專案 PPA,更新套件索引,然後安裝 Patchsplit:

sudo add-apt-repository ppa:zitzhen/patchsplit
sudo apt update
sudo apt install patchsplit

從原始碼安裝

準備 Rust、Cargo 和 Git;執行 CLI 需要系統 curl。請確保 Cargo 二進位目錄(通常為 ~/.cargo/bin)位於 PATH:

git clone https://github.com/zitzhen/patchsplit.git
cd patchsplit
cargo install --path . --locked
patchsplit --version

Arch Linux(AUR)

patchsplit-bin 是由 lingbopro 維護的社群套件,可選擇以下任一 AUR 助手安裝:

paru -S patchsplit-binyay -S patchsplit-bin
查看 AUR 套件

Automation

發版流程

推送 v* tag,或手動執行 Release workflow 並指定 ref 和發布 tag。不存在的 tag 指向 workflow 的 commit。檢查包含 x86_64 封存檔和發行版套件的草稿後發布;發布會觸發 Notify PPA,對原始碼套件簽章並上傳至 Launchpad 建構。

發布產物

git tag v1.x.x
git push origin v1.x.x

讓 Pull Request patch 小到可以逐個檢查。

開啟專案倉庫