补丁,当本地版本库与远程版本库未直接进行关联,需要通过补丁来进行相关对象的同步(通常是commit)。
补丁的内容
git format-patch generates one email message for each selected commit
git format-patch generates an email message complete with headers that list the commit author, the commit date, and the commit log message associated with the change
format-patch命令为每次提交都生成一个补丁,补丁的内容头部是邮件的一些信息,和提交相关的信息,包含提交作者,日期,提交的日志信息。内容体,是当前提交与其父提交的比较结果(git diff)。
补丁的创建,发送,应用。实际工作的应用场景很少。
官网地址:https://git-scm.com/docs,patching部分和Email部分
1、创建
使用git format-patch生成补丁。它的选项或者是参数有四种形式,
- 第一种形式-n,指最近的n次提交,每次提交都生成一份补丁。
- 第二种形式range,在范围之内的提交生成补丁。
- 第三种形式是commit的标识,例如引用标识,ID等类似的提交名称
- 第四种形式是branch的名称。
在第二种形式中,若range中存在合并的操作,它生成补丁的步骤如下,
- 它会从end开始沿着提交历史找寻所有的父提交,祖父提交直到初始提交。
- 之后排除由start开始沿着提交历史找寻到的所有父提交,祖父提交,并且包含start本身。
- 最后排除所有合并的提交,也可以理解为有多个父提交的提交。
假定目前有两个分支alt,master分支,范围为C..F。
第一步,从F开始寻找所有父提交,祖父提交,它们包括A,B,C,D,E,F,X,Y,Z。即全部包括
第二步,排除由C开始寻找到的所有父提交,祖父提交,包含C自身。此时剩余D,E,F,X,Y,Z
第三步,排除所有合并的提交,即E,此时剩余D,F,X,Y,Z。
执行git format-patch C..F会为D,F,X,Y,Z每个提交各生成一份补丁。
第三种形式本质是commitID..HEAD之间的补丁。它与commitID,HEAD有关。执行git format-path master~1与 -1是等价的。
第四种形式分两种情况,若选项中的分支名称与当前分支名称相同,无任何结果。若分支名称与当前分支名称不同,例如在master分支上执行git format-patch alt,会生成alt分支上没有的,而master分支上存在的提交。
本质是当前分支与选项分支的差集,并且排除合并的提交。
格式为:
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] [--cover-from-description=<mode>] [--rfc] [--subject-prefix=<subject prefix>] [(--reroll-count|-v) <n>] [--to=<email>] [--cc=<email>] [--[no-]cover-letter] [--quiet] [--no-notes | --notes[=<ref>]] [--interdiff=<previous>] [--range-diff=<previous> [--creation-factor=<percent>]] [--progress] [<common diff options>] [ <since> | <revision range>]
它的大部分选项分为三个部分,
第一部分,补丁文件,例如补丁文件的名称,存放的路径等等。
第二部分,补丁文件的内容,例如补丁文件的格式。
第三部分,生成补丁的条件,默认情况下选取提交历史范围,为该范围的每个提交都生成一份补丁文件。
只需要记住条件和文件的选项。
文件:
--no-numbered:文件名中不包含数字。
--start-number:开始数字,默认值为1,所以生成的补丁文件有0001。
--numbered-files:文件名称只显示数字。
--suffix:文件的后缀,默认值为patch,可以设置为txt。
条件:
-n,--numbered:最多n个提交。
--ignore-if-in-upstream:忽略当前提交区间。
--root:为根提交生成补丁,由于根提交没有父提交,所以通过显示的内容也不是diff结果。
其他选项略。
2、发送
使用git send-email发送补丁。本质通过git send-email发送邮件,邮件的内容是补丁文件。
通过命令行方式发送邮件非常繁琐,它需要大约两部分配置,
第一部分是服务器相关的,邮件服务器地址,用户名,端口,协议等等。
第二部分是邮件内容相关的,邮件主题,邮件发送者,接收人,抄送者等等。
格式为:
git send-email [<options>] <file|directory|rev-list options>…
邮件相关:
--from=<address>:发送人
--to=<address>:收件人
--bcc=<address>:抄送人
--cc=<address>:抄送人
--reply-to=<address>:回复人
--subject=<string>:邮件的标题
其他不常见的选项略。
内容相关:
--8bit-encoding=<encoding>:略。
--compose-encoding=<encoding>:略。
--transfer-encoding=<encoding>:略。
其他不常见的选项略。
3、应用
Git应用补丁的指令有两个,apply,am。
引用apply命令手册的定义:
Reads the supplied diff output (i.e. "a patch") and applies it to files. When running from a subdirectory in a repository, patched paths outside the directory are ignored. With the --index option the patch is also applied to the index, and with the --cached option the patch is only applied to the index. Without these options, the command applies the patch only to files, and does not require them to be in a Git repository.
根据当前提交与父提交的比较结果生成补丁文件。在版本库应用补丁时,默认情况下只应用到工作目录,没有对应目录结构的被忽略,添加--index应用到索引,添加--cached只应用到索引。
This command applies the patch but does not create a commit.
命令不会产生提交。am命令会产生。
3.1 apply
格式为:
git apply [--stat] [--numstat] [--summary] [--check] [--index | --intent-to-add] [--3way] [--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] [--unsafe-paths] [<patch>…]
它只关注应用单个补丁这个过程。
它的选项分为三类,模拟运行,实际运行,和杂项。
最常见的是模拟运行和实际运行的选项。
模拟运行最常见的选项是check,实际运行最常见的选项directory,-3way。
模拟运行:
--stat:模拟运行,只显示统计信息
--numstat:模拟运行,只显示数字统计信息。
--summary:模拟运行,只显示统计信息中的总结部分
--check:模拟运行,检查是否存在冲突。
--index:与模拟运行的选项配合使用,表示会更新index。
--cached:TODO。
--intent-to-add:与模拟运行的选项配合使用,表示忽略新增文件类型的修改。
--apply:与模拟运行的选项配合使用,表示会实际运行。
实际运行:
--3way:与am的选项含义相同,冲突发生时,采用合并。
--reverse:逆序应用补丁。
--reject: 默认情况下是all or nothing,添加该选项后,只会拒绝失败的补丁,它不会对已经成功的补丁产生影响。
-p<n>,选取补丁文件路径的后几层级,例如a/b/c/d.patch,-p2之后,补丁的路径变为c/d.patch。感觉没啥用。
--directory=<root>:指定补丁的根目录。
--include,--exclude,指定包含哪些,排除哪些,值为补丁文件的路径集合。
其他:
-v, verbose公共选项,略。
--ignore-whitespace, --ignore-space-change, --whitespace=<action>,在am命令中已介绍过。
--inaccurate-eof:修复文件末尾比较时产生的Bug。
--recount:不相信原始的行号,重新计算行号,通常不会有人手动修改补丁文件吧。
--allow-binary-replacement,--binary:TODO。感觉无意义。
--unsafe-paths:TODO, 感觉无意义。
--unidiff-zero。
3.2 am
格式为:
git am [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--[no-]3way] [--interactive] [--committer-date-is-author-date] [--ignore-date] [--ignore-space-change | --ignore-whitespace] [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>] [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet] [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>] [(<mbox> | <Maildir>)…]
am的选项大致可以分为三类。
第一类是公共选项,例如-q quiet,--interactive, -[no-]utf-8。略。
第二类是与提交有关的,因为am会创建提交对象。
第三类是控制整个应用补丁过程的。
提交信息:
--signoff:添加签名,或者署名。
-S[keyid], --gpg-sign=<keyid>:gpg签名
--[no]message-id:是否将邮件中的messageId添加到commit日志信息中
--ignore-space-change, --ignore-whitespace, --white-space=<option>:是否忽略空格。
--committer-date-is-author-date:提交日期使用原始日期。
--ignore-date:忽略原始日期。
过程:
--3,--3way,应用补丁存在冲突时,使用合并策略。
--skip,跳过当前补丁。
-r, --resolved,冲突已解决。
--resolvedmsg=<msg>,冲突解决的日志信息。
--abort,中断, --quit,退出,--continue,继续。
其他:
--patch-format:指定补丁的格式,没什么用
--show-current-patch=[diff | raw],也没啥用。