设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.44.1 → 2.53.0 无变更
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 无更改
-
2.43.0
2023-11-20
- 2.32.1 → 2.42.4 无更改
-
2.32.0
2021-06-06
- 2.31.1 → 2.31.8 无更改
-
2.31.0
2021-03-15
- 2.21.1 → 2.30.9 无更改
-
2.21.0
2019-02-24
- 2.13.7 → 2.20.5 无更改
-
2.12.5
2017-09-22
- 2.10.5 → 2.11.4 无更改
-
2.9.5
2017-07-30
- 2.5.6 → 2.8.6 无更改
-
2.4.12
2017-05-05
- 2.1.4 → 2.3.10 无更改
-
2.0.5
2014-12-17
描述
diff 命令 git diff-index、git diff-files 和 git diff-tree 可以被指示在显示 diff 输出之前以非常规方式操作它们发现的差异。这种操作统称为“diffcore 转换”。这份简短的说明描述了它们是什么以及如何使用它们来生成比传统方式更易于理解的 diff 输出。
操作链
git diff-* 系列的工作方式是首先比较两组文件
-
git diff-index 比较“树”对象和工作目录的内容(当不使用
--cached标志时)或“树”对象和索引文件的内容(当使用--cached标志时); -
git diff-files 比较索引文件和工作目录的内容;
-
git diff-tree 比较两个“树”对象的内容;
在所有这些情况下,命令本身首先通过其命令行上给出的任何路径规范可选地限制两组文件,然后比较两组结果文件中的相应路径。
路径规范用于限制 diff 操作的范围。它们会移除指定路径集之外的文件对。例如,如果输入的文件对集包含
:100644 100644 bcd1234... 0123456... M junkfile
但命令调用是 git diff-files myfile,那么 junkfile 条目将从列表中删除,因为只考虑“myfile”。
比较结果以类似于不使用 -p 选项时输出的格式从这些命令传递到内部称为“diffcore”的机制。例如:
in-place edit :100644 100644 bcd1234... 0123456... M file0 create :000000 100644 0000000... 1234567... A file4 delete :100644 000000 1234567... 0000000... D file5 unmerged :000000 000000 0000000... 0000000... U file6
diffcore 机制接收此类比较结果的列表(每个结果都称为“文件对”,尽管此时它们都只涉及一个文件),并将此类列表转换为另一个列表。目前有 5 种这样的转换
-
diffcore-break
-
diffcore-rename
-
diffcore-merge-broken
-
diffcore-pickaxe
-
diffcore-order
-
diffcore-rotate
这些按顺序应用。git diff-* 命令找到的文件对集用作 diffcore-break 的输入,而 diffcore-break 的输出用作下一个转换的输入。最终结果然后传递给输出例程并生成 diff-raw 格式(参见 git diff-* 命令手册的“输出格式”部分)或 diff-patch 格式。
diffcore-break:用于拆分完整重写
链中的第二个转换是 diffcore-break,由 git diff-* 命令的 -B 选项控制。它用于检测代表“完整重写”的文件对,并将此类文件对拆分为代表删除和创建的两个文件对。例如,如果输入包含此文件对
:100644 100644 bcd1234... 0123456... M file0
如果它检测到文件“file0”被完全重写,它会将其更改为
:100644 000000 bcd1234... 0000000... D file0 :000000 100644 0000000... 0123456... A file0
为了拆分文件对,diffcore-break 检查文件修改前后内容(即,在上述示例中,SHA-1 内容 ID 为“bcd1234...”和“0123456...”的内容)之间更改的程度。原始内容的删除量和新材料的插入量相加,如果超过“中断分数”,则文件对被拆分为两个。中断分数默认为原始文件和结果文件两者中较小者大小的 50%(即,如果编辑使文件缩小,则使用结果文件大小;如果编辑使文件变长,则使用原始文件大小),并且可以通过在“-B”选项后给出一个数字来定制(例如,“-B75”表示使用 75%)。
diffcore-rename:用于检测重命名和复制
此转换用于检测重命名和复制,由 git diff-* 命令的 -M 选项(检测重命名)和 -C 选项(同时检测复制)控制。如果输入包含这些文件对
:100644 000000 0123456... 0000000... D fileX :000000 100644 0000000... 0123456... A file0
并且已删除文件 fileX 的内容与已创建文件 file0 的内容足够相似,则重命名检测将这些文件对合并并创建
:100644 100644 0123456... 0123456... R100 fileX file0
当使用“-C”选项时,修改文件的原始内容和已删除文件(如果使用“--find-copies-harder”选项,则也包括未修改文件)被视为重命名/复制操作中源文件的候选。如果输入是这些文件对,它们涉及一个修改过的文件 fileY 和一个新创建的文件 file0
:100644 100644 0123456... 1234567... M fileY :000000 100644 0000000... bcd3456... A file0
比较 fileY 的原始内容和 file0 的结果内容,如果它们足够相似,则将它们更改为
:100644 100644 0123456... 1234567... M fileY :100644 100644 0123456... bcd3456... C100 fileY file0
在重命名和复制检测中,使用与 diffcore-break 中相同的“更改程度”算法来确定两个文件是否“足够相似”,并且可以通过在“-M”或“-C”选项后给出一个数字(例如,“-M8”表示使用 8/10 = 80%)来定制,以使用与默认 50% 不同的相似度分数。
请注意,当重命名检测开启但复制和拆分检测都关闭时,重命名检测会添加一个初步步骤,首先检查文件是否在目录之间移动而文件名保持不变。如果一个文件被添加到某个目录,其内容与一个从不同目录中删除的同名文件足够相似,它将它们标记为重命名并将其排除在后续的二次步骤之外(该步骤成对比较所有不匹配的文件以找到“最佳”匹配,由最高内容相似度决定)。因此,例如,如果已删除的 docs/ext.txt 和已添加的 docs/config/ext.txt 足够相似,它们将被标记为重命名,并阻止可能与已删除的 docs/ext.txt 更相似的已添加 docs/ext.md 在后续步骤中被视为重命名目标。因此,初步的“匹配相同文件名”步骤使用更高的阈值将文件对标记为重命名,并停止考虑其他候选以获得更好的匹配。在此初步阶段,每个文件最多进行一次比较;因此,如果在精确重命名检测之后,在整个目录层次结构中仍然存在几个 ext.txt 文件,则可能会跳过这些文件的此初步步骤。
注意。当“-C”选项与 --find-copies-harder 选项一起使用时,git diff-* 命令将未修改的文件对以及修改过的文件对都提供给 diffcore 机制。这使得复制检测器可以将未修改的文件视为复制源候选,但代价是会使其变慢。如果没有 --find-copies-harder,git diff-* 命令只能在被复制的文件恰好在同一更改集中被修改时检测到复制。
diffcore-merge-broken:用于将完整重写重新组合
此转换用于合并被 diffcore-break 拆分但未被 diffcore-rename 转换为重命名/复制的文件对,将其重新合并为单个修改。当使用 diffcore-break 时,此转换总是运行。
为了将拆分的文件对重新合并,它使用与 diffcore-break 和 diffcore-rename 所用的不同的“更改程度”计算方法。它只计算从原始文件中删除的部分,而不计算插入的部分。如果您只从一个 100 行的文档中删除了 10 行,即使您添加了 910 行新内容来创建一个新的 1000 行文档,您也没有进行完整的重写。diffcore-break 会拆分这种情况,以帮助 diffcore-rename 将此类文件对视为重命名/复制检测的候选,但如果以这种方式拆分的文件对没有与其他文件对匹配以创建重命名/复制,则此转换会将它们重新合并回原始的“修改”。
“更改程度”参数可以从默认的 80%(即,除非原始材料被删除超过 80%,否则拆分的对将被重新合并为单个修改)通过给 -B 选项第二个数字来调整,例如:
-
-B50/60(给 diffcore-break 50% 的“中断分数”,给 diffcore-merge-broken 使用 60%)。
-
-B/60(与上面相同,因为 diffcore-break 默认为 50%)。
请注意,早期的实现将拆分的对作为单独的创建和删除补丁留下。这是一个不必要的黑客行为,最新的实现总是将所有拆分的对重新合并为修改,但是对于这种完整的重写情况,生成的补丁输出格式不同,以便于审查,它会显示以 - 为前缀的旧版本全部内容,然后是所有以 + 为前缀的新版本内容。
diffcore-pickaxe:用于检测指定字符串的添加/删除
此转换将文件对集合限制为那些以特定方式更改前像和后像之间指定字符串的文件对。-S<block-of-text> 和 -G<regular-expression> 选项用于指定查找这些字符串的不同方式。
“-S<block-of-text>”检测那些前像和后像中指定文本块出现次数不同的文件对。根据定义,它不会检测文件内部移动。此外,当一个变更集整体移动一个文件而不影响感兴趣的字符串时,diffcore-rename 会像往常一样启动,并且 -S 会省略该文件对(因为该字符串在该重命名检测到的文件对中出现的次数没有改变)。与 --pickaxe-regex 一起使用时,将 <block-of-text> 视为扩展的 POSIX 正则表达式进行匹配,而不是字面字符串。
“-G<regular-expression>”(助记符:grep)检测其文本 diff 中有添加或删除行与给定正则表达式匹配的文件对。这意味着它将检测文件内部(或重命名检测认为是同一文件)的移动,这是一种噪音。实现运行 diff 两次并进行 grep,这可能非常昂贵。为了加快速度,没有 textconv 过滤器的二进制文件将被忽略。
当 -S 或 -G 在没有 --pickaxe-all 的情况下使用时,只有那些符合其各自标准的文件对才保留在输出中。当使用 --pickaxe-all 时,如果一个变更集中即使有一个文件对符合其各自标准,则整个变更集都会保留。此行为旨在使在整个变更集上下文中审查更改变得更容易。
diffcore-order:用于根据文件名对输出进行排序
这用于根据用户的(或项目的)偏好重新排序文件对,由 git diff-* 命令的 -O 选项控制。
这需要一个文本文件,其中每行都是一个 shell glob 模式。与文件中较早的 glob 模式匹配的文件对在与较晚的行匹配的文件对之前输出,而与任何 glob 模式都不匹配的文件对最后输出。
例如,Git 核心的典型 orderfile 可能看起来像这样
README Makefile Documentation *.h *.c t
diffcore-rotate:用于更改输出从哪个路径开始
此转换接受一个路径名,并旋转文件对集合,以便给定路径名的文件对排在第一位,可选地丢弃在其之前的路径。这用于实现 --skip-to 和 --rotate-to 选项。当指定的路径名不在文件对集合中时,会发生错误,但在与“git log”系列命令一起使用时,报错并无益处,因为期望“git log”命令显示的每个提交都修改给定路径是不合理的。因此,当与“git log”一起使用时,输出从与给定路径名排序相同或紧随其后的第一个文件对开始。
此转换与 diffcore-order 结合使用会产生意想不到的结果,因为当 diffcore-order 生效时,此转换的输入可能未排序。