gitdiffcore
名称
gitdiffcore - Tweaking diff output
概要
git diff *
描述
该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
比较两个“树”对象的内容;
在所有这些情况下,命令本身首先可选地通过在它们的命令行上给出的任何路径规格限制两组文件,并比较两组得到的文件中的对应路径。
pathspecs用于限制差异操作的世界。他们删除指定的路径名集外的文件对。例如,如果文件对的输入集包括:
:100644 100644 bcd1234... 0123456... M junkfile
但是命令调用是git diff-files myfile
,那么junkfile条目将从列表中删除,因为只考虑“myfile”。
比较结果从这些命令传递到内部称为“diffcore”的内容,格式类似于不使用-p选项时输出的格式。例如
in-place edit :100644 100644 bcd1234... 0123456... M file0 create :000000 100644 0000000... 1234567... A file4delete :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
这些按顺序应用。filepairs 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检查修改之前和之后文件内容之间的变化程度(即具有“bcd1234 ...”和“0123456 ...”作为其SHA-1内容ID的内容在上面的例子中)。原始内容的删除量和新素材的插入量相加在一起,如果超过“中断分数”,则文件对被分成两部分。中断分数默认为原始大小和结果大小的50%(即,如果编辑缩小文件,则使用结果的大小;如果编辑延长文件,则使用原始大小),并且可以通过在“-B”选项之后给出一个数字来进行定制(例如“-B75”告诉它使用75%)。
Diffcore-rename:用于检测重命名和复制
此转换用于检测重命名和副本,并由-M选项(以检测重命名)和-C选项(以检测副本)控制git diff-*
命令。如果输入包含这些文件对象:
: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中使用的相同“变化程度”算法用于确定两个文件是否“足够相似”,并且可以定制为使用与默认值50%相似的得分在“-M”或“-C”选项之后给出一个数字(例如“-M8”来告诉它使用8/10 = 80%)。
注意。当“-C”选项与--find-copies-harder
选项一起使用时,git diff-*
命令将未修改的文件对提供给diffcore机制以及修改的机制。这可以让复制检测器将未修改的文件视为复制源候选项,代价是速度较慢。如果没有--find-copies-harder
,git diff-*
只有当被复制的文件在相同的变更集中被修改时,命令才能检测到拷贝。
Diffcore-merge-broken:将完整的重写放在一起
此转换用于合并由diffcore-break打破的文件对,而不是通过diffcore-rename转换为rename/copy,返回到单个修改中。当使用diffcore-break时,它总是运行。
为了合并破损的文件对,它使用了diffcore-break和diffcore-rename使用的不同的“变化范围”计算。它只计算从原始的删除,并不计入插入。如果您从100行文档中只删除了10行,即使您添加了910行来创建新的1000行文档,也没有执行完全重写。diffcore-break打破了这种情况,以帮助diffcore-rename将文件对视为rename/copy检测的候选对象,但是如果文件对以这种方式打破与其他文件对不匹配以创建rename/copy,则该转换将它们合并回来进入原来的“修改”。
“extent of changes”参数可以从默认的80%调整(也就是说,除非超过80%的原始材料被删除,破碎的对会重新合并为一个修改),给第二个数字为-B选项,如下所示:
- -B50/60(给予50%的“破裂得分”以弥补破裂,使用60%作为diffcore-merge-broken)。
- -B/60(与上面相同,因为diffcore-break默认为50%)。
请注意,早期的实现会将一对损坏的对作为单独的创建和删除补丁程序。这是一种不必要的破解,最新的实现总是将所有破损的对重新合并到修改中,但是由此产生的修补程序输出格式不同,以便在完全重写的情况下更容易查看,方法是显示旧版本前缀的全部内容-
,随后新版本的全部内容都以前缀+
。
Diffcore-pickaxe:用于检测指定字符串的addition/deletion
此转换将文件对的集合限制为那些以某种方式在预映像和postimage之间更改指定字符串的文件对。-S <文本块>和-G <正则表达式>选项用于指定查找这些字符串的不同方式。
“-S <block of text>”检测文件对象,其前像和后像具有不同的指定文本块的出现次数。根据定义,它不会检测文件中的移动。另外,当变更集移动批量文件而不影响有趣的字符串时,diffcore-rename像往常一样踢,并-S
省略文件对(因为该字符串的出现次数在该重命名检测的文件对中没有变化)。使用时--pickaxe-regex
,将<文本块>视为扩展的POSIX正则表达式进行匹配,而不是文字字符串。
“-G <regular expression>”(助记符:grep)检测文本对,其文本差异的添加行或删除行与给定正则表达式匹配。这意味着它会检测文件中(或重命名检测认为是同一个文件)的移动,这是噪声。该实现运行差异两次,greps,这可能是相当昂贵的。
如果使用-S
或-G
不使用--pickaxe-all
,则只有符合其各自标准的文件对保留在输出中。何时--pickaxe-all
使用,如果即使一个文件对在变更集中与其各自的标准相匹配,整个变更集也会保留。此行为旨在使整个变更集环境中的审阅更容易。
Diffcore-order:用于根据文件名对输出进行排序
这用于根据用户(或项目)的口味重新排列文件对,并由git diff-*
命令的-O选项控制。
这需要一个文本文件,每个文件的行都是一个shell glob模式。匹配文件中较早行的全局模式的文件对在比较后一行匹配之前输出,并且最后输出不匹配任何全局模式的文件对。
举个例子,核心Git的一个典型的命令文件可能看起来像这样:
README Makefile Documentation*.h*.c t
也可以看看
git-diff[1], git-diff-files[1], git-diff-index[1], git-diff-tree[1], git-format-patch[1], git-log[1], gitglossary[7], The Git User’s Manual