Skip to content

补丁(Patch)

补丁(Patch)是以文件形式存储的代码差异,可以在不同机器或仓库之间传递改动。在没有共享代码库访问权限时,补丁是传递代码改动的经典方式。

git diff > file.patch 生成补丁

git diff 生成标准 diff 格式的补丁:

bash
# 工作区改动 vs 暂存区
git diff > changes.patch

# 暂存区 vs HEAD
git diff --cached > staged.patch

# 指定提交之间的差异
git diff abc123..def456 > feature.patch

# 指定文件的差异
git diff HEAD~3 -- src/app.js > app-changes.patch

git apply 应用补丁

将补丁文件应用到当前工作区:

bash
# 应用补丁
git apply changes.patch

# 应用补丁并自动暂存
git apply --index changes.patch

# 应用补丁(更详细的输出)
git apply -v changes.patch

git format-patch 生成邮件格式补丁

git format-patch 生成的补丁包含完整的提交信息(作者、时间、提交消息),适合通过邮件发送:

bash
# 生成最近 3 个提交的补丁(每个提交一个 .patch 文件)
git format-patch -3
# 生成:
# 0001-feat-add-login.patch
# 0002-feat-add-register.patch
# 0003-fix-validation.patch

# 生成某个范围的提交
git format-patch main..feature/login

# 生成单个文件(所有提交合并)
git format-patch -1 --stdout > single.patch

# 指定输出目录
git format-patch -3 -o patches/

# 基于某个提交生成补丁
git format-patch abc123..HEAD

# 只生成某个特定提交的补丁
git format-patch -1 abc123

补丁文件内容示例:

From abc123456789 Mon Sep 17 00:00:00 2001
From: Zhang San <zhang@example.com>
Date: Mon, 9 Mar 2026 10:30:00 +0800
Subject: [PATCH] feat: 添加用户登录功能

实现了基于 JWT 的用户认证

---
 src/auth.js | 45 +++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/src/auth.js b/src/auth.js
...

git am 应用邮件格式补丁

git am(Apply Mailbox)将 format-patch 生成的补丁应用为完整提交(包含作者信息):

bash
# 应用单个补丁文件
git am 0001-feat-add-login.patch

# 应用目录下所有补丁
git am patches/*.patch

# 从邮件中应用(通过 stdin)
cat 0001-*.patch | git am

# 应用并签名
git am --signoff 0001-*.patch

git am vs git apply 的区别:

对比项git applygit am
输入格式标准 diffformat-patch 格式
创建提交否(只修改工作区)是(创建完整提交)
保留作者信息
适用场景快速应用差异应用他人的提交

git apply --check 测试补丁

在实际应用前,先验证补丁是否能正常应用:

bash
# 检查补丁是否能应用(不实际修改)
git apply --check changes.patch

# 成功:无输出
# 失败:error: patch failed: src/app.js:10

git apply --reject 部分应用

当补丁无法完全应用时(有冲突),--reject 允许应用可以应用的部分,并将冲突部分保存为 .rej 文件:

bash
# 尽力应用,冲突部分保存为 .rej 文件
git apply --reject changes.patch

# 查看冲突部分
cat src/app.js.rej

# 手动合并后,删除 .rej 文件
rm src/app.js.rej
git add src/app.js

实际工作流示例

场景1:向没有仓库访问权限的人发送改动

bash
# 开发者 A:生成补丁
git format-patch -3 -o ~/patches/
# 通过邮件发送 patches/ 目录中的文件

# 开发者 B:应用补丁
git am ~/patches/*.patch
git log --oneline -3  # 看到完整的提交历史,包含原作者信息

场景2:快速测试某个 PR 的改动

bash
# 从 PR 的差异生成补丁(GitHub 支持直接下载 .patch 文件)
# URL: https://github.com/user/repo/pull/123.patch
curl -o pr-123.patch https://github.com/user/repo/pull/123.patch

# 先检查
git apply --check pr-123.patch

# 应用测试
git am pr-123.patch

# 测试完后回退
git reset --hard HEAD~<commit-count>

场景3:保存工作进度为补丁

bash
# 将未提交的工作保存为补丁(备用方案)
git diff > wip-2026-03-09.patch

# 之后恢复
git apply wip-2026-03-09.patch

总结

操作命令
生成 diff 补丁git diff > file.patch
应用 diff 补丁git apply file.patch
生成邮件格式补丁git format-patch -n
应用邮件格式补丁git am file.patch
检查补丁可应用性git apply --check file.patch
部分应用git apply --reject file.patch

在现代 Git 工作流中,补丁的使用场景已经大幅减少(被 PR/MR 替代),但在一些特殊场景下(离线协作、邮件列表项目如 Linux 内核),补丁仍然是重要的工具。