--distributed-even-if-your-workflow-isnt
中文 (简体) ▾ 主题 ▾ 最新版本 ▾ git-diff-index 最后更新于 2.48.0

名称

git-diff-index - 将树与工作树或索引进行比较

概要

git diff-index [-m] [--cached] [--merge-base] [<common-diff-options>] <tree-ish> [<path>…​]

描述

将树对象中找到的 blob 的内容和模式与工作树中相应的已跟踪文件或索引中相应的路径进行比较。如果存在 <path> 参数,则仅比较与这些模式匹配的路径。否则,将比较所有已跟踪的文件。

选项

-p
-u
--patch

生成补丁(请参阅使用 -p 生成补丁文本)。

-s
--no-patch

禁止来自 diff 机制的所有输出。对于像 git show 这样默认显示补丁的命令,用来抑制其输出,或者取消别名中命令行上较早的 --patch, --stat 等选项的效果很有用。

-U<n>
--unified=<n>

生成带有 <n> 行上下文的差异,而不是通常的三行。隐含 --patch

--output=<file>

输出到指定文件,而不是标准输出。

--output-indicator-new=<char>
--output-indicator-old=<char>
--output-indicator-context=<char>

指定用于指示生成的补丁中的新行、旧行或上下文行的字符。通常,它们分别是 +- 和 ' '。

--raw

以原始格式生成差异。这是默认设置。

--patch-with-raw

-p --raw 的同义词。

--indent-heuristic

启用启发式算法,该算法会移动差异块边界,使补丁更容易阅读。这是默认设置。

--no-indent-heuristic

禁用缩进启发式算法。

--minimal

花费额外的时间来确保生成尽可能小的差异。

--patience

使用 "patience diff" 算法生成差异。

--histogram

使用 "histogram diff" 算法生成差异。

--anchored=<text>

使用 "anchored diff" 算法生成差异。

此选项可以指定多次。

如果一行同时存在于源和目标中,仅存在一次,并且以 <text> 开头,则此算法会尝试阻止它作为删除或添加出现在输出中。它在内部使用 "patience diff" 算法。

--diff-algorithm=(patience|minimal|histogram|myers)

选择一种差异算法。变体如下

default
myers

基本的贪婪差异算法。目前,这是默认值。

minimal

花费额外的时间来确保生成尽可能小的差异。

patience

在生成补丁时使用 "patience diff" 算法。

histogram

此算法扩展了耐心算法以“支持低频常见的元素”。

例如,如果您将 diff.algorithm 变量配置为非默认值,并且想要使用默认值,则必须使用 --diff-algorithm=default 选项。

--stat[=<width>[,<name-width>[,<count>]]]

生成 diffstat。默认情况下,文件名部分将使用尽可能多的空间,其余空间用于图形部分。最大宽度默认为终端宽度,或者如果未连接到终端,则为 80 列,并且可以通过 <width> 覆盖。文件名部分的宽度可以通过在逗号后给出另一个宽度 <name-width> 或通过设置 diff.statNameWidth=<name-width> 来限制。图形部分的宽度可以通过使用 --stat-graph-width=<graph-width> 或通过设置 diff.statGraphWidth=<graph-width> 来限制。使用 --stat--stat-graph-width 会影响生成统计图的所有命令,而设置 diff.statNameWidthdiff.statGraphWidth 不会影响 git format-patch。通过给出第三个参数 <count>,您可以将输出限制为前 <count> 行,如果还有更多行,则后跟 ...

这些参数也可以使用 --stat-width=<width>--stat-name-width=<name-width>--stat-count=<count> 单独设置。

--compact-summary

在 diffstat 中输出扩展标头信息的简明摘要,例如文件创建或删除(“new”或“gone”,如果是符号链接,则可选 +l)和模式更改(+x-x 分别用于添加或删除可执行位)。信息放在文件名部分和图形部分之间。隐含 --stat

--numstat

类似于 --stat,但以十进制表示法显示添加和删除的行数,并显示没有缩写的路径名,使其更便于机器读取。对于二进制文件,输出两个 -,而不是说 0 0

--shortstat

仅输出包含已修改文件总数以及添加和删除的行数的 --stat 格式的最后一行。

-X [<param>,...]
--dirstat[=<param>,...]

输出每个子目录的相对更改量的分布。可以通过传递逗号分隔的参数列表来定制 --dirstat 的行为。默认值由 diff.dirstat 配置变量控制(请参阅 git-config[1])。以下参数可用

changes

通过计算从源中删除或添加到目标中的行数来计算 dirstat 数字。 这忽略了文件内纯代码移动的数量。 换句话说,重新排列文件中的行与其它更改相比,不被计入那么多。 这是未给定任何参数时的默认行为。

lines

通过执行常规的基于行的 diff 分析,并汇总删除/添加的行数来计算 dirstat 数字。(对于二进制文件,则计算 64 字节的块,因为二进制文件没有自然的行概念)。这是一个比 changes 行为更耗费资源的 --dirstat 行为,但它会将文件中的重新排列的行与其它更改一样计入。 结果输出与您从其它 --*stat 选项获得的结果一致。

files

通过计算已更改文件的数量来计算 dirstat 数字。每个已更改文件在 dirstat 分析中都平等计数。 这是计算成本最低的 --dirstat 行为,因为它根本不必查看文件内容。

cumulative

同时计算父目录中子目录的更改。 请注意,使用 cumulative 时,报告的百分比之和可能超过 100%。 可以使用 noncumulative 参数指定默认(非累积)行为。

<limit>

整数参数指定一个截止百分比(默认为 3%)。 贡献小于此百分比的更改的目录不会在输出中显示。

示例:以下命令将计算已更改的文件,同时忽略已更改文件总量的 10% 以下的目录,并将子目录计数累积到父目录中:--dirstat=files,10,cumulative

--cumulative

--dirstat=cumulative 的同义词。

--dirstat-by-file[=<param>,...]

--dirstat=files,<param>,... 的同义词。

--summary

输出扩展头信息的精简摘要,例如创建、重命名和模式更改。

--patch-with-stat

-p --stat 的同义词。

-z

当给出了 --raw--numstat--name-only--name-status 时,不要修改路径名,并使用 NUL 作为输出字段终止符。

如果没有此选项,具有“不寻常”字符的路径名将按照配置变量 core.quotePath 的说明进行引用(请参阅 git-config[1])。

--name-only

仅显示后映像树中每个已更改文件的名称。 文件名通常以 UTF-8 编码。 有关更多信息,请参阅 git-log[1] 手册页中关于编码的讨论。

--name-status

仅显示每个已更改文件的名称和状态。 有关状态字母的含义,请参阅 --diff-filter 选项的说明。 就像 --name-only 一样,文件名通常以 UTF-8 编码。

--submodule[=<format>]

指定子模块中差异的显示方式。 当指定 --submodule=short 时,使用 short 格式。 此格式仅显示范围开始和结束时的提交名称。 当指定 --submodule--submodule=log 时,使用 log 格式。 此格式列出范围内的提交,如 git-submodule[1] summary 所做的那样。 当指定 --submodule=diff 时,使用 diff 格式。 此格式显示提交范围之间子模块内容中更改的内联差异。 默认为 diff.submodule,如果未设置配置选项,则默认为 short 格式。

--color[=<when>]

显示彩色差异。 --color(即没有 =<when>)与 --color=always 相同。 <when> 可以是 alwaysneverauto 之一。

--no-color

关闭彩色差异。 它与 --color=never 相同。

--color-moved[=<mode>]

移动的代码行以不同的颜色显示。 如果未给定选项,则 <mode> 默认为 no,如果给定没有模式的选项,则默认为 zebra。 模式必须是以下之一

no

移动的行不会被突出显示。

default

zebra 的同义词。 将来可能会更改为更合理的模式。

plain

在一个位置添加并在另一个位置删除的任何行都将使用 color.diff.newMoved 着色。 类似地,color.diff.oldMoved 将用于在差异中的其它位置添加的已删除的行。 此模式会拾取任何移动的行,但在确定代码块是否在没有排列的情况下移动的审查中,它不是很有用。

blocks

贪婪地检测至少 20 个字母数字字符的移动文本块。 检测到的块使用 color.diff.(old|new)Moved 颜色绘制。 相邻的块无法区分。

zebra

移动的文本块的检测方式与 blocks 模式相同。 这些块使用 color.diff.(old|new)Moved 颜色或 color.diff.(old|new)MovedAlternative 颜色绘制。 两种颜色之间的变化表明检测到了一个新的块。

dimmed-zebra

zebra 类似,但对移动的代码中不感兴趣的部分执行额外的变暗。 两个相邻块的边界线被认为是有趣的,其余部分是不感兴趣的。 dimmed_zebra 是一个已弃用的同义词。

--no-color-moved

关闭移动检测。 这可用于覆盖配置设置。 它与 --color-moved=no 相同。

--color-moved-ws=<mode>,...

这配置了在为 --color-moved 执行移动检测时如何忽略空格。 这些模式可以作为逗号分隔的列表给出

no

执行移动检测时不忽略空格。

ignore-space-at-eol

忽略 EOL 处的空格更改。

ignore-space-change

忽略空格数量的变化。 这会忽略行尾的空格,并将所有其它一个或多个空格字符的序列视为等效。

ignore-all-space

比较行时忽略空格。 即使一行有空格而另一行没有空格,这也会忽略差异。

allow-indentation-change

最初忽略移动检测中的任何空格,然后仅当每行的空格更改相同时,才将移动的代码块分组到一个块中。 这与其它模式不兼容。

--no-color-moved-ws

执行移动检测时不忽略空格。 这可用于覆盖配置设置。 它与 --color-moved-ws=no 相同。

--word-diff[=<mode>]

默认情况下,单词由空格分隔; 请参阅下面的 --word-diff-regex<mode> 默认为 plain,并且必须是以下之一

color

仅使用颜色突出显示已更改的单词。 意味着 --color

plain

将单词显示为 [-removed-]{added}。 如果定界符出现在输入中,则不尝试转义定界符,因此输出可能不明确。

porcelain

使用特殊的基于行的格式,旨在供脚本使用。 添加/删除/未更改的运行以通常的统一 diff 格式打印,行首以 +/-/` ` 字符开头并延伸到行尾。 输入中的换行符由其自身行上的波浪号 ~ 表示。

none

再次禁用单词差异。

请注意,尽管第一个模式的名称如此,但如果启用,则所有模式都使用颜色来突出显示已更改的部分。

--word-diff-regex=<regex>

使用 <regex> 来决定什么是单词,而不是将非空格的运行视为一个单词。 除非已经启用,否则也意味着 --word-diff

<regex> 的每个非重叠匹配项都被认为是一个单词。 这些匹配项之间的任何内容都被认为是空格,并且为了查找差异的目的而被忽略(!)。 您可能想要将 |[^[:space:]] 附加到您的正则表达式,以确保它匹配所有非空格字符。 包含换行符的匹配项会在换行符处被静默截断(!)。

例如,--word-diff-regex=. 会将每个字符视为一个单词,并相应地逐个字符地显示差异。

也可以通过差异驱动程序或配置选项设置正则表达式,请参阅 gitattributes[5]git-config[1]。 显式地给出它会覆盖任何差异驱动程序或配置设置。 差异驱动程序会覆盖配置设置。

--color-words[=<regex>]

等效于 --word-diff=color 加上(如果指定了正则表达式)--word-diff-regex=<regex>

--no-renames

关闭重命名检测,即使配置文件默认开启此功能。

--[no-]rename-empty

是否使用空 blob 作为重命名的源。

--check

如果更改引入了冲突标记或空白错误,则发出警告。 空白错误的判断由 core.whitespace 配置控制。 默认情况下,尾随空格(包括仅由空格组成的行)和行初始缩进中紧跟在制表符前的空格字符被认为是空白错误。 如果发现问题,则以非零状态退出。 与 --exit-code 不兼容。

--ws-error-highlight=<kind>

突出显示 diff 中 contextoldnew 行的空白错误。 多个值用逗号分隔,none 重置先前的值,default 将列表重置为 newallold,new,context 的简写。 如果未给出此选项,并且未设置配置变量 diff.wsErrorHighlight,则仅突出显示 new 行中的空白错误。 空白错误用 color.diff.whitespace 着色。

--full-index

生成补丁格式输出时,在 "index" 行上显示完整的 pre- 和 post-image blob 对象名称,而不是前几个字符。

--binary

除了 --full-index 之外,还输出可以使用 git-apply 应用的二进制 diff。 隐含 --patch

--abbrev[=<n>]

在 diff-raw 格式输出和 diff-tree 标头行中,不显示完整的 40 字节十六进制对象名称,而是显示至少 <n> 位十六进制数字长的、唯一引用该对象的最短前缀。 在 diff-patch 输出格式中,--full-index 具有更高的优先级,即,如果指定了 --full-index,则无论 --abbrev 如何,都将显示完整的 blob 名称。 可以使用 --abbrev=<n> 指定非默认的位数。

-B[<n>][/<m>]
--break-rewrites[=[<n>][/<m>]]

将完整的重写更改分解为删除和创建的对。 这有两个目的:

它影响了将文件的完全重写更改视为一系列删除和插入混合在一起的方式,其中只有极少数行恰好在文本上与上下文匹配,而是将其视为删除所有旧内容,然后插入所有新内容,数字 *<m>* 控制 -B 选项的这个方面(默认为 60%)。 -B/70% 指定原始内容中少于 30% 的内容保留在结果中,Git 才会将其视为完全重写(即,否则生成的补丁将是一系列删除和插入混合在一起,并带有上下文行)。

-M 一起使用时,完全重写的文件也被认为是重命名的源(通常 -M 仅将消失的文件视为重命名的源),数字 *<n>* 控制 -B 选项的这个方面(默认为 50%)。 -B20% 指定与文件大小相比,添加和删除更改了 20% 或更多的文件有资格被视为可能重命名到另一个文件的源。

-M[<n>]
--find-renames[=<n>]

检测重命名。 如果指定了 *<n>*,则它是相似度索引的阈值(即,与文件大小相比,添加/删除的数量)。 例如,-M90% 表示如果超过 90% 的文件未更改,则 Git 应将删除/添加对视为重命名。 如果没有 % 符号,则该数字应被读取为小数,小数点位于其前面。 即,-M5 变为 0.5,因此与 -M50% 相同。 类似地,-M05-M5% 相同。 要将检测限制为精确重命名,请使用 -M100%。 默认相似度索引为 50%。

-C[<n>]
--find-copies[=<n>]

检测副本以及重命名。 另请参见 --find-copies-harder。 如果指定了 *<n>*,则其含义与 -M<n> 相同。

--find-copies-harder

出于性能原因,默认情况下,-C 选项仅在副本的原始文件在同一变更集中被修改时才查找副本。 此标志使命令检查未修改的文件作为副本的源的候选对象。 对于大型项目,这是一个非常昂贵的操作,因此请谨慎使用。 给出多个 -C 选项具有相同的效果。

-D
--irreversible-delete

省略删除的 pre-image,即,仅打印标头,而不打印 pre-image 和 /dev/null 之间的 diff。 生成的补丁并非旨在与 patchgit apply 一起应用; 这仅适用于只想专注于查看更改后文本的人员。 此外,输出显然缺乏足够的信息来反向应用此类补丁,即使是手动应用,因此该选项的名称如此。

-B 一起使用时,也省略删除/创建对的删除部分的 pre-image。

-l<num>

-M-C 选项涉及一些初步步骤,这些步骤可以廉价地检测重命名/副本的子集,然后是一个详尽的回退部分,该部分将所有剩余的未配对的目标与所有相关的源进行比较。 (对于重命名,只有剩余的未配对源是相关的;对于副本,所有原始源都是相关的。) 对于 N 个源和目标,此穷举检查为 O(N^2)。 如果所涉及的源/目标文件数超过指定的数量,则此选项会阻止重命名/副本检测的穷举部分运行。 默认为 diff.renameLimit。 请注意,值 0 被视为无限制。

--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]

仅选择已添加 (A)、已复制 (C)、已删除 (D)、已修改 (M)、已重命名 (R)、类型已更改(即,常规文件、符号链接、子模块、…​)(T)、未合并 (U)、未知 (X) 或其配对已断开 (B) 的文件。 可以使用过滤器字符的任意组合(包括无)。 当 *(全选或全不选)添加到组合时,如果比较中存在任何符合其他条件的文件,则选择所有路径; 如果没有符合其他条件的文件,则不选择任何内容。

此外,这些大写字母可以小写以排除。 例如,--diff-filter=ad 排除已添加和已删除的路径。

请注意,并非所有差异都可以包含所有类型。 例如,如果禁用了这些类型的检测,则不会出现复制和重命名的条目。

-S<string>

查找更改文件中指定 *<string>* 的出现次数(即,添加/删除)的差异。 专为脚本编写者使用。

当您查找确切的代码块(如结构)时,并且想知道该块自首次出现以来的历史记录时,它非常有用:迭代使用该功能将 pre-image 中感兴趣的块反馈到 -S 中,并继续进行,直到获得该块的第一个版本。

还会搜索二进制文件。

-G<regex>

查找其补丁文本包含与 *<regex>* 匹配的添加/删除行的差异。

为了说明 -S<regex> --pickaxe-regex-G<regex> 之间的区别,请考虑一个提交,该提交在同一文件中具有以下差异:

+    return frotz(nitfol, two->ptr, 1, 0);
...
-    hit = frotz(nitfol, mf2.ptr, 1, 0);

虽然 git log -G"frotz\(nitfol" 会显示此提交,但 git log -S"frotz\(nitfol" --pickaxe-regex 不会(因为该字符串的出现次数没有改变)。

除非提供了 --text,否则将忽略没有 textconv 过滤器的二进制文件的补丁。

有关更多信息,请参见 gitdiffcore[7] 中的 *pickaxe* 条目。

--find-object=<object-id>

查找更改指定对象出现次数的差异。 与 -S 类似,只是参数不同,因为它不搜索特定字符串,而是搜索特定对象 ID。

该对象可以是 blob 或子模块提交。 它意味着 git-log 中的 -t 选项也用于查找树。

--pickaxe-all

-S-G 找到更改时,显示该变更集中的所有更改,而不仅仅是包含 *<string>* 中更改的文件。

--pickaxe-regex

将提供给 -S 的 *<string>* 视为要匹配的扩展 POSIX 正则表达式。

-O<orderfile>

控制文件在输出中出现的顺序。 这会覆盖 diff.orderFile 配置变量(请参见 git-config[1])。 要取消 diff.orderFile,请使用 -O/dev/null

输出顺序由 *<orderfile>* 中 glob 模式的顺序确定。 首先输出所有路径名与第一个模式匹配的文件,接下来输出所有路径名与第二个模式匹配的文件(但不与第一个匹配),依此类推。 最后输出所有路径名与任何模式都不匹配的文件,就像文件末尾有一个隐式的匹配所有模式一样。 如果多个路径名具有相同的等级(它们与相同的模式匹配但不与更早的模式匹配),则它们彼此之间的输出顺序为正常顺序。

*<orderfile>* 的解析方式如下:

  • 忽略空行,因此它们可以用作分隔符以提高可读性。

  • 忽略以井号("#")开头的行,因此它们可以用作注释。 如果模式以井号开头,请在模式开头添加反斜杠("\")。

  • 其他每一行都包含一个模式。

模式具有与用于 fnmatch(3) 的模式相同的语法和语义,但没有 FNM_PATHNAME 标志,除非删除任何数量的最终路径名组件与模式匹配,否则路径名也与模式匹配。 例如,模式 "foo*bar" 匹配 "fooasdfbar" 和 "foo/bar/baz/asdf",但不匹配 "foobarx"。

--skip-to=<file>
--rotate-to=<file>

从输出中丢弃命名 *<file>* 之前的文件(即,*跳到*),或者将它们移动到输出的末尾(即,*旋转到*)。 这些选项最初是为了 git difftool 命令的使用而发明的,否则可能不太有用。

-R

交换两个输入; 也就是说,显示从索引或磁盘上的文件到树内容的差异。

--relative[=<path>]
--no-relative

从项目的子目录运行时,可以告知它排除目录外的更改,并使用此选项显示相对于该目录的路径名。 当您不在子目录中(例如,在裸存储库中)时,可以通过给出一个 <path> 作为参数来指定要使输出相对于哪个子目录。 --no-relative 可用于抵消 diff.relative 配置选项和先前的 --relative

-a
--text

将所有文件视为文本。

--ignore-cr-at-eol

在进行比较时忽略行尾的回车符。

--ignore-space-at-eol

忽略 EOL 处的空格更改。

-b
--ignore-space-change

忽略空格数量的变化。 这会忽略行尾的空格,并将所有其它一个或多个空格字符的序列视为等效。

-w
--ignore-all-space

比较行时忽略空格。 即使一行有空格而另一行没有空格,这也会忽略差异。

--ignore-blank-lines

忽略所有行都为空白的更改。

-I<regex>
--ignore-matching-lines=<regex>

忽略所有行都匹配 *<regex>* 的更改。此选项可以多次指定。

--inter-hunk-context=<number>

显示差异块之间的上下文,最多为指定的 *<number>* 行,从而融合彼此接近的块。 默认为 diff.interHunkContext,如果未设置配置选项,则为 0。

-W
--function-context

将整个函数显示为每个更改的上下文行。函数名称的确定方式与 git diff 计算补丁块标题的方式相同(请参阅 gitattributes[5] 中的“定义自定义块标题”)。

--exit-code

使程序以类似于 diff(1) 的代码退出。 也就是说,如果存在差异,则以 1 退出;0 表示没有差异。

--quiet

禁用程序的所有输出。 意味着 --exit-code。 禁用外部差异助手的执行,这些助手的退出代码不可信,即它们各自的配置选项 diff.trustExitCodediff.<driver>.trustExitCode 或环境变量 GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE 为 false。

--ext-diff

允许执行外部差异助手。 如果使用 gitattributes[5] 设置了外部差异驱动程序,则需要将此选项与 git-log[1] 及其朋友一起使用。

--no-ext-diff

不允许使用外部差异驱动程序。

--textconv
--no-textconv

允许(或禁止)在比较二进制文件时运行外部文本转换过滤器。 有关详细信息,请参见 gitattributes[5]。 由于 textconv 过滤器通常是单向转换,因此生成的差异适合人类使用,但不能应用。 因此,默认情况下,仅为 git-diff[1]git-log[1] 启用 textconv 过滤器,但不为 git-format-patch[1] 或差异管道命令启用。

--ignore-submodules[=(none|untracked|dirty|all)]

忽略差异生成中对子模块的更改。 all 是默认值。 使用 none 会在子模块包含未跟踪或已修改的文件或者其 HEAD 与超级项目中记录的提交不同时,将子模块视为已修改,并且可用于覆盖 git-config[1]gitmodules[5]ignore 选项的任何设置。 使用 untracked 时,如果子模块仅包含未跟踪的内容,则不会将其视为脏的(但仍会扫描已修改的内容)。 使用 dirty 会忽略对子模块工作树的所有更改,仅显示对超级项目中存储的提交的更改(这是 1.7.0 之前的行为)。 使用 all 会隐藏对子模块的所有更改。

--src-prefix=<prefix>

显示给定的源 *<prefix>* 而不是“a/”。

--dst-prefix=<prefix>

显示给定的目标 *<prefix>* 而不是“b/”。

--no-prefix

不显示任何源或目标前缀。

--default-prefix

使用默认的源和目标前缀(“a/”和“b/”)。 这将覆盖配置变量,例如 diff.noprefixdiff.srcPrefixdiff.dstPrefixdiff.mnemonicPrefix(请参见 git-config[1])。

--line-prefix=<prefix>

在每行输出前添加一个额外的 *<prefix>*。

--ita-invisible-in-index

默认情况下,由 git add -N 添加的条目在 git diff 中显示为现有的空文件,在 git diff --cached 中显示为新文件。 此选项使条目在 git diff 中显示为新文件,在 git diff --cached 中显示为不存在的文件。 可以使用 --ita-visible-in-index 撤消此选项。 这两个选项都是实验性的,将来可能会被删除。

有关这些常见选项的更详细说明,另请参见 gitdiffcore[7]

<tree-ish>

要进行差异比较的树对象的 ID。

--cached

根本不考虑磁盘上的文件。

--merge-base

不直接比较 <tree-ish>,而是使用 <tree-ish> 和 HEAD 之间的合并基础。 <tree-ish> 必须是提交。

-m

默认情况下,索引中记录但未检出的文件报告为已删除。 此标志使 *git diff-index* 说明所有未检出的文件都是最新的。

原始输出格式

来自 git-diff-indexgit-diff-treegit-diff-filesgit diff --raw 的原始输出格式非常相似。

这些命令都比较两组事物;比较的内容有所不同

git-diff-index <tree-ish>

比较 *<tree-ish>* 和文件系统上的文件。

git-diff-index --cached <tree-ish>

比较 *<tree-ish>* 和索引。

git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]

比较由两个参数命名的树。

git-diff-files [<pattern>...]

比较索引和文件系统上的文件。

git-diff-tree 命令首先打印被比较内容的哈希值来开始其输出。 之后,所有命令都为每个已更改的文件打印一行输出。

输出行的格式如下

in-place edit  :100644 100644 bcd1234 0123456 M file0
copy-edit      :100644 100644 abcd123 1234567 C68 file1 file2
rename-edit    :100644 100644 abcd123 1234567 R86 file1 file3
create         :000000 100644 0000000 1234567 A file4
delete         :100644 000000 1234567 0000000 D file5
unmerged       :000000 000000 0000000 0000000 U file6

也就是说,从左到右

  1. 一个冒号。

  2. “src”的模式; 如果是创建或未合并,则为 000000。

  3. 一个空格。

  4. “dst”的模式; 如果是删除或未合并,则为 000000。

  5. 一个空格。

  6. “src”的 sha1; 如果是创建或未合并,则为 0{40}。

  7. 一个空格。

  8. “dst”的 sha1; 如果是删除、未合并或“工作树与索引不同步”,则为 0{40}。

  9. 一个空格。

  10. 状态,后跟可选的“score”数字。

  11. 一个制表符或一个 NUL,当使用 -z 选项时。

  12. “src”的路径

  13. 一个制表符或一个 NUL,当使用 -z 选项时; 仅对于 C 或 R 存在。

  14. “dst”的路径; 仅对于 C 或 R 存在。

  15. 一个 LF 或一个 NUL,当使用 -z 选项时,以终止记录。

可能的status字母是

  • A:添加文件

  • C:将文件复制到新文件中

  • D:删除文件

  • M:修改文件的内容或模式

  • R:重命名文件

  • T:文件类型发生更改(常规文件、符号链接或子模块)

  • U:文件未合并(必须先完成合并才能提交)

  • X:“未知”更改类型(很可能是 bug,请报告)

状态字母 CR 始终后跟一个分数(表示移动或复制的源和目标之间的相似百分比)。 状态字母 M 可能会后跟一个分数(表示文件重写的差异百分比)。

如果文件系统上的文件与索引不同步,则“dst”的 sha1 显示为全 0。

示例

:100644 100644 5be4a4a 0000000 M file.c

如果不使用 -z 选项,则具有“不寻常”字符的路径名会按照配置变量 core.quotePath 的说明进行引用(请参见 git-config[1])。 使用 -z 时,文件名将逐字输出,并且该行以 NUL 字节结尾。

合并的差异格式

git-diff-treegit-diff-filesgit-diff --raw 可以使用 -c--cc 选项来为合并提交生成差异输出。 输出与上述格式的不同之处在于

  1. 每个父级都有一个冒号

  2. 有更多的“src”模式和“src”sha1

  3. 状态是每个父级的串联状态字符

  4. 没有可选的“score”数字

  5. 文件的制表符分隔的路径名

对于 -c--cc,即使文件在历史的任何一方被重命名,也只显示目标或最终路径。 对于 --combined-all-paths,显示每个父级中路径的名称,后跟合并提交中路径的名称。

没有 --combined-all-paths-c--cc 的示例

::100644 100644 100644 fabadb8 cc95eb0 4866510 MM	desc.c
::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM	bar.sh
::100644 100644 100644 e07d6c5 9042e82 ee91881 RR	phooey.c

--combined-all-paths 添加到 -c--cc 时 的示例

::100644 100644 100644 fabadb8 cc95eb0 4866510 MM	desc.c	desc.c	desc.c
::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM	foo.sh	bar.sh	bar.sh
::100644 100644 100644 e07d6c5 9042e82 ee91881 RR	fooey.c	fuey.c	phooey.c

请注意,*合并差异* 仅列出从所有父级修改的文件。

使用 -p 生成补丁文本

使用 -p 选项运行 git-diff[1]git-log[1]git-show[1]git-diff-index[1]git-diff-tree[1]git-diff-files[1] 会生成补丁文本。 可以通过 GIT_EXTERNAL_DIFFGIT_DIFF_OPTS 环境变量(请参见 git[1])以及 diff 属性(请参见 gitattributes[5])自定义补丁文本的创建。

-p 选项产生的内容与传统的差异格式略有不同

  1. 它前面有一个“git diff”标头,如下所示

    diff --git a/file1 b/file2

    除非涉及重命名/复制,否则 a/b/ 文件名相同。 尤其是,即使对于创建或删除,也不会使用 /dev/null 代替 a/b/ 文件名。

    当涉及重命名/复制时,file1file2 分别显示重命名/复制的源文件的名称和重命名/复制产生的文件名。

  2. 它后面跟着一个或多个扩展的标头行

    旧模式 <mode> 新模式 <mode> 已删除文件模式 <mode> 新文件模式 <mode> 复制自 <path> 复制到 <path> 重命名自 <path> 重命名到 <path> 相似度指数 <number> 相异度指数 <number> 索引 <hash>..<hash> <mode>

    文件模式 <mode> 以 6 位八进制数打印,包括文件类型和文件权限位。

    扩展标头中的路径名不包括 a/b/ 前缀。

    相似度指数是不变行的百分比,相异度指数是已更改行的百分比。 这是一个向下舍入的整数,后跟百分号。 因此,100% 的相似度指数值保留给两个相等的文件,而 100% 的相异度意味着旧文件中的任何行都没有进入新文件。

    索引行包括更改前后的 blob 对象名称。 如果文件模式没有更改,则包括 <mode>;否则,单独的行指示旧模式和新模式。

  3. 带有“不寻常”字符的路径名按照配置变量 core.quotePath 的说明进行引用(请参阅 git-config[1])。

  4. 输出中的所有 file1 文件都引用提交之前的文件,所有 file2 文件都引用提交之后的文件。 依次将每个更改应用到每个文件是不正确的。 例如,此补丁将交换 a 和 b

    diff --git a/a b/b
    rename from a
    rename to b
    diff --git a/b b/a
    rename from b
    rename to a
  5. Hunk 头部会提及该 Hunk 应用的函数名称。 有关如何针对特定语言定制它的详细信息,请参阅 gitattributes[5] 中的“定义自定义 Hunk 头部”。

组合差异格式

任何差异生成命令都可以使用 -c--cc 选项来生成在显示合并时产生组合差异。 这是使用 git-diff[1]git-show[1] 显示合并时的默认格式。 另请注意,您可以为这些命令提供合适的 --diff-merges 选项,以强制生成特定格式的差异。

“组合差异”格式如下所示

diff --combined describe.c
index fabadb8,cc95eb0..4866510
--- a/describe.c
+++ b/describe.c
@@@ -98,20 -98,12 +98,20 @@@
	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
  }

- static void describe(char *arg)
 -static void describe(struct commit *cmit, int last_one)
++static void describe(char *arg, int last_one)
  {
 +	unsigned char sha1[20];
 +	struct commit *cmit;
	struct commit_list *list;
	static int initialized = 0;
	struct commit_name *n;

 +	if (get_sha1(arg, sha1) < 0)
 +		usage(describe_usage);
 +	cmit = lookup_commit_reference(sha1);
 +	if (!cmit)
 +		usage(describe_usage);
 +
	if (!initialized) {
		initialized = 1;
		for_each_ref(get_name);
  1. 它前面是一个“git diff”头,如下所示(当使用 -c 选项时)

    diff --combined file

    或如下所示(当使用 --cc 选项时)

    diff --cc file
  2. 它后面是一个或多个扩展头行(此示例显示了具有两个父级的合并)

    索引 <hash>,<hash>..<hash> 模式 <mode>,<mode>..<mode> 新文件模式 <mode> 已删除文件模式 <mode>,<mode>

    只有当至少一个 <mode> 与其余 <mode> 不同时,才会出现 mode <mode>,<mode>..<mode> 行。 包含有关检测到的内容移动(重命名和复制检测)信息的扩展标头旨在与两个 <tree-ish> 的差异一起使用,并且不被组合差异格式使用。

  3. 它后面是两行的 from-file/to-file 头部

    --- a/file
    +++ b/file

    与传统 unified 差异格式的两行头部类似,/dev/null 用于指示创建或删除的文件。

    但是,如果提供了 --combined-all-paths 选项,则会得到一个 N+1 行的 from-file/to-file 头部,而不是两行的 from-file/to-file,其中 N 是合并提交中的父级数

    --- a/file
    --- a/file
    --- a/file
    +++ b/file

    如果重命名或复制检测处于活动状态,则此扩展格式可能很有用,使您可以查看不同父级中文件的原始名称。

  4. 修改了块头格式,以防止人们意外地将其提供给 patch -p1。 创建组合差异格式是为了审核合并提交更改,而不是用于应用。 此更改类似于扩展索引标头中的更改

    @@@ <from-file-range> <from-file-range> <to-file-range> @@@

    组合差异格式的块头中有(父级数 + 1)个 @ 字符。

与传统的 unified 差异格式不同,后者使用单列显示两个文件 A 和 B,该单列具有 -(减号 — 出现在 A 中但在 B 中删除)、+(加号 — A 中缺少但在 B 中添加)或 " "(空格 — 未更改)前缀,此格式将两个或多个文件 file1、file2,…​与一个文件 X 进行比较,并显示 X 与每个 fileN 的不同之处。 每个 fileN 一列都预先添加到输出行,以记录 X 的行与其的不同之处。

列 N 中的 - 字符表示该行出现在 fileN 中,但未出现在结果中。 列 N 中的 + 字符表示该行出现在结果中,并且 fileN 没有该行(换句话说,从该父级的角度来看,该行已添加)。

在上面的示例输出中,函数签名已从两个文件中更改(因此从 file1 和 file2 中删除了两个 -,加上 ++ 表示添加的一行未出现在 file1 或 file2 中)。 此外,来自 file1 的其他八行是相同的,但未出现在 file2 中(因此以 + 作为前缀)。

当由 git diff-tree -c 显示时,它将合并提交的父级与合并结果进行比较(即 file1..fileN 是父级)。 当由 git diff-files -c 显示时,它将两个未解决的合并父级与工作树文件进行比较(即 file1 是阶段 2,也称为“我们的版本”,file2 是阶段 3,也称为“他们的版本”)。

其他差异格式

--summary 选项描述了新添加、已删除、已重命名和已复制的文件。 --stat 选项将 diffstat(1) 图添加到输出。 这些选项可以与其他选项(例如 -p)组合使用,并且旨在供人使用。

当显示涉及重命名或复制的更改时,--stat 输出通过组合路径名的公共前缀和后缀来紧凑地格式化路径名。 例如,将 arch/i386/Makefile 移动到 arch/x86/Makefile 并修改 4 行的更改将如下所示

arch/{i386 => x86}/Makefile    |   4 +--

--numstat 选项提供 diffstat(1) 信息,但旨在更易于机器使用。 --numstat 输出中的条目如下所示

1	2	README
3	1	arch/{i386 => x86}/Makefile

也就是说,从左到右

  1. 添加的行数;

  2. 一个制表符;

  3. 删除的行数;

  4. 一个制表符;

  5. 路径名(可能包含重命名/复制信息);

  6. 一个换行符。

-z 输出选项生效时,输出将以这种方式格式化

1	2	README NUL
3	1	NUL arch/i386/Makefile NUL arch/x86/Makefile NUL

也就是说

  1. 添加的行数;

  2. 一个制表符;

  3. 删除的行数;

  4. 一个制表符;

  5. 一个 NUL(仅在重命名/复制时存在);

  6. preimage 中的路径名;

  7. 一个 NUL(仅在重命名/复制时存在);

  8. postimage 中的路径名(仅在重命名/复制时存在);

  9. 一个 NUL。

重命名情况下 preimage 路径之前的额外 NUL 允许读取输出的脚本判断当前正在读取的记录是单路径记录还是重命名/复制记录,而无需提前读取。 读取添加和删除的行后,读取到 NUL 将产生路径名,但如果那是 NUL,则记录将显示两个路径。

操作模式

您可以选择是否完全信任索引文件(使用 --cached 标志)或要求 diff 逻辑显示任何与 stat 状态不匹配的文件,这些文件被“初步更改”。 这两个操作确实非常有用。

缓存模式

如果指定了 --cached,则允许您询问

show me the differences between HEAD and the current index
contents (the ones I'd write using 'git write-tree')

例如,假设您已经在工作目录中工作,更新了索引中的某些文件,并且准备提交。 您想准确地了解您将要提交什么,而无需编写新的树对象并以这种方式进行比较,为此,您只需执行

git diff-index --cached HEAD

示例:假设我将 commit.c 重命名为 git-commit.c,并且我执行了 update-index 以使其在索引文件中生效。 git diff-files 不会显示任何内容,因为索引文件与我的工作目录匹配。 但是执行 git diff-index

torvalds@ppc970:~/git> git diff-index --cached HEAD
:100644 000000 4161aecc6700a2eb579e842af0b7f22b98443f74 0000000000000000000000000000000000000000 D	commit.c
:000000 100644 0000000000000000000000000000000000000000 4161aecc6700a2eb579e842af0b7f22b98443f74 A	git-commit.c

您可以很容易地看到上面是一个重命名。

事实上,git diff-index --cached **应该**始终完全等效于实际执行 git write-tree 并进行比较。 只是在这种情况下,如果您只想检查自己的位置,它会更好。

因此,当您问自己“我已经标记了哪些要提交的内容,以及与前一个树的区别是什么”时,执行 git diff-index --cached 基本上非常有用。

非缓存模式

“非缓存”模式采用不同的方法,并且可能比两种方法中的任何一种都更有用,因为它所做的事情无法通过 git write-tree + git diff-tree 来模拟。 因此,这是默认模式。 非缓存版本会提出以下问题

show me the differences between HEAD and the currently checked out
tree - index contents _and_ files that aren't up to date

这显然也是一个非常有用的问题,因为它会告诉您可以提交什么。 同样,输出与 git diff-tree -r 输出完全匹配,但有一个转折。

转折是,如果某些文件与索引不匹配,我们没有它的后备存储,我们使用神奇的“全零”sha1 来显示它。 假设您已经编辑了 kernel/sched.c,但尚未对其执行 git update-index - 没有与新状态关联的“对象”,您会得到

torvalds@ppc970:~/v2.6/linux> git diff-index --abbrev HEAD
:100644 100644 7476bb5ba 000000000 M	kernel/sched.c

也就是说,它表明树已更改,并且 kernel/sched.c 不是最新的,可能包含新内容。 全零 sha1 意味着要获得真正的差异,您需要直接查看工作目录中的对象,而不是进行对象到对象的差异。

注意
与此类型的其他命令一样,git diff-index 实际上根本不查看文件的内容。 因此,可能 kernel/sched.c 实际上没有更改,而只是您触摸了它。 无论哪种情况,都需要注意,您需要 git update-index 它以使索引同步。
注意
您可以同时看到一些文件显示为“已更新”和“在工作目录中仍然是脏的”。 您总是可以区分哪个文件处于哪种状态,因为“已更新”的文件会显示一个有效的 sha1,而“与索引不同步”的文件将始终具有特殊的全部为零的 sha1。

GIT

属于 git[1] 套件的一部分

scroll-to-top