正在加载,请稍候…

Git Diff 与 Apply:开发者实用指南

学习使用 git diff 和 apply 进行代码审查和打补丁,包含真实场景示例、常见陷阱和 FAQ。

Git 的 diffapply 命令是代码审查、打补丁以及在分支或仓库间迁移变更的必备工具。git diff 生成显示提交或工作树之间差异的补丁文件,而 git apply 则将补丁应用到另一个代码库。本指南从基本的文件级 diff 到处理复杂场景,结合实际开发工作流,介绍实用用法。

开发者在大屏幕上审查 diff

理解 git diff 和补丁文件

git diff 生成统一 diff 格式,逐行描述变更。补丁文件(.patch.diff)是 git diff 的输出,可应用到其他地方。与 git format-patch(每个提交生成一个文件,包含完整提交元数据)不同,git diff 生成单个无提交历史的补丁,非常适合临时变更。

基本用法

为特定文件生成补丁:

git diff Test.java > test.patch

为所有修改的文件生成补丁:

git diff > all-changes.patch

在两个提交之间生成补丁:

git diff <old-commit> <new-commit> > changes.patch

使用 git apply 应用补丁

获得补丁文件后,将其应用到目标仓库:

git apply test.patch

git apply 修改工作树但不创建提交。在干净的工作目录上使用是安全的;如果补丁失败,工作树保持不变。

选项

  • --check:测试补丁是否能干净应用,不实际应用。
  • --reject:应用能应用的部分,拒绝的块留在 .rej 文件中。
  • --whitespace=fix:自动修复空白错误。

完整示例:代码审查与打补丁

假设开发者 Alice 在功能分支上做了修改,希望 Bob 审查并应用。

  1. Alice 修改了两个文件:src/app.jssrc/utils.js
  2. 她生成补丁:
    git diff > feature.patch
    
  3. Bob 收到 feature.patch 并审查。他可以在不应用的情况下检查 diff:
    git apply --check feature.patch
    
  4. 如果干净,Bob 应用:
    git apply feature.patch
    

处理冲突

如果补丁失败,Bob 可以使用 --reject 应用非冲突部分:

git apply --reject feature.patch

这为拒绝的块创建 .rej 文件,Bob 可以手动解决。

对比:git diff vs git format-patch

特性 git diff git format-patch
包含提交元数据 是(作者、日期、消息)
文件粒度 单个文件或全部变更 每个提交一个文件
使用场景 临时补丁、代码审查 基于邮件的工作流、保留历史
应用命令 git apply git am

常见陷阱

  • 在脏工作树上应用补丁:始终在干净状态下应用补丁以避免混淆。
  • 二进制文件git diff 适用于文本文件;二进制文件需要 --binary 标志。
  • 空白问题:补丁可能因尾部空白或缩进差异而失败。使用 --whitespace=fix
  • 跨仓库补丁:路径必须匹配;否则使用 -p<n> 剥离前导目录组件。
  • 大补丁:对于大变更,考虑拆分为更小的逻辑补丁。

性能考虑

git diffgit apply 对大多数用例高效。但对于非常大的仓库或深历史,考虑:

  • 使用路径参数限制 diff 范围。
  • 使用 git diff --cached 比较暂存区与上次提交。
  • 对于大型补丁,使用 git format-patchgit am,它们能更好地处理二进制文件和编码。

常见问题

.patch.diff 文件有什么区别?

技术上格式相同。.patch 通常用于 git format-patch 的输出,.diff 用于 git diff。两者都是纯文本统一 diff。

可以应用来自另一个仓库的补丁吗?

可以,只要文件路径匹配。如果不匹配,使用 git apply -p1(剥离一个目录级别)或用 -p<n> 调整。

如何撤销已应用的补丁?

使用 git apply -R <patch-file> 反转补丁。或者 git checkout 受影响的文件。

git apply 会创建提交吗?

不会,它只修改工作树。要提交,之后运行 git commit

如果补丁部分失败怎么办?

使用 --reject 应用非冲突部分。手动解决 .rej 文件中的拒绝块。

在应用补丁之前,试试我们的文本差异工具来直观比较变更。