Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

Language: English | [Simplified Chinese](README_zh-cn.md)

Download GitHub pull requests or individual commits as patches, one file per
commit or one combined diff.
Download GitHub pull requests, GitLab merge requests, or individual commits as
patches, one file per commit or one combined diff.

`patchsplit` is a command-line tool written in Rust. It fetches patches directly
from GitHub without cloning the repository, making it useful for reviewing,
sharing, and applying changes locally.
from GitHub or GitLab without cloning the repository, making it useful for
reviewing, sharing, and applying changes locally.

- **Per-commit patches:** Keep the original patch content, commit messages, and
authorship, with numbered filenames in commit order.
- **Single commit:** Use `--commit <hash>` to download one commit's `.patch`
with either a short or full hash.
- **Combined diff:** Use `--squash` to export the PR's net changes as a single patch.
- **GitLab support:** Pass `--gitlab` to fetch merge requests and commits from
gitlab.com, including projects nested under subgroups.
- **Combined diff:** Use `--squash` to export the request's net changes as a single patch.
- **Predictable output:** Choose an output directory; existing files are only
overwritten when you pass `--force`.
- **Localized CLI:** English and built-in Simplified Chinese messages.
Expand Down Expand Up @@ -142,6 +144,8 @@ patchsplit <owner/repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit <owner> <repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit <owner/repo> --commit <hash> [--out <dir>] [--force]
patchsplit <owner> <repo> --commit <hash> [--out <dir>] [--force]
patchsplit --gitlab <namespace/project> <mr-number> [--out <dir>] [--force] [--squash]
patchsplit --gitlab <namespace/project> --commit <hash> [--out <dir>] [--force]
```

### Split a pull request by commit
Expand Down Expand Up @@ -193,9 +197,12 @@ git apply /path/to/pr-42-patches/pr-42.patch

| Mode | Output | Commit messages and authorship | Apply with |
| --- | --- | --- | --- |
| Default | One numbered patch per commit | Preserved | `git am` |
| `--squash` | One `pr-<pr-number>.patch` | Not included | `git apply` |
| `--commit <hash>` | One `<hash>.patch` | Preserved | `git am` |
| Default (GitHub PR) | One numbered patch per commit | Preserved | `git am` |
| `--squash` (GitHub PR) | One `pr-<pr-number>.patch` | Not included | `git apply` |
| `--commit <hash>` (GitHub) | One `<hash>.patch` | Preserved | `git am` |
| `--gitlab` (GitLab MR) | One numbered patch per commit | Preserved | `git am` |
| `--gitlab --squash` | One `mr-<mr-number>.patch` | Not included | `git apply` |
| `--gitlab --commit <hash>` | One `<hash>.patch` | Preserved | `git am` |

The combined output is a raw diff, not a `git am` mailbox. An empty net diff
is reported as an error and no file is written. Binary changes are limited to
Expand All @@ -216,13 +223,35 @@ the commit's mail-formatted patch verbatim to `<hash>.patch` in the output
directory, for example `patches/b430113.patch`. Apply it with `git am` just
like a per-commit PR patch. `--commit` cannot be combined with `--squash`.

### Download from GitLab

Pass `--gitlab` to download a GitLab merge request or commit from gitlab.com.
The project path uses `namespace/project` form and may contain subgroups, for
example `group/subgroup/project`:

```sh
patchsplit --gitlab zitzhen/patchsplit 1
patchsplit --gitlab zitzhen/patchsplit --commit fafbad69af7507f41e786aa6685b2fa29716c85f
patchsplit --gitlab group/subgroup/project 1 --squash -o mr-1-patches
```

A merge request is fetched from
`https://gitlab.com/<namespace>/<project>/-/merge_requests/<number>.patch` and,
just like a GitHub PR, split into one mail-formatted patch per commit. With
`--squash`, the request's `.diff` net change is written to
`mr-<number>.patch`. A `--commit` download fetches
`https://gitlab.com/<namespace>/<project>/-/commit/<hash>.patch` and writes the
verbatim patch to `<hash>.patch`. The same `--out`, `--force`, and `--squash`
rules apply, and `--commit` cannot be combined with `--squash`.

### Options

| Option | Description |
| --- | --- |
| `-o, --out <dir>` | Output directory (default: `patches/`). |
| `-f, --force` | Overwrite existing patch files. |
| `-s, --squash` | Write the PR's net diff as one patch. |
| `-s, --squash` | Write the request's net diff as one patch. |
| `--gitlab` | Download a merge request or commit from gitlab.com. |
| `--commit <hash>` | Download one commit's `.patch`; accepts a short or full hash. |
| `-h, --help` | Show help. |
| `-V, --version` | Show version. |
Expand Down
30 changes: 27 additions & 3 deletions README_zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

语言:[English](README.md) | 简体中文

`patchsplit` 是一个 Rust CLI,用来从 GitHub 下载 Pull Request 或单个 commit 的
`.patch` 文件,PR 补丁可按 commit 拆分成多个独立 patch 文件。
`patchsplit` 是一个 Rust CLI,用来从 GitHub 下载 Pull Request、或从 GitLab
下载合并请求(Merge Request)及单个 commit 的 `.patch` 文件,PR/MR 补丁可按
commit 拆分成多个独立 patch 文件。

## 用法

Expand All @@ -12,6 +13,8 @@ patchsplit <owner/repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit <owner> <repo> <pr-number> [--out <dir>] [--force] [--squash]
patchsplit <owner/repo> --commit <hash> [--out <dir>] [--force]
patchsplit <owner> <repo> --commit <hash> [--out <dir>] [--force]
patchsplit --gitlab <namespace/project> <mr-number> [--out <dir>] [--force] [--squash]
patchsplit --gitlab <namespace/project> --commit <hash> [--out <dir>] [--force]
```

示例:
Expand Down Expand Up @@ -60,11 +63,32 @@ patchsplit zitzhen/patchsplit --commit b4301133226e5c3a464cff9649de0b321c0b0a2e
`patches/b430113.patch`。它和按 commit 拆分的 PR 补丁一样可用 `git am` 应用。
`--commit` 不能与 `--squash` 同时使用。

### 从 GitLab 下载

传入 `--gitlab` 即可从 gitlab.com 下载合并请求(Merge Request)或单个 commit。
项目路径使用 `namespace/project` 格式,并支持子组(subgroup),例如
`group/subgroup/project`:

```sh
patchsplit --gitlab zitzhen/patchsplit 1
patchsplit --gitlab zitzhen/patchsplit --commit fafbad69af7507f41e786aa6685b2fa29716c85f
patchsplit --gitlab group/subgroup/project 1 --squash -o mr-1-patches
```

合并请求从
`https://gitlab.com/<namespace>/<project>/-/merge_requests/<编号>.patch` 下载,
和 GitHub PR 一样会按 commit 拆分成邮件格式补丁。传入 `--squash` 时下载
`.diff` 净变化并输出为 `mr-<编号>.patch`。`--commit` 则下载
`https://gitlab.com/<namespace>/<project>/-/commit/<hash>.patch`,并把补丁原样
写入 `<hash>.patch`。`--out`、`--force`、`--squash` 的规则与 GitHub 模式相同,
`--commit` 不能与 `--squash` 同时使用。

## 参数

- `-o, --out <dir>`:指定 patch 文件的输出目录。
- `-f, --force`:允许覆盖已存在的 patch 文件。
- `-s, --squash`:将 PR 的最终净变化输出为一个补丁。
- `-s, --squash`:将 PR/MR 的最终净变化输出为一个补丁。
- `--gitlab`:改为从 gitlab.com 下载合并请求或单个 commit(项目路径支持子组)。
- `--commit <hash>`:下载单个 commit 的 `.patch`,接受短哈希或完整哈希。
- `-h, --help`:显示帮助。
- `-V, --version`:显示版本。
Expand Down
69 changes: 65 additions & 4 deletions debian/patchsplit.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.TH PATCHSPLIT 1 "August 2026" "patchsplit 1.0.2" "User Commands"
.TH PATCHSPLIT 1 "September 2026" "patchsplit 1.2.0" "User Commands"
.SH NAME
patchsplit \- download a GitHub pull request patch, split it by commit, or fetch a single commit patch
patchsplit \- download GitHub pull request or GitLab merge request patches, split them by commit, or fetch a single commit patch
.SH SYNOPSIS
.B patchsplit
.RI < owner/repo > " <pr-number>"
Expand Down Expand Up @@ -41,6 +41,30 @@ patchsplit \- download a GitHub pull request patch, split it by commit, or fetch
[\c
.B \-\-force ]
.RE
.br
.B patchsplit
.B \-\-gitlab
.RI < namespace/project > " <mr-number>"
.RS
[\c
.B \-\-out
.IR dir ]
[\c
.B \-\-force ]
[\c
.B \-\-squash ]
.RE
.br
.B patchsplit
.B \-\-gitlab
.RI < namespace/project > " \-\-commit <hash>"
.RS
[\c
.B \-\-out
.IR dir ]
[\c
.B \-\-force ]
.RE
.SH DESCRIPTION
.B patchsplit
downloads the patch for a GitHub pull request and splits it into
Expand All @@ -65,13 +89,41 @@ The result is a mail-formatted patch for git am.
cannot be combined with
.BR \-\-squash .
.PP
With
.BR \-\-gitlab ,
download patches from GitLab
.RB ( gitlab.com )
instead of GitHub.
The merge request
.B https://gitlab.com/<namespace>/<project>/-/merge_requests/<number>.patch
is split into one patch per commit just like a GitHub pull request, while
.B \-\-squash
downloads the
.B .diff
net change and writes it to
.BR mr-<number>.patch .
The project path uses
.I namespace/project
form and may contain subgroups, for example
.IR group/subgroup/project .
With
.BR \-\-gitlab " " \-\-commit " " \fIhash\fR ,
fetch
.BR https://gitlab.com/<namespace>/<project>/-/commit/<hash>.patch .
.PP
The resulting patch files are written to the
.B patches
directory by default.
.SH OPTIONS
.TP
.BR \-s ", " \-\-squash
Write the PR's net diff as one patch instead of splitting by commit.
Write the request's net diff as one patch instead of splitting by commit.
.TP
.B \-\-gitlab
Download a merge request or commit patch from gitlab.com instead of GitHub.
The project argument uses
.I namespace/project
form and may contain subgroups.
.TP
.BR \-\-commit " " \fIhash\fR
Download the .patch of a single commit instead of a pull request.
Expand Down Expand Up @@ -114,11 +166,20 @@ Download the patch for commit b430113 from
.BR zitzhen/patchsplit
and write it to
.BR b430113.patch .
.TP
.B patchsplit \-\-gitlab zitzhen/patchsplit 1
Download and split merge request 1 from the GitLab project
.BR zitzhen/patchsplit .
.TP
.B patchsplit \-\-gitlab zitzhen/patchsplit \-\-commit de9ea1a
Download the patch for commit de9ea1a from GitLab and write it to
.BR de9ea1a.patch .
.SH REQUIREMENTS
.B patchsplit
uses
.B curl
to download pull request and commit patches from GitHub.
to download pull request, merge request, and commit patches from GitHub and
GitLab.
.SH SEE ALSO
.BR curl (1)
.SH AUTHORS
Expand Down
69 changes: 65 additions & 4 deletions packaging/patchsplit.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.TH PATCHSPLIT 1 "August 2026" "patchsplit 1.0.2" "User Commands"
.TH PATCHSPLIT 1 "September 2026" "patchsplit 1.2.0" "User Commands"
.SH NAME
patchsplit \- download a GitHub pull request patch, split it by commit, or fetch a single commit patch
patchsplit \- download GitHub pull request or GitLab merge request patches, split them by commit, or fetch a single commit patch
.SH SYNOPSIS
.B patchsplit
.RI < owner/repo > " <pr-number>"
Expand Down Expand Up @@ -41,6 +41,30 @@ patchsplit \- download a GitHub pull request patch, split it by commit, or fetch
[\c
.B \-\-force ]
.RE
.br
.B patchsplit
.B \-\-gitlab
.RI < namespace/project > " <mr-number>"
.RS
[\c
.B \-\-out
.IR dir ]
[\c
.B \-\-force ]
[\c
.B \-\-squash ]
.RE
.br
.B patchsplit
.B \-\-gitlab
.RI < namespace/project > " \-\-commit <hash>"
.RS
[\c
.B \-\-out
.IR dir ]
[\c
.B \-\-force ]
.RE
.SH DESCRIPTION
.B patchsplit
downloads the patch for a GitHub pull request and splits it into
Expand All @@ -65,13 +89,41 @@ The result is a mail-formatted patch for git am.
cannot be combined with
.BR \-\-squash .
.PP
With
.BR \-\-gitlab ,
download patches from GitLab
.RB ( gitlab.com )
instead of GitHub.
The merge request
.B https://gitlab.com/<namespace>/<project>/-/merge_requests/<number>.patch
is split into one patch per commit just like a GitHub pull request, while
.B \-\-squash
downloads the
.B .diff
net change and writes it to
.BR mr-<number>.patch .
The project path uses
.I namespace/project
form and may contain subgroups, for example
.IR group/subgroup/project .
With
.BR \-\-gitlab " " \-\-commit " " \fIhash\fR ,
fetch
.BR https://gitlab.com/<namespace>/<project>/-/commit/<hash>.patch .
.PP
The resulting patch files are written to the
.B patches
directory by default.
.SH OPTIONS
.TP
.BR \-s ", " \-\-squash
Write the PR's net diff as one patch instead of splitting by commit.
Write the request's net diff as one patch instead of splitting by commit.
.TP
.B \-\-gitlab
Download a merge request or commit patch from gitlab.com instead of GitHub.
The project argument uses
.I namespace/project
form and may contain subgroups.
.TP
.BR \-\-commit " " \fIhash\fR
Download the .patch of a single commit instead of a pull request.
Expand Down Expand Up @@ -114,11 +166,20 @@ Download the patch for commit b430113 from
.BR zitzhen/patchsplit
and write it to
.BR b430113.patch .
.TP
.B patchsplit \-\-gitlab zitzhen/patchsplit 1
Download and split merge request 1 from the GitLab project
.BR zitzhen/patchsplit .
.TP
.B patchsplit \-\-gitlab zitzhen/patchsplit \-\-commit de9ea1a
Download the patch for commit de9ea1a from GitLab and write it to
.BR de9ea1a.patch .
.SH REQUIREMENTS
.B patchsplit
uses
.B curl
to download pull request and commit patches from GitHub.
to download pull request, merge request, and commit patches from GitHub and
GitLab.
.SH SEE ALSO
.BR curl (1)
.SH AUTHORS
Expand Down
Loading
Loading