Git
English ▾ 主题 ▾ 最新版本 ▾ git-diff-index 最后更新于 2.46.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

使用“耐心差异”算法生成差异。

--histogram

使用“直方图差异”算法生成差异。

--anchored=<text>

使用“锚定差异”算法生成差异。

此选项可以多次指定。

如果一行同时存在于源和目标中,仅存在一次,并且以该文本开头,则此算法尝试防止它在输出中显示为删除或添加。它在内部使用“耐心差异”算法。

--diff-algorithm={patience|minimal|histogram|myers}

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

defaultmyers

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

minimal

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

patience

在生成补丁时使用“耐心差异”算法。

histogram

此算法扩展了耐心算法以“支持低出现率的公共元素”。

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

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

生成 diffstat。默认情况下,文件名部分将使用尽可能多的空间,其余部分将用于图形部分。最大宽度默认为终端宽度,或者如果未连接到终端则为 80 列,并且可以通过 <width> 覆盖。文件名部分的宽度可以通过在逗号后给出另一个宽度 <name-width> 来限制,或者通过设置 diff.statNameWidth=<width> 来限制。图形部分的宽度可以通过使用 --stat-graph-width=<width> 或设置 diff.statGraphWidth=<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

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

--numstat

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

--shortstat

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

-X[<param1,param2,…​>]
--dirstat[=<param1,param2,…​>]

输出每个子目录更改的相对数量的分布。可以通过传递逗号分隔的参数列表来自定义 --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[=<param1,param2>…​]

与 --dirstat=files,<param1>,<param2>…​ 同义。

--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 时,将使用简短格式。此格式仅显示范围开始和结束处的提交名称。当指定 --submodule--submodule=log 时,将使用日志格式。此格式列出范围内的提交,就像 git-submodule[1] summary 一样。当指定 --submodule=diff 时,将使用差异格式。此格式显示子模块内容在提交范围之间更改的内联差异。默认为 diff.submodule,如果未设置配置选项,则默认为简短格式。

--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=<modes>

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

no

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

ignore-space-at-eol

忽略行尾空格的更改。

ignore-space-change

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

ignore-all-space

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

allow-indentation-change

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

--no-color-moved-ws

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

--word-diff[=<mode>]

显示单词差异,使用<mode>分隔更改的单词。默认情况下,单词由空格分隔;请参见下面的 --word-diff-regex。<mode>默认为plain,并且必须是以下之一:

color

仅使用颜色突出显示更改的单词。暗示 --color

plain

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

porcelain

使用专为脚本使用而设计的基于行的特殊格式。添加/删除/未更改的运行将以通常的统一差异格式打印,在一行的开头以 +/-/` ` 字符开头并扩展到该行的末尾。输入中的换行符由其自身一行上的波浪号 ~ 表示。

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>

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

--full-index

在生成补丁格式输出时,在“索引”行上显示完整的预镜像和后镜像 Blob 对象名称,而不是前几个字符。

--binary

除了--full-index之外,还输出一个可以用git-apply应用的二进制差异。暗示 --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

省略删除操作的前镜像,即仅打印标题,而不打印前镜像和 /dev/null 之间的差异。生成的补丁不打算与 patchgit apply 一起应用;这仅适用于希望专注于查看更改后文本的人员。此外,输出显然缺乏足够的信息来反向应用此类补丁,即使是手动操作,因此得名。

当与 -B 选项一起使用时,还会省略删除/创建对中删除部分的前镜像。

-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>

查找更改指定字符串出现次数(即添加/删除)的文件差异。旨在供脚本编写者使用。

当您查找确切的代码块(如结构体)并希望了解该代码块从创建到现在的历史记录时,此功能很有用:迭代使用此功能将前镜像中的有趣代码块反馈到 -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,否则没有文本转换过滤器的二进制文件的补丁将被忽略。

有关更多信息,请参阅 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

忽略行尾空格的更改。

-b
--ignore-space-change

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

-w
--ignore-all-space

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

--ignore-blank-lines

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

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

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

--inter-hunk-context=<lines>

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

-W
--function-context

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

--exit-code

使程序退出代码类似于diff(1)。也就是说,如果存在差异,则退出代码为1;如果不存在差异,则退出代码为0。

--quiet

禁用程序的所有输出。隐含--exit-code。禁用执行其退出代码不可信的外部 diff 帮助程序,即其相应的配置选项diff.trustExitCodediff.<driver>.trustExitCode或环境变量GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE为假。

--ext-diff

允许执行外部 diff 帮助程序。如果使用gitattributes[5]设置了外部 diff 驱动程序,则需要将此选项与git-log[1]等一起使用。

--no-ext-diff

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

--textconv
--no-textconv

允许(或不允许)在比较二进制文件时运行外部文本转换过滤器。有关详细信息,请参阅gitattributes[5]。由于文本转换过滤器通常是单向转换,因此生成的 diff 适用于人工阅读,但不能应用。因此,默认情况下,仅对git-diff[1]git-log[1]启用文本转换过滤器,而不对git-format-patch[1]或 diff 底层命令启用。

--ignore-submodules[=<when>]

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

--src-prefix=<prefix>

显示给定的源前缀,而不是“a/”。

--dst-prefix=<prefix>

显示给定的目标前缀,而不是“b/”。

--no-prefix

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

--default-prefix

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

--line-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>

要进行 diff 的树对象的 ID。

--cached

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

--merge-base

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

-m

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

原始输出格式

“git-diff-index”、“git-diff-tree”、“git-diff-files”和“git 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. 状态,后跟可选的“分数”数字。

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

  12. "src" 的路径

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

  14. "dst" 的路径;仅存在于 C 或 R 中。

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

可能的状体字母是

  • A:添加文件

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

  • D:删除文件

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

  • R:重命名文件

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

  • U:文件未合并(您必须在提交之前完成合并)

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

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

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

示例

:100644 100644 5be4a4a 0000000 M file.c

如果没有-z选项,则将包含“异常”字符的文件名用引号括起来,如配置变量core.quotePath所述(请参阅git-config[1])。使用-z,文件名将逐字输出,行以 NUL 字节结尾。

合并的 diff 格式

“git-diff-tree”、“git-diff-files”和“git-diff --raw”可以采用-c--cc选项,以生成合并提交的 diff 输出。输出与上面描述的格式在以下方面有所不同

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

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

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

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

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

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

-c--cc在不使用--combined-all-paths时的示例

::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

请注意,组合 diff仅列出从所有父项修改的文件。

使用 -p 生成补丁文本

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

-p 选项生成的输出与传统的 diff 格式略有不同

  1. 它前面是类似这样的“git diff”标题

    diff --git a/file1 b/file2

    a/b/文件名相同,除非涉及重命名/复制。尤其是在创建或删除的情况下,/dev/null不会用于替换a/b/文件名。

    如果涉及重命名/复制,则file1file2分别显示重命名/复制的源文件的名称和重命名/复制生成的文件的名称。

  2. 后面是一行或多行扩展标题行

    old mode <mode>
    new mode <mode>
    deleted file mode <mode>
    new file mode <mode>
    copy from <path>
    copy to <path>
    rename from <path>
    rename to <path>
    similarity index <number>
    dissimilarity index <number>
    index <hash>..<hash> <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. 块标题会提及该块应用到的函数的名称。有关如何根据特定语言调整此功能的详细信息,请参阅 gitattributes[5] 中的“定义自定义块标题”。

组合 diff 格式

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

“组合 diff”格式如下所示

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. 后面跟着一个或多个扩展标题行(此示例显示了一个有两个父级的合并)

    index <hash>,<hash>..<hash>
    mode <mode>,<mode>..<mode>
    new file mode <mode>
    deleted file mode <mode>,<mode>

    仅当至少一个 <mode> 与其余部分不同时,才会出现 mode <mode>,<mode>..<mode> 行。包含关于检测到的内容移动(重命名和复制检测)信息的扩展标题旨在与两个 <tree-ish> 的 diff 一起使用,而不适用于组合 diff 格式。

  3. 后面跟着两行 from-file/to-file 标题

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

    类似于传统统一 diff 格式的两行标题,/dev/null 用于指示创建或删除的文件。

    但是,如果提供了 --combined-all-paths 选项,则不会出现两行 from-file/to-file,而是会出现 N+1 行 from-file/to-file 标题,其中 N 是合并提交中的父级数。

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

    如果重命名或复制检测处于活动状态,此扩展格式会很有用,因为它允许您查看不同父级中文件的原始名称。

  4. 块标题格式已修改,以防止人们意外将其馈送到 patch -p1。创建组合 diff 格式是为了审查合并提交更改,而不是为了应用。此更改类似于扩展索引标题中的更改。

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

    组合 diff 格式的块标题中包含(父级数 + 1)个 @ 字符。

与显示两个文件 A 和 B 以及带有 -(减号——出现在 A 中但在 B 中删除)、+(加号——在 A 中缺失但在 B 中添加)或 " "(空格——未更改)前缀的单个列的传统统一 diff 格式不同,此格式比较两个或多个文件 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,也称为“他们的版本”)。

其他 diff 格式

--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. 原像中的路径名;

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

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

  9. 一个 NUL。

重命名情况下在原像路径之前的额外 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 表示要获得真实的 diff,您需要直接查看工作目录中的对象,而不是执行对象到对象的 diff。

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

GIT

git[1] 套件的一部分

scroll-to-top