Rust CLI for GitHub PR and GitLab MR patch streams

Patchsplit

Download a GitHub Pull Request or GitLab merge request as one patch per commit, export its net changes as a single diff with --squash, or fetch one commit by hash with --commit. Review, share, or apply changes without cloning the source repository.

$ 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.0latest release
1 PR / MRinput
N / 1patch files
curlruntime dependency

Patchsplit

Built for patch-level review work

The tool keeps the workflow explicit: fetch the PR or MR patch stream, split by commit boundaries, and write predictable files without surprise overwrites.

01

GitHub and GitLab

Fetch GitHub pull requests and commits, or pass --gitlab to download merge requests and commits from gitlab.com, including projects nested under subgroups.

02

Three patch modes

Keep one patch per commit, use --squash to export net PR changes as pr-<pr-number>.patch, or pass --commit <hash> to download a single commit.

03

Predictable filenames

Each file starts with a four-digit index and a sanitized commit subject, such as 0001-add-parser.patch.

04

No accidental overwrite

Existing output files are protected by default. Add --force only when replacing them is intentional.

05

Small dependency surface

System curl handles downloads; thiserror 2 provides Rust error types. Rust and Cargo are needed only for source builds, and Git is used to apply patches and run Unix tests.

i18n

Localized CLI output

User-facing CLI text now runs through a PO-based i18n layer. Chinese translations are built in, and external UTF-8 .po catalogs can be loaded at runtime.

Locale selection

Patchsplit checks PATCHSPLIT_LANGUAGE, LANGUAGE, LC_ALL, LC_MESSAGES, then LANG, using the first matching locale.

Catalog locations

Set PATCHSPLIT_LOCALEDIR or place .po catalogs next to the executable in locale/, po/, or ../share/locale.

Template refresh

Run scripts/update-pot.sh to regenerate po/patchsplit.pot from the files listed in po/POTFILES.in.

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

Flow

From PR to patch set

01

Point at a Pull Request

Patchsplit builds the GitHub or GitLab .patch URL from the repository and PR/MR number.

02

Download the patch stream

curl follows redirects, fails on HTTP errors, and identifies itself with the patchsplit version.

03

Split by commit

Mail-style From markers define commit boundaries. A raw single patch is kept as one file.

04

Write portable files

Output lands in patches/ by default, or in the directory supplied with --out.

CLI

Usage

GitHub and GitLab commands share the same flags: per-commit output by default, --squash for the net diff, and --commit for a single commit. Apply patches inside the target repository checked out at a compatible base.

Repository shorthand

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

Separate owner and repo

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

Single 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

Per-commit patches

Numbered mail patches retain commit messages and authorship. Apply them with git am from inside the target repository.

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

One combined diff

The aggregate .diff contains net changes from merge base to head. Repeated edits merge and reverted changes disappear. GitHub writes pr-<pr-number>.patch and GitLab writes mr-<number>.patch; neither has commit messages or authorship and both are applied with 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

Single commit patch

Pass --commit <hash> with a short or full commit hash instead of a PR number. The mail-formatted patch is saved verbatim as <hash>.patch, keeping its commit message and authorship. It cannot be combined with --squash.

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

GitLab merge request

Pass --gitlab to fetch a merge request from gitlab.com and split it into numbered mail patches, keeping commit messages and authorship. Project paths may include subgroups. Apply with git am.

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

An empty net diff is an error and writes no file. Binary content is limited to what the platform includes in its diff. Combined output is not a git am mailbox.

Options

-o, --out <dir>
Output directory for split patch files. Defaults to patches/.
-f, --force
Overwrite existing patch files.
-h, --help
Show help.
-s, --squash
Write the request's net diff as one patch for git apply.
--gitlab
Download a merge request or commit from gitlab.com.
--commit <hash>
Download one commit's .patch by short or full hash. Cannot be combined with --squash.
-V, --version
Show version.

Packages

Install Patchsplit

Install from the Ubuntu PPA, a distribution package, a prebuilt archive, or source. curl must be available in PATH for the CLI.

Linux

Download for 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

Download for 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: this release provides an Ubuntu 26.04 build. Check compatibility with your distribution; apt resolves the declared curl dependency.

Fedora

Download for 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: this artifact targets Fedora 44. Use a compatible system and choose the main package, excluding debuginfo and debugsource.

macOS

Download for 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

If macOS blocks a binary you have verified and trust, remove its quarantine attribute: xattr -d com.apple.quarantine /usr/local/bin/patchsplit

Windows

Download for Windows (x86_64)
Expand-Archive .\patchsplit-windows-x86_64.zip -DestinationPath .\patchsplit
.\patchsplit\patchsplit.exe --version

Add the extracted directory to your user Path for global use. curl.exe must also be in Path.

Ubuntu (PPA)

Add the project PPA, refresh the package index, and install Patchsplit:

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

From source

Install Rust, Cargo, and Git; system curl is required to run the CLI. Ensure the Cargo binary directory (usually ~/.cargo/bin) is in PATH:

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

Arch Linux (AUR)

The community-maintained patchsplit-bin package is maintained by lingbopro. Install with either AUR helper:

paru -S patchsplit-binyay -S patchsplit-bin
View AUR package

Automation

Release flow

Push a v* tag, or run the Release workflow manually with a ref and release tag. A missing tag points to the workflow commit. Review and publish the draft containing x86_64 archives and distribution packages. Publishing triggers Notify PPA to sign and upload a source package to Launchpad for building.

Release artifacts

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

Keep Pull Request patches small enough to inspect.

Open the repository