Git 归档与补丁命令大全(完整详解版)

Git 的归档与补丁功能不仅是代码的"打包工具"和"传送协议",更是实现备份恢复、离线同步、团队协作与代码评审的核心机制。以下将为你完整拆解这些命令的每一处细节。


一、归档相关命令

归档命令用于将 Git 仓库中的文件打包成单个文件,便于备份、分发或离线传输。

1.1 git archive ------ 生成代码快照归档

git archive 将指定提交、分支或标签中的文件打包成 tarzip 等格式的归档文件。它生成的快照包含干净的代码内容,但不包含 .git 目录,非常适合发布和分发。

命令语法

bash 复制代码
git archive [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>] [-o <file>] [--worktree-attributes] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [<path>...]

全部选项详解

格式控制选项:

选项 说明
--format=<fmt> 指定归档格式:tarziptar.gztgz,或通过 tar.<format>.command 配置的自定义格式
-l / --list 列出所有可用的归档格式
-v / --verbose 报告进度信息到标准错误输出

文件和路径控制选项:

选项 说明
--prefix=<prefix>/ 为归档内所有文件路径添加指定前缀,可以重复使用;右边的值会被用于所有跟踪文件
-o <file> / --output=<file> 将归档写入指定文件而非标准输出
--add-file=<file> 非跟踪文件 添加到归档中。在归档中的路径由最后一次 --prefix 的值和该文件的基础名拼接而成
--add-virtual-file=<path>:<content> 直接通过内容添加虚拟文件。路径中的冒号需要转义,可以通过引号包裹。该选项不受 --prefix 影响
--worktree-attributes 查找工作区 .gitattributes 文件中的属性设置
--mtime=<time> 设置归档中所有文件的修改时间

远程操作选项:

选项 说明
--remote=<repo> 从远程仓库生成归档,无需本地克隆
--exec=<git-upload-archive> --remote 配合,指定远程端的 git-upload-archive 命令路径

归档中的元数据特性:

  • 当使用提交 ID 或标签 ID 时,每个文件的修改时间取自该提交的提交时间,且 tar 格式会在全局扩展 pax 头中存储提交 ID,便于追溯
  • 当使用树 ID 时,使用当前时间作为修改时间

全部使用示例

1. 基本打包

bash 复制代码
# 将当前 HEAD 打包为 tar 格式
git archive --format=tar HEAD > project.tar

# 利用扩展名自动推断格式
git archive -o project.tar.gz HEAD      # 自动使用 tar.gz
git archive -o project.zip HEAD         # 自动使用 zip

2. 添加路径前缀

bash 复制代码
# 所有文件放入项目根目录
git archive --prefix=myapp-1.0/ -o myapp-1.0.tar.gz HEAD

# 解压测试
git archive --prefix=myapp-1.0/ HEAD | tar -x -C /tmp/

3. 打包指定路径

bash 复制代码
# 只打包 src 和 docs 目录
git archive -o src-only.zip HEAD src/ docs/

# 打包单个文件
git archive -o README.zip HEAD README.md

4. 添加非跟踪文件

bash 复制代码
# 打包时额外包含配置文件
git archive -o deploy.tar.gz --add-file=.env.production HEAD

# 添加多个文件
git archive -o bundle.tar.gz --add-file=LICENSE --add-file=README.md HEAD

# 使用 prefix 控制非跟踪文件位置
git archive --prefix=config/ --add-file=.env.production -o deploy.tar.gz HEAD

5. 添加虚拟文件

bash 复制代码
# 在归档中创建包含版本信息的文件
git archive -o release.tar.gz --add-virtual-file=version.txt:v1.0.0 HEAD

# 文件名含特殊字符时需加引号
git archive -o release.tar.gz --add-virtual-file='"path/with:colon.txt":content' HEAD

# 从环境变量读取内容
git archive -o release.tar.gz --add-virtual-file="build-info.txt:$(git describe)" HEAD

6. 指定其他提交/分支/标签

bash 复制代码
# 打包指定标签
git archive --format=tar.gz --prefix=myapp-1.0/ -o myapp-1.0.tar.gz v1.0.0

# 打包指定分支
git archive -o feature.zip feature/login

# 打包指定提交
git archive -o snapshot.zip abc1234

7. 从远程仓库打包

bash 复制代码
# 从远程仓库直接打包,无需克隆
git archive --remote=https://github.com/user/repo.git --format=tar.gz HEAD > remote.tar.gz

# 指定远程分支
git archive --remote=git@github.com:user/repo.git --format=zip v1.0.0 > remote.zip

8. 组合使用不同压缩格式

bash 复制代码
# 打包并压缩为 gz
git archive --format=tar --prefix=myapp/ HEAD | gzip > myapp.tar.gz

# 打包为 bz2
git archive --format=tar HEAD | bzip2 > myapp.tar.bz2

# 打包为 xz
git archive --format=tar HEAD | xz > myapp.tar.xz

9. 查看归档内容

bash 复制代码
# 预览 tar 包内容
git archive --format=tar HEAD | tar -t

# 预览 zip 包内容
git archive --format=zip HEAD | zipinfo /dev/stdin

# 查看详细输出
git archive -v --format=tar HEAD > verbose.tar

10. 使用 .gitattributes 控制导出

bash 复制代码
# 在 .gitattributes 中定义导出行为
echo "tests/ export-ignore" >> .gitattributes
echo "*.log    export-ignore" >> .gitattributes
echo "README.md export-subst" >> .gitattributes

# 使用--worktree-attributes包含工作区属性
git archive --worktree-attributes -o release.zip HEAD

注意事项

  • 归档不包含 .git 目录和历史信息
  • 默认遵循 .gitattributes 中的 export-ignoreexport-subst 设置
  • --remote 需要远程仓库启用 git-upload-archive 服务
  • --add-virtual-file 受平台命令行长度限制,复杂内容建议使用 --add-file

1.2 git bundle ------ 离线传输 Git 对象

git bundle 将 Git 对象和引用打包成单个文件,用于没有网络连接情况下的仓库传输 。它支持增量备份和完整备份,可以配合 git clonegit fetch 使用。

命令语法

bash 复制代码
git bundle create [-q | --quiet | --progress] [--version=<version>] <file> <git-rev-list-args>
git bundle verify [-q | --quiet] <file>
git bundle list-heads <file> [<refname>...]
git bundle unbundle [--progress] <file> [<refname>...]

全部选项详解

子命令 说明
create 创建 bundle 文件,需指定 git-rev-list-args 定义包内容
verify 验证 bundle 文件是否有效,检查前提提交是否存在
list-heads 列出 bundle 中包含的引用(分支、标签)
unbundle 将 bundle 中的对象解包到当前仓库
选项 说明
-q / --quiet 静默模式,不输出进度信息
--progress 显示进度信息(适用于 createunbundle
--version=<version> 指定 bundle 版本号

Bundle 格式原理

Bundle 本质上是带有头部的 .pack 文件,头部指示包含哪些引用。使用修订排除创建的 bundle 是 "瘦包" ,体积更小。Git 不支持将 git push 直接推送到 bundle 文件。

全部使用示例

1. 创建完整仓库的 bundle

bash 复制代码
# 备份整个仓库(包含所有引用)
git bundle create repo.bundle --all

# 验证 bundle 完整性
git bundle verify repo.bundle

# 使用安静模式
git bundle create -q repo.bundle --all

2. 创建增量 bundle

bash 复制代码
# 打包从 v1.0 到 master 的所有提交
git bundle create updates.bundle v1.0..master

# 或使用负向引用
git bundle create updates.bundle ^v1.0 master

# 打包从特定提交到当前 HEAD
git bundle create feature.bundle abc1234..HEAD

3. 创建指定分支的 bundle

bash 复制代码
# 只打包 feature 分支
git bundle create feature.bundle feature/login

# 打包多个分支
git bundle create branches.bundle main feature/login

# 打包所有标签
git bundle create tags.bundle --tags

4. 查看 bundle 内容

bash 复制代码
# 查看 bundle 中的引用列表
git bundle list-heads updates.bundle
# 输出示例:
# abc1234 refs/heads/master
# def5678 refs/heads/feature

# 验证 bundle 对当前仓库是否可用
git bundle verify updates.bundle

# 查看特定引用
git bundle list-heads repo.bundle refs/heads/main

5. 从 bundle 克隆仓库

bash 复制代码
# 从 bundle 文件直接克隆
git clone updates.bundle new-repo

# 克隆后添加远程仓库
git clone repo.bundle my-repo
cd my-repo
git remote add origin https://github.com/user/repo.git

# 克隆时指定分支
git clone -b feature updates.bundle feature-repo

6. 从 bundle 获取更新

bash 复制代码
# 在已有仓库中从 bundle fetch
git fetch updates.bundle master:temp-branch

# fetch 后合并
git merge temp-branch

# 或直接 fetch 到当前分支
git pull updates.bundle master

# fetch 所有引用
git fetch updates.bundle --all

7. 使用标准输入输出

bash 复制代码
# 创建 bundle 并写入 stdout
git bundle create - --all > repo.bundle

# 从 stdin 读取 bundle
git bundle verify - < repo.bundle
git clone - repo2 < repo.bundle

8. 创建增量备份脚本

bash 复制代码
#!/bin/bash
# 增量备份脚本
LAST_BACKUP="refs/tags/last-backup"
CURRENT_BACKUP="refs/tags/backup-$(date +%Y%m%d)"

# 检查是否已有上次备份标签
if git rev-parse -q --verify $LAST_BACKUP >/dev/null; then
    # 创建增量 bundle
    git bundle create backup-$CURRENT_BACKUP.bundle $LAST_BACKUP..HEAD
else
    # 创建完整 bundle
    git bundle create backup-$CURRENT_BACKUP.bundle --all
fi

# 更新备份标签
git tag -f $CURRENT_BACKUP HEAD

9. 跨网络传输完整工作流

bash 复制代码
# 源机器:创建 bundle
git bundle create repo.bundle --all

# 通过 U 盘、scp 等方式传输 repo.bundle 到目标机器
# 目标机器:克隆 bundle
git clone repo.bundle my-repo

# 增量更新:源机器更新 bundle
git bundle create update.bundle v1.0..master

# 目标机器获取增量
cd my-repo
git fetch /path/to/update.bundle master:new-master
git merge new-master

10. 基于时间点的增量备份

bash 复制代码
# 备份最近一周的提交
git bundle create weekly-backup.bundle --since="1 week ago" --all

# 备份特定作者的所有提交
git bundle create author-backup.bundle --author="John Doe" --all

二、补丁相关命令(完整详解)

补丁命令是 Git 邮件驱动开发工作流的核心,下面以 git format-patchgit am 的闭环操作为主线进行深度展开。

补丁工作流全景图

scss 复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                            Git 补丁工作流全景图                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────┐     ┌─────────────────┐     ┌─────────────────────────┐  │
│   │ 提交历史    │ ──► │ git format-patch│ ──► │ .patch 文件(邮件格式) │  │
│   │ (commits)   │     │                 │     │ ▸ 每个提交独立文件       │  │
│   └─────────────┘     └─────────────────┘     │ ▸ 包含完整提交元数据     │  │
│                                                └───────────┬─────────────┘  │
│                                                            │                 │
│                                                            ▼                 │
│                                      ┌─────────────────────────────────┐    │
│                                      │          传输方式               │    │
│                                      ├───────────────┬─────────────────┤    │
│                                      │ 邮件 (email)  │ 文件传输 (USB等)│    │
│                                      └───────┬───────┴────────┬────────┘    │
│                                              │                │             │
│                                              ▼                ▼             │
│                         ┌────────────────────────┐  ┌─────────────────────┐ │
│                         │   git send-email       │  │  直接传递 .patch    │ │
│                         │   ▸ 发送到邮件列表     │  │  文件给对方         │ │
│                         │   ▸ 支持附注/内嵌      │  │                     │ │
│                         └───────────┬────────────┘  └──────────┬──────────┘ │
│                                     │                          │            │
│                                     └──────────┬───────────────┘            │
│                                                ▼                            │
│                                    ┌─────────────────────┐                  │
│                                    │  接收方获取补丁     │                  │
│                                    └─────────┬───────────┘                  │
│                                              │                              │
│                    ┌─────────────────────────┼─────────────────────────┐    │
│                    │                         │                         │    │
│                    ▼                         ▼                         ▼    │
│         ┌──────────────────┐     ┌──────────────────┐     ┌────────────────┐│
│         │   git am         │     │   git apply      │     │ git request-   ││
│         │   ▸ 应用邮件补丁 │     │   ▸ 应用普通补丁 │     │ pull           ││
│         │   ▸ 保留作者信息 │     │   ▸ 不自动提交   │     │ ▸ 生成拉取请求 ││
│         └────────┬─────────┘     └────────┬─────────┘     └───────┬────────┘│
│                  │                        │                        │         │
│                  ▼                        ▼                        ▼         │
│         ┌──────────────────┐     ┌──────────────────┐     ┌────────────────┐│
│         │   生成新提交     │     │   仅修改工作区   │     │   通知上游     ││
│         │   ▸ 保留原作者   │     │   ▸ 不创建提交   │     │   ▸ 执行 git   ││
│         │   ▸ 保留提交信息 │     │   ▸ 可选择性提交 │     │     pull       ││
│         └──────────────────┘     └──────────────────┘     └────────────────┘│
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

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

git format-patch 将每个提交转换为独立的补丁文件,完整保留提交元数据(作者、日期、提交信息),格式类似 UNIX 邮箱格式,便于邮件提交或与 git am 配合使用。

命令语法

bash 复制代码
git format-patch [-k] [(-o|--output-directory) <dir> | --stdout] [--no-thread | --thread[=<style>]] [(--attach|--inline)[=<boundary>] | --no-attach] [-s | --signoff] [--signature=<signature> | --no-signature] [--signature-file=<file>] [-n | --numbered | -N | --no-numbered] [--start-number <n>] [--numbered-files] [--in-reply-to=<message-id>] [--suffix=.<sfx>] [--ignore-if-in-upstream] [--always] [--cover-from-description=<mode>] [--rfc[=<rfc>]] [--subject-prefix=<subject-prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--[no-]encode-email-headers] [--no-notes | --notes[=<ref>]] [--interdiff=<previous>] [--range-diff=<previous> [--creation-factor=<percent>]] [--filename-max-length=<n>] [--progress] [<common-diff-options>] [ <since> | <revision-range> ]

全部选项详解

输出控制选项:

选项 说明
-o <dir> / --output-directory=<dir> 指定补丁输出目录
--stdout 输出到标准输出(适合管道操作)
--numbered-files 使用纯数字作为文件名
--start-number <n> 设置起始编号
--filename-max-length=<n> 限制文件名最大长度
--progress 显示生成进度
-q / --quiet 静默模式

格式控制选项:

选项 说明
--suffix=.<sfx> 设置补丁文件后缀,默认 .patch
-k / --keep-subject 保持提交信息的原样,不添加 [PATCH] 前缀
-N / --no-numbered 不添加编号(不推荐)
-n / --numbered 强制添加编号
--attach[=<boundary>] 以附件形式生成补丁,可选边界字符串
--inline[=<boundary>] 以内嵌形式生成补丁
--no-attach 禁用附件模式
--encode-email-headers / --no-encode-email-headers 控制是否编码邮件头(如非 ASCII 字符)

提交范围选项:

选项 说明
--root 从初始提交开始生成补丁
--always 即使没有变更也生成补丁
<since> 单个提交:输出从此提交之后(直到 HEAD)的所有提交
<revision-range> 标准修订范围表达式,如 main..feature

邮件相关选项:

选项 说明
--to=<email> 添加 To 收件人
--cc=<email> 添加 Cc 抄送
--subject-prefix=<prefix> 设置邮件主题前缀,默认 [PATCH]
-v <n> / --reroll-count=<n> 设置补丁版本号,如 -v2 生成 [PATCH v2]
--rfc[=<rfc>] 将主题前缀修改为 [RFC PATCH](请求意见稿)
--in-reply-to=<message-id> 设置回复的 Message-ID
--no-thread / --thread[=<style>] 设置邮件线程化:shallowdeep
--cover-letter 生成封面信(cover letter)
--cover-from-description=<mode> 控制封面信内容来源:messagesubjectautonone
--notes[=<ref>] / --no-notes 在提交信息中包含 Notes
--range-diff=<previous> 生成与之前版本的差异说明
--interdiff=<previous> 生成与之前版本的补丁差异
--creation-factor=<percent> 调整 range-diff 的匹配相似度

签名选项:

选项 说明
-s / --signoff 添加 Signed-off-by 签名
--signature=<signature> 自定义邮件签名
--signature-file=<file> 从文件读取签名内容
--no-signature 不添加签名

其他选项:

选项 说明
--ignore-if-in-upstream 跳过已在上游存在的提交
--keep-non-patch 保留非补丁部分的输出

全部使用示例

1. 基本用法

bash 复制代码
# 生成最近 3 次提交的补丁
git format-patch -3

# 生成从 v1.0 到 HEAD 之间的所有提交补丁
git format-patch v1.0..HEAD

# 生成从初始提交到 HEAD 的所有补丁
git format-patch --root

# 仅生成单个提交的补丁
git format-patch -1 abc1234

2. 指定输出位置和格式

bash 复制代码
# 输出到指定目录
git format-patch -o patches/ main..feature

# 输出到标准输出(适合管道)
git format-patch --stdout main..feature > all.patches

# 使用纯数字文件名(不包含提交主题)
git format-patch --numbered-files -3

# 设置起始编号
git format-patch --start-number 100 -3

# 自定义文件后缀
git format-patch --suffix=.diff -3

3. 邮件主题控制

bash 复制代码
# 添加版本号
git format-patch -v2 main..feature
# 生成主题: [PATCH v2 1/3] ...

# 自定义主题前缀
git format-patch --subject-prefix="RFC PATCH" main..feature
# 生成主题: [RFC PATCH 1/3] ...

# 添加 RFC 标识(快捷方式)
git format-patch --rfc main..feature
# 生成主题: [RFC PATCH 1/3] ...

# 使用多个前缀
git format-patch --subject-prefix="PATCH net-next" main..feature

4. 添加收件人

bash 复制代码
# 添加 To 和 Cc
git format-patch --to=maintainer@example.com --cc=reviewer@example.com main..feature

# 多个收件人
git format-patch --to=team@example.com --cc=lead@example.com --cc=qa@example.com main..feature

# 从文件读取收件人列表
git format-patch --to="$(cat maintainers.txt)" main..feature

5. 版本系列对比

bash 复制代码
# 生成与上一版本的差异说明(range-diff)
git format-patch --range-diff=origin/main~5 main

# 调整匹配相似度(默认 100,数值越小允许更大差异)
git format-patch --range-diff=origin/main~5 --creation-factor=80 main

# 生成简化的版本之间的补丁差异(interdiff)
git format-patch --interdiff=origin/main~5 main

6. 生成封面信

bash 复制代码
# 生成包含封面信的补丁系列
git format-patch --cover-letter -o patches/ main..feature

# 自动从提交内容生成封面信
git format-patch --cover-letter --cover-from-description=message -3

# 编辑生成的 patches/0000-cover-letter.patch 文件

7. 添加签名

bash 复制代码
# 自动添加 Signed-off-by
git format-patch -s main..feature

# 自定义签名内容
git format-patch --signature="My Project Team" main..feature

# 从文件读取签名
git format-patch --signature-file=signature.txt main..feature

8. 回复已有邮件线程

bash 复制代码
# 设置 In-Reply-To,使补丁成为某个邮件的回复
git format-patch --in-reply-to="<message-id@example.com>" main..feature

# 设置线程化(所有补丁回复给第一封)
git format-patch --thread main..feature

# 深度线程化(每个补丁回复前一个)
git format-patch --thread=deep main..feature

9. 附件和内嵌模式

bash 复制代码
# 以附件形式生成补丁
git format-patch --attach main..feature

# 以内嵌形式生成补丁
git format-patch --inline main..feature

# 指定边界字符串
git format-patch --attach="boundary-string" main..feature

10. 高级用法

bash 复制代码
# 生成补丁时忽略已在上游存在的提交
git format-patch --ignore-if-in-upstream main..feature

# 保持提交信息中原有的 [PATCH] 前缀
git format-patch -k main..feature

# 显示生成进度
git format-patch --progress -100

# 控制文件名长度(避免过长文件名)
git format-patch --filename-max-length=80 -3

# 静默模式(不输出任何提示)
git format-patch -q main..feature

2.2 git am ------ 应用邮箱格式补丁

git am(apply mailbox)从邮箱文件中读取补丁,自动分割邮件,提取提交信息、作者信息和补丁内容,并在当前分支上创建提交。

命令语法

bash 复制代码
git am [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--[no-]verify] [--[no-]3way] [--interactive] [--committer-date-is-author-date] [--ignore-date] [--ignore-space-change | --ignore-whitespace] [--whitespace=<action>] [-C<n>] [-p<n>] [--directory=<dir>] [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet] [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>] [--quoted-cr=<action>] [--empty=(stop|drop|keep)] [(<mbox> | <Maildir>)...]
git am (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty)

全部选项详解

应用控制选项:

选项 说明
-s / --signoff 在提交信息中添加 Signed-off-by
-k / --keep 保留提交信息中原有的 [PATCH] 前缀
--keep-non-patch 保留邮件中非补丁部分的内容
--keep-cr / --no-keep-cr 保留或去除行尾的 CR 字符(回车符)
-c / --scissors 忽略邮件中的剪刀线(-- >8 --)之后的内容
--no-scissors 不忽略剪刀线

编码和格式控制:

| 选项 | 说明 |
|---------------------------|-------------------------------------------|---------|----------------------------------------|
| --utf8 / --no-utf8 | 将提交信息从 ISO-8859-1 转换为 UTF-8(默认启用) |
| --patch-format=<format> | 指定补丁格式:mboxstgitstgit-serieshg |
| --quoted-cr=<action> | 处理带引号的可打印编码中的回车符 |
| `--empty=(stop | drop | keep)` | 处理空补丁:stop停止、drop跳过、keep保留为仅信息提交 |

合并和冲突处理:

选项 说明
--3way / --no-3way 尝试三方合并,增强补丁应用的兼容性
--interactive 交互模式,逐个确认每个补丁的应用
--committer-date-is-author-date 使用作者日期作为提交日期
--ignore-date 使用当前日期作为提交日期,忽略作者日期
--ignore-space-change / --ignore-whitespace 忽略空白字符变化
--whitespace=<action> 处理空白字符错误:nowarnwarnfixerrorerror-all
-C<n> 减少上下文匹配行数(默认 3)
-p<n> 剥离路径前缀的级数
--directory=<dir> 将补丁应用到指定子目录
--exclude=<path> 排除指定路径
--include=<path> 只包含指定路径
--reject 冲突时保留 .rej 文件
-S[<keyid>] 使用 GPG 签名提交(使用指定密钥)

其他选项:

选项 说明
--verify / --no-verify 跳过 pre-applypatch 和 post-applypatch 钩子
-q / --quiet 静默模式
--retry 重新尝试应用失败的补丁

冲突处理子命令

| 子命令 | 说明 |
|--------------------------------|------------------|---------------|
| --continue / -r | 解决冲突后继续应用剩余补丁 |
| --skip | 跳过当前有问题的补丁 |
| --abort | 放弃整个 am 操作,恢复原状态 |
| --quit | 退出 am 操作,但不恢复原状态 |
| `--show-current-patch[=(diff | raw)]` | 显示当前正在应用的补丁内容 |
| --allow-empty | 允许创建空提交 |

全部使用示例

1. 基本用法

bash 复制代码
# 应用单个补丁文件
git am 0001-fix-bug.patch

# 应用目录下的所有补丁(按文件名顺序)
git am patches/*.patch

# 从标准输入读取
git am < incoming.patch

2. 添加签名

bash 复制代码
# 应用补丁时自动添加 Signed-off-by
git am --signoff patches/*.patch

# 使用 GPG 签名提交
git am -S patches/*.patch

# 指定签名密钥
git am -S=0A46826A patches/*.patch

3. 三方合并模式

bash 复制代码
# 使用三方合并,提高补丁兼容性
git am --3way patches/*.patch

# 检查冲突时减少上下文匹配
git am -C1 patches/*.patch

4. 交互模式

bash 复制代码
# 逐个确认每个补丁的应用
git am --interactive patches/*.patch
# 每个补丁前会询问: Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

5. 日期控制

bash 复制代码
# 使用作者日期作为提交日期
git am --committer-date-is-author-date patches/*.patch

# 忽略作者日期,使用当前日期
git am --ignore-date patches/*.patch

6. 处理空白字符

bash 复制代码
# 忽略空白字符差异
git am --ignore-space-change patches/*.patch

# 自动修复空白字符错误
git am --whitespace=fix patches/*.patch

# 将空白字符错误视为警告但不阻止应用
git am --whitespace=warn patches/*.patch

7. 调整路径

bash 复制代码
# 将补丁应用到 subdir 目录下
git am --directory=subdir/ patches/*.patch

# 剥离路径前缀(-p1 表示去掉第一级路径)
git am -p2 patches/*.patch

# 排除特定路径
git am --exclude="docs/*" patches/*.patch

# 只包含特定路径
git am --include="src/*" patches/*.patch

8. 冲突处理流程

bash 复制代码
# 开始应用补丁
git am patches/*.patch
# 如果出现冲突...

# 方法一:解决冲突后继续
git status                    # 查看冲突文件
# 手动解决冲突...
git add <resolved-files>
git am --continue

# 方法二:跳过当前补丁
git am --skip

# 方法三:放弃整个操作
git am --abort

9. 查看当前补丁

bash 复制代码
# 查看正在应用的补丁内容
git am --show-current-patch

# 查看补丁的 diff 部分
git am --show-current-patch=diff

# 查看补丁的原始内容(含邮件头)
git am --show-current-patch=raw

10. 高级选项

bash 复制代码
# 使用剪刀线(忽略邮件签名等)
git am --scissors patches/*.patch

# 处理空提交(保留空提交)
git am --empty=keep patches/*.patch

# 跳过空提交
git am --empty=drop patches/*.patch

# 遇到空提交时停止
git am --empty=stop patches/*.patch

# 强制重新尝试应用(之前失败的补丁)
git am --retry

# 退出但不恢复(保留当前状态)
git am --quit

2.3 git apply ------ 应用普通补丁(不自动提交)

git apply 读取 diff 输出并将其应用到文件。与 git am 不同,git apply 不会自动创建提交,仅修改工作区文件。可以在非 Git 仓库中使用。

命令语法

bash 复制代码
git apply [--stat] [--numstat] [--summary] [--check] [--index | --intent-to-add] [--3way] [--ours | --theirs | --union] [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse] [--allow-binary-replacement | --binary] [--reject] [-z] [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached] [--ignore-space-change | --ignore-whitespace] [--whitespace=(nowarn|warn|fix|error|error-all)] [--exclude=<path>] [--include=<path>] [--directory=<root>] [--verbose | --quiet] [--unsafe-paths] [--allow-empty] [<patch>...]

全部选项详解

检查模式选项(不实际应用补丁):

选项 说明
--stat 输出 diffstat 统计,不应用补丁
--numstat 输出机器可读的统计(添加/删除行数)
--summary 输出扩展头信息摘要(创建、重命名、模式变更)
--check 检查补丁是否可应用,不实际修改

应用范围选项:

选项 说明
--index 同时应用到索引和工作区(需在 Git 仓库中执行)
--cached 只应用到索引(暂存区),不修改工作区
--intent-to-add / -N 标记新文件为"待添加",配合工作区使用
-z 使用 NUL 字符分隔输出,而非 LF

合并和冲突处理:

选项 说明
--3way / -3 尝试三方合并,应对冲突
--ours 三方合并时优先使用我们的版本
--theirs 三方合并时优先使用对方的版本
--union 合并所有版本(并集)
--reject 冲突时保留 .rej 文件
--build-fake-ancestor=<file> 构建假祖先树,用于调试

路径处理选项:

选项 说明
-p<n> 剥离路径前缀级数
--directory=<root> 将补丁应用到指定子目录
--exclude=<path> 排除指定路径
--include=<path> 只包含指定路径
--unsafe-paths 允许应用到工作区外的路径

空白字符处理:

选项 说明
--ignore-space-change / --ignore-whitespace 忽略空白字符变化
--whitespace=<action> 处理空白字符:nowarnwarnfixerrorerror-all

其他选项:

选项 说明
--apply 强制应用操作(默认)
--no-add 不添加新文件
-R / --reverse 反向应用补丁(撤销)
--allow-binary-patch-replacement / --binary 允许二进制补丁替换
--recount 忽略补丁中的行数信息,重新计算
--inaccurate-eof 允许不精确的 EOF 处理
--allow-empty 允许应用空补丁
-v / --verbose 详细输出
-q / --quiet 静默模式

全部使用示例

1. 基本应用

bash 复制代码
# 应用补丁到工作区(不创建提交)
git apply patchfile.patch

# 在非 Git 仓库中也可使用
cd /some/non-git/directory
git apply /path/to/patchfile.patch

2. 检查补丁

bash 复制代码
# 检查补丁是否可应用
git apply --check patchfile.patch

# 查看补丁的统计信息
git apply --stat patchfile.patch

# 查看补丁的数字统计(机器可读)
git apply --numstat patchfile.patch

# 查看补丁的摘要信息(创建、重命名、模式变更)
git apply --summary patchfile.patch

3. 应用到索引

bash 复制代码
# 应用到索引和工作区(需在 Git 仓库中)
git apply --index patchfile.patch

# 只应用到索引(暂存区)
git apply --cached patchfile.patch

# 标记新文件为待添加
git apply --intent-to-add patchfile.patch

4. 反向应用(撤销补丁)

bash 复制代码
# 反向应用,撤销补丁
git apply -R patchfile.patch

# 等价写法
git apply --reverse patchfile.patch

# 应用补丁时遇到已存在的内容 - 可反向处理
git apply --reverse fix.patch

5. 处理冲突

bash 复制代码
# 尝试三方合并解决冲突
git apply --3way patchfile.patch

# 三方合并时使用我们的版本
git apply --3way --ours patchfile.patch

# 使用对方的版本
git apply --3way --theirs patchfile.patch

# 合并所有版本(并集)
git apply --3way --union patchfile.patch

# 冲突时保留 .rej 文件
git apply --reject patchfile.patch
# 之后可以手动处理 .rej 文件

6. 路径控制

bash 复制代码
# 将补丁应用到子目录
git apply --directory=src/ patchfile.patch

# 剥离路径前缀(-p1 去掉第一级路径)
git apply -p2 patchfile.patch

# 只包含特定路径的文件
git apply --include=src/*.c patchfile.patch

# 排除特定路径的文件
git apply --exclude=docs/* patchfile.patch

# 允许应用到工作区外的路径(谨慎使用)
git apply --unsafe-paths patchfile.patch

7. 空白字符处理

bash 复制代码
# 忽略空白字符差异
git apply --ignore-space-change patchfile.patch

# 自动修复空白字符错误
git apply --whitespace=fix patchfile.patch

# 将空白字符错误视为错误
git apply --whitespace=error patchfile.patch

# 只警告不处理
git apply --whitespace=warn patchfile.patch

# 不输出警告
git apply --whitespace=nowarn patchfile.patch

8. 二进制文件处理

bash 复制代码
# 允许二进制补丁替换
git apply --binary patchfile.patch

# 允许二进制补丁替换(旧选项)
git apply --allow-binary-replacement patchfile.patch

9. 上下文和行数控制

bash 复制代码
# 减少上下文匹配行数(更宽松的匹配)
git apply -C1 patchfile.patch

# 忽略补丁中的行数信息,重新计算
git apply --recount patchfile.patch

# 允许不精确的 EOF 处理
git apply --inaccurate-eof patchfile.patch

10. 组合使用

bash 复制代码
# 先检查,再应用
git apply --check patchfile.patch && git apply patchfile.patch

# 将补丁应用到索引并提交
git apply --index patchfile.patch
git commit -m "Apply patch from contributor"

# 从标准输入读取补丁
git apply --index - < patchfile.patch

# 详细输出模式
git apply -v patchfile.patch

# 静默模式
git apply -q patchfile.patch

2.4 git send-email ------ 发送补丁邮件

git send-email 将补丁通过电子邮件发送出去,是邮件驱动开发工作流的核心工具。

子命令语法

bash 复制代码
git send-email [<options>] (<file>|<directory>)...
git send-email [<options>] <format-patch-options>
git send-email --dump-aliases
git send-email --translate-aliases

全部选项详解

邮件撰写选项(Composing):

选项 说明
--annotate 发送前审查和编辑每封邮件,默认值为 sendemail.annotate
--bcc=<address> 指定密送,可多次使用,默认 sendemail.bcc
--cc=<address> 指定抄送,可多次使用,默认 sendemail.cc
--compose 编写封面信(cover letter),打开编辑器编辑
--from=<address> 指定发件人,否则使用 sendemail.from
--in-reply-to=<message-id> 使补丁成为某邮件的回复
--reply-to=<address> 指定 Reply-To 地址
--subject=<string> 指定邮件主题
--to=<address> 指定收件人,可多次使用

补丁格式选项:

选项 说明
--attach 以附件形式发送补丁
--inline 以内嵌形式发送补丁
--no-attach 禁用附件形式(默认)

SMTP 配置选项:

选项 说明
--smtp-server=<server> SMTP 服务器地址
--smtp-server-port=<port> SMTP 服务器端口
--smtp-user=<user> SMTP 用户名
--smtp-pass=<password> SMTP 密码(不建议命令行传入)
--smtp-encryption=<type> 加密类型:tlsssl
--smtp-domain=<domain> 指定 EHLO/HELO 域名

其他选项:

选项 说明
--dry-run 模拟运行,不实际发送
-v / --verbose 详细输出
-q / --quiet 静默模式
--confirm=<mode> 发送前确认模式:alwaysnevercccomposeauto
--dump-aliases 显示邮件别名
--translate-aliases 翻译邮件别名
--no-validate 跳过补丁格式验证
--force-send 即使没有收件人也强制发送

SMTP 配置示例

配置 Gmail

bash 复制代码
git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser your@gmail.com

配置 Outlook.com

bash 复制代码
git config --global sendemail.smtpserver smtp-mail.outlook.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls

常用发送设置

bash 复制代码
# 设置默认发件人
git config --global sendemail.from "Your Name <you@example.com>"

# 启用发送前确认
git config --global sendemail.confirm always

# 设置别名文件
git config --global sendemail.aliasfiletype mutt
git config --global sendemail.aliasfile ~/.mutt_aliases

全部使用示例

1. 基本发送

bash 复制代码
# 发送单个补丁文件
git send-email --to=maintainer@example.com 0001-fix.patch

# 发送目录下的所有补丁
git send-email --to=maintainer@example.com patches/

# 发送最近 3 个提交的补丁
git send-email --to=maintainer@example.com -3

2. 多个收件人

bash 复制代码
# 多个 To 和 Cc
git send-email --to=maintainer@example.com --to=co-maintainer@example.com \
               --cc=reviewer@example.com --cc=testing@example.com patches/

# 添加密送
git send-email --bcc=others@example.com patches/

3. 编写封面信

bash 复制代码
# 编写封面信
git send-email --compose --to=maintainer@example.com patches/

# 发送前会打开编辑器编写封面信
# 封面信中可以设置 From、To、Cc、Subject、Reply-To、In-Reply-To 等

4. 审查和编辑

bash 复制代码
# 发送前审查每个补丁
git send-email --annotate --to=maintainer@example.com patches/

# 启用多文件编辑(每个补丁单独编辑)
git config sendemail.multiEdit true
git send-email --annotate --to=maintainer@example.com patches/

5. 版本号控制

bash 复制代码
# 发送 v2 版本的补丁
git send-email -v2 --to=maintainer@example.com patches/

# 设置主题前缀
git send-email --subject-prefix="PATCH v3" --to=maintainer@example.com patches/

# 使用 RFC 前缀
git send-email --rfc --to=maintainer@example.com patches/

6. 回复邮件线程

bash 复制代码
# 使补丁成为某个邮件的回复
git send-email --in-reply-to="<message-id@example.com>" patches/

# 设置 Reply-To 地址
git send-email --reply-to=reviewer@example.com patches/

7. 使用不同的 SMTP 服务器

bash 复制代码
# 临时覆盖 SMTP 设置
git send-email --smtp-server=smtp.company.com \
               --smtp-user=yourname \
               --smtp-encryption=tls \
               --to=maintainer@example.com patches/

8. 模拟运行

bash 复制代码
# 模拟发送,不实际发送
git send-email --dry-run --to=maintainer@example.com patches/

# 详细模式,查看发送过程
git send-email --verbose --to=maintainer@example.com patches/

9. 发送前确认

bash 复制代码
# 每次发送前都确认
git send-email --confirm=always --to=maintainer@example.com patches/

# 只在添加了 Cc 时确认
git send-email --confirm=cc --to=maintainer@example.com patches/

# 只在编写封面信时确认(默认)
git send-email --confirm=compose --to=maintainer@example.com patches/

10. 高级用法

bash 复制代码
# 使用附件格式
git send-email --attach --to=maintainer@example.com patches/

# 内嵌格式
git send-email --inline --to=maintainer@example.com patches/

# 结合 format-patch 选项
git send-email --to=maintainer@example.com --cover-letter -3

# 使用别名文件
git send-email --to=maintainer --cc=reviewer patches/

# 显示别名
git send-email --dump-aliases

2.5 git request-pull ------ 生成拉取请求

git request-pull 生成一个拉取请求摘要,输出到标准输出,内容包含分支描述、变更摘要和拉取地址,便于向上游项目请求拉取变更。

命令语法

bash 复制代码
git request-pull [-p] <start> <URL> [<end>]

参数说明

参数 说明
-p 在输出中包含补丁文本
<start> 起始提交,必须是上游已存在的提交
<URL> 公共仓库的 URL
<end> 结束提交,默认 HEAD,可以是提交、分支或标签
<local>:<remote> 当本地和远程分支名不同时使用此语法

全部使用示例

1. 基本用法

bash 复制代码
# 生成拉取请求(基于 v1.0 到当前分支)
git request-pull v1.0 https://github.com/user/repo.git

# 输出示例:
# The following changes since commit abc1234:
#   Release v1.0 (2024-01-01 10:00:00 +0800)
# 
# are available in the Git repository at:
# 
#   https://github.com/user/repo.git master
# 
# for you to fetch changes up to def5678:
# 
#   Add new feature (2024-01-15 14:30:00 +0800)
# 
# ----------------------------------------------------------------
# 详细提交列表...

2. 指定结束提交

bash 复制代码
# 指定结束提交为 feature 分支
git request-pull v1.0 https://github.com/user/repo.git feature/login

# 指定结束提交为具体哈希
git request-pull v1.0 https://github.com/user/repo.git abc1234

3. 包含补丁内容

bash 复制代码
# 在输出中包含完整补丁
git request-pull -p v1.0 https://github.com/user/repo.git master

4. 处理分支名差异

bash 复制代码
# 本地分支名为 master,远程分支名为 for-linus
git request-pull v1.0 https://github.com/user/repo.git master:for-linus

# 输出中的拉取地址会显示正确的远程分支名

5. 完整工作流示例

bash 复制代码
# 1. 在本地完成开发
git checkout -b feature/new-ui
# ... 开发提交 ...

# 2. 推送到公共仓库
git push origin feature/new-ui

# 3. 生成拉取请求并发送给维护者
git request-pull main https://github.com/user/repo.git feature/new-ui | \
    mail -s "Pull request: New UI feature" maintainer@example.com

6. 与邮件集成

bash 复制代码
# 存储输出到文件
git request-pull -p origin/main https://github.com/user/repo.git feature > pull_request.txt

# 使用 git send-email 发送
git send-email --to=maintainer@example.com pull_request.txt

2.6 git patch-id ------ 生成补丁唯一标识

git patch-id 为补丁生成稳定的唯一标识符,基于补丁的 diff 内容(忽略空白和提交信息差异)。

使用示例

bash 复制代码
# 为补丁文件生成 patch-id
git patch-id < 0001-fix.patch

# 输出格式: <patch-id> <commit-hash>
# abc1234... 9a8b7c6...

# 比较两个补丁是否等价(忽略提交信息)
git patch-id < patch1.patch > id1
git patch-id < patch2.patch > id2
diff id1 id2

应用场景

  • 检测不同提交是否引入了相同的代码变更
  • git rebase 中识别重复提交
  • 避免重复应用相同的补丁

2.7 git format-patchgit am 的闭环协作

下图展示了社区协作中最常用的标准补丁工作流,覆盖了从补丁生成到应用的全部链路:

bash 复制代码
# 补丁生成与邮件发送 (补丁制作者)
git checkout -b feature/bug-fix
# ... 开发并提交 ...

# 生成补丁文件并发送
git format-patch --cover-letter --to=maintainer@example.com -v1 origin/main..HEAD
git send-email --to=maintainer@example.com *.patch

# 补丁接收与应用 (维护者)
git checkout main
git pull origin main
git checkout -b review/bug-fix

# 下载或接收邮件补丁后应用
git am --signoff --3way /path/to/patches/*.patch

# 测试无误后合并
git checkout main
git merge --ff-only review/bug-fix
git push origin main

这个闭环涵盖了补丁工作的所有环节,每一步都有对应的 Git 命令支撑,确保协作流程完整、可追溯。

三、git amgit apply 详细对比

特性 git am git apply
输入格式 mbox 邮箱格式(git format-patch 输出) 普通 diff/patch 格式
Git 仓库要求 必须在仓库中执行 ❌ 可在非仓库中执行
自动提交 ,每个补丁生成一个提交 ❌ 否,只修改工作区
保留提交元数据 ✅ 保留作者、日期、提交信息 ❌ 不保留
冲突处理机制 --continue--skip--abort--quit --reject--3way--ours--theirs
交互模式 --interactive ❌ 无
三方合并 --3way --3way
签名支持 --signoff-S(GPG 签名) ❌ 无
适用场景 接收邮件补丁、保留贡献者信息 快速测试补丁、非 Git 环境、精细控制
路径过滤 --exclude--include--directory --exclude--include--directory

四、速查表

分类 命令 核心功能 关键选项
归档 git archive 生成代码快照归档 --format-o--prefix--add-file--remote
git bundle 离线传输 Git 对象(备份) createverifylist-headsunbundle
补丁生成 git format-patch 生成邮件格式补丁 -v--to--cc--cover-letter--rfc
补丁应用 git am 应用邮箱补丁并提交 --signoff--3way--continue--skip--abort
git apply 应用普通补丁(不提交) --check--index--3way-R
补丁发送 git send-email 发送补丁邮件 --to--cc--compose--dry-run
请求拉取 git request-pull 生成拉取请求摘要 -p<start><URL><end>
辅助工具 git patch-id 生成补丁唯一标识 用于补丁去重检测

五、最佳实践建议

  1. 正式协作补丁 :使用 git format-patch + git am 流程,完整保留贡献者元数据
  2. 快速测试补丁 :使用 git apply --check 先验证兼容性,再用 git apply 应用或 git apply -R 撤销
  3. 邮件发送前 :务必用 --dry-run--confirm=always 检查收件人和补丁内容
  4. 远程仓库受限时git bundle 是最佳的离线传输替代方案
  5. 补丁版本管理 :使用 git format-patch -v<N> 生成带版本号的补丁,便于维护者追溯迭代历史
  6. 仓库备份 :定期使用 git bundle create 创建完整备份,或结合 git rev-list 做增量备份
  7. 跨团队合作 :团队间无法直接 git push/pull 时,补丁流转是最安全、规范的选择,保持审计链完整

💡 特别注意git diff 生成的普通 diff 格式不包含提交元数据 ,只适用于 git apply;而 git format-patch 生成的 mbox 格式补丁必须使用 git am 提交,才能保留作者信息和提交消息。

相关推荐
RePeaT1 小时前
【Nginx】前端项目部署与反向代理实战指南
前端·nginx
索木木2 小时前
ShortCut MoE模型分析
前端·html
MXN_小南学前端3 小时前
Vue3 + Spring Boot 工单系统实战:用户反馈和客服处理的完整闭环(提供gitHub仓库地址)
前端·javascript·spring boot·后端·开源·github
轮子大叔3 小时前
CSS基础入门
前端·css
踩着两条虫3 小时前
强强联合!VTJ.PRO 正式接入 DeepSeek V4,AI 编码能力再跃升
前端·vue.js·ai编程
Lily.C3 小时前
DOMPurify 前端富文本 XSS 防护使用指南
前端
一叶渡江3 小时前
深挖 iOS 16 以下 flex column-reverse 滚动失效问题
前端
众创岛3 小时前
回调函数、闭包概念、场景及python实战
前端
得想办法娶到那个女人3 小时前
项目中 TypeScript 类型推导 极简实战总结
前端·javascript·typescript