Git
简体中文 ▾ Topics ▾ Latest version ▾ git-diff-index last updated in 2.46.0

名称

git-diff-index - 比较树和工作树或索引

概述

git diff-index [-m] [--cached] [--merge-base] [<提交差异选项>] <目录树对象> [<路径>…​]

描述

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

选项

-p
-u
--patch

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

-s
--no-patch

抑制差异(diff)工具的所有输出。 对于默认显示补丁的 git show 等命令,可以压制其输出,或在别名中取消命令行中的 --patch--stat 等选项的效果。

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

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

--output=<文件>

输出到一个特定的文件,而不是标准输出。

--output-indicator-new=<字符>
--output-indicator-old=<字符>
--output-indicator-context=<字符>

指定在生成的补丁中用来表示新、旧或上下文行的字符。通常它们分别是 +- 和 ' '(空格)。

--raw

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

--patch-with-raw

-p--raw 的同义词。

--indent-heuristic

启用启发式的缩进区块的方法,使得补丁更易读。这是默认选项。

--no-indent-heuristic

禁用启发式缩进。

--minimal

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

--patience

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

--histogram

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

--anchored=<文本>

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

这个选项可以被指定多次。

如果某一个行同时存在于来源和目标中,各只出现一次,以这个文本开头,这个算法试图防止它在输出中以删除或添加的形式出现。它在内部使用了 "patience diff" 算法。

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

选择差异算法。有如下可选项:

default, myers

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

minimal

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

patience

使用 "patience diff" 算法时产生的补丁。

histogram

该算法将耐心算法扩展为 “支持低发生率的常见元素”。

例如,如果你将 diff.algorithm 变量配置为非默认值,但希望使用默认值,那么你必须使用 --diff-algorithm=default 选项。

--stat[=<宽度>[,<名称宽度>[,<数值>]]]

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

这些参数也可以用 --stat-width=<宽度>--stat-name-width=<名称宽度>--stat-count=<数量> 单独设置。

--compact-summary

在差异状态中输出扩展头信息的压缩摘要,如文件的创建或删除("new" 或 "good"。如果是符号链接,则为 "+l")和模式变化("+x" 或 "-x" 分别用于添加或删除可执行位)。这些信息被放在文件名部分和图形部分之间。暗含 --stat 选项。

--numstat

类似于 --stat,但是使用小数点和不含缩写的路径名显示添加和删除的行数,使其对程序更友好。对于二进制文件,输出两个 -,而不是 0 0

--shortstat

只输出使用 --stat 选项输出的最后一行,包含修改的文件总数,添加和删除的行数。

-X[<参数1,参数2,…​>]
--dirstat[=<参数1,参数2,…​>]

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

changes

通过计算从源文件中删除的行数或添加到目标文件中的行数来计算分布状态的数字。这忽略了文件内的代码移动行为。也就是说,在文件中重新排列的行不会像其他变化一样被计算在内。这是在没有给出参数时的默认行为。

lines

通过做常规基于行的差异分析,计算分布状态的数字,并将删除/添加的行数相加。(对于二进制文件,用 64 字节的块来计算,因为二进制文件没有行的概念)。在使用 --dirstat 时这个选项的行为开销比 changes 更大,但会对文件中重新排列的行进行计数。其得到的输出结果与其他的 --*stat 选项一致。

files

通过计算被改变的文件数量来计算分布状态的数字。在分布状态分析中,每一个被改变的文件都会被平等地计算。这是计算上开销最小的 --dirstat 行为,因为它无需查看文件内容。

cumulative

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

<limit>

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

例如:下面的参数会统计更改的文件,同时忽略占更改文件总数 10% 以下的目录,并累积父目录中的子目录计数:--dirstat=files,10,cumulative

--cumulative

--dirstat=cumulative 同义

--dirstat-by-file[=<参数1,参数2>…​]

与 --dirstat=files,<参数 1>,<参数 2> 同义

--summary

输出扩展头信息,如创建、重命名和模式变化等,的压缩摘要。

--patch-with-stat

同义词 -p --stat

-z

另外,当给出 --raw--numstat--name-only--name-status 选项时, 不合并路径名,并使用 NUL 作为输出字段终止符。

如果没有这个选项,带 “不常见” 字符的路径名会被引用,正如配置变量 core.quotePath 所解释的那样(参见 git-config[1])。

--name-only

Show only the name of each changed file in the post-image tree. The file names are often encoded in UTF-8. For more information see the discussion about encoding in the git-log[1] manual page.

--name-status

Show only the name(s) and status of each changed file. See the description of the --diff-filter option on what the status letters mean. Just like --name-only the file names are often encoded in UTF-8.

--submodule[=<格式>]

指定子模块中的差异如何显示。当指定 --submodule=short 选项时,会使用 short 格式。这种格式只显示范围的开头和结尾处的提交名称。当指定了 --submodule--submodule=log 时,会使用 log 格式。这种格式会像 git-submodule[1] summary 那样,列出该范围内的提交。当指定了 --submodule=diff 时,会使用 diff 格式。这个格式显示的是子模块内在提交范围之间的变化差异。默认为 diff.submodule,如果配置选项未设置, 则为 short 格式。

--color[=<when>]

显示有颜色的差异。--color(即不含 =<何时>)与 --color=always 相同。<何时> 可以是 alwaysneverauto

--no-color

关掉带彩色显示的差异。 这和 --color=never 相同。

--color-moved[=<模式>]

移动的代码行的颜色不同。 如果没有给出该选项,<模式> 默认为 no 如果没有给定模式选项,则为 zebra。 该模式必须以下其中之一:

no

被移动的行不突出显示。

default

zebra 的同义词。今后可能会改成更合理的模式。

plain

任何在某个位置被添加,且在另一个位置被删除的行,都会被用 color.diff.newMoved 着色。同样的,在差异中在某处删除且在其它地方添加的行会使用 color.diff.oldMoved 着色。这种模式可以读取任何被移动的行,但在代码审查中,它不能确定一个代码块是否未经排列而进行了移动。

blocks

使用贪心方法检测含至少 20 个字母数字字符的移动文本块。检测到的区块使用 color.diff.{old,new}Moved 的颜色。相邻的区块不能被区分开。

zebra

在 ‘块’ 模式下检测到移动的文本块。块使用 color.diff.{old,new}Moved 颜色或 color.diff.{old,new}MovedAlternative 颜色。这两种颜色之间的变化表示检测到了新的块。

dimmed-zebra

类似于 zebra 模式,但对使移动的代码中不关注的部分变暗。相邻两个区块的边界线被认为是重要,其余的部分是无关紧要的。dimmed_zebra 是一个被废弃的同义词。

--no-color-moved

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

--color-moved-ws=<模式>

这将配置在执行 --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[=<模式>]

显示词的差异,用 <模式> 来分隔已更改的词。默认情况下,单词是以空格分隔;请参考 --word-diff-regex。<模式> 默认为 plain,并且必须是以下其中之一:

color

只用颜色突出显示已更改的单词。暗含 --color 选项。

plain

显示更改的词为 [-removed-]{+added+}。如果在输入中出现定界符,则不尝试转义,所以输出可能是多义的。

porcelain

使用一种特殊的、基于行的格式,供脚本使用。添加/删除/未更改的运行数据以通常的统一的差异格式输出,行的开头以 + / - / ` ` 字符开始,一直到行的结尾。输入中的新行用单行上的 `~`表示。

none

再次禁用单词差异模式。

请注意,无论第一个模式的名称是什么,如果启用该选项,将在所有模式中使用颜色,以高亮显示更改的部分。

--word-diff-regex=<正则表达式>

使用 <正则表达式> 来确定单词的格式,而不是将一串非空白行视为单词。除非已启用,否则还暗含 --word-diff 选项。

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

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

正则表达式也可以通过差异程序或配置选项来设置,参见 gitattributes[5]git-config[1]。显式指明会覆盖任何程序或配置。差异程序会覆盖配置。

--color-words[=<正则表达式>]

--word-diff=color 和(如果指明了正则表达式)--word-diff-regex=<正则表达式> 两个选项含义相同。

--no-renames

关闭重命名检测,即使配置文件给出的默认是这样做。

--[no-]rename-empty

是否使用空的数据对象作为重命名源。

--check

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

--ws-error-highlight=<种类>

突出显示差异中 context(上下文)、old(旧)或 new(新)行中的空格错误。多个值用逗号隔开,none 选项会重置以前的值,default 重置列表为 newallold,new,context 的简写。当没有给定这个选项,并且配置变量 diff.wsErrorHighlight 没有设置时,只有 new 行中的空格错误会被高亮显示。空格错误会用 color.diff.whitespace 配置进行着色。

--full-index

在生成补丁格式输出时,在 index(索引)行上显示完整的图像前和图像后数据对象名称,而不仅是前几个字符。

--binary

除了 --full-index 输出的差异之外,输出二进制的差异。其可以用 git-apply 命令来应用。暗含 --patch 选项。 暗含 --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>]]

将完整的重写更改切分成删除和创建对(pair)。这有两个目的:

它会影响决定更改形式的阈值,当单个文件内修改总量达到一定值时,会认为该文件进行了完全重写,而不是将一系列删除和插入操作视为修改。如果视为多个删除和插入修改,修改中的行可能会碰巧在文本上与原文一致,从而被当作上下文。选项中的数字 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<数量>

-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<正则表达式>

查找其补丁文本包含与 <正则表达式> 匹配的添加/删除行的差异。

为了说明 -S<正则表达式> --pickaxe-regex-G<正则表达式> 之间的区别,假设某次提交在同一文件中有以下差异:

+    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=<对象ID>

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

该对象可以是一个 blob 或一个子模块提交。它意味着 git-log 中的 -t 选项也能找到工作树。

--pickaxe-all

当使用 -S-G 选项找到一个更改时,显示该更改集中的所有更改,而不仅仅是显示包含 <string> 更改的文件。

--pickaxe-regex

-S 选项的 <string> 参数当作扩展的 POSIX 正则表达式来匹配。

-O<顺序控制文件>

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

输出顺序由 <顺序控制文件> 中的 glob 模式的顺序决定。所有路径名与第一个模式匹配的文件首先输出,路径名与第二个模式匹配(但不与第一个模式匹配)的文件其次输出,以此类推。所有路径名与任何模式匹配的文件会最后输出,就像在文件末尾有一个隐含的全部匹配模式。如果多个路径名具有相同的等级(它们匹配相同的模式,但没有匹配先前的模式),它们相对于彼此的输出顺序是正常的。

<顺序控制文件> 格式如下:

  • 空白行会被忽略,因此可以用它们作为分隔符,以保证可读性。

  • 以井号("#")开头的行会被忽略,所以它们可以用来做注释。如果模式以井号开头,则需要在模式的开头加上反斜杠("\")。

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

模式的语法和语义与 fnmatch(3) 中使用的相同,不包括 FNM_PATHNAME 标志,但在删除路径名中结尾任意几个成分后匹配的情况下例外。例如,模式 "foo*bar" 匹配 "fooasdfbar" 和 "foo/bar/baz/asdf",但不匹配 "foobarx"。

--skip-to=<文件>
--rotate-to=<文件>

从输出中丢弃命名 <文件> 之前的文件(即 skip to),或将它们移到输出的末尾(即 rotate to)。 这些选项主要是为使用 git difftool 命令而发明的,在其他情况下可能用处不大。

-R

交换两个输入;即显示从索引或磁盘文件到目录树内容的差异。

--relative[=<路径>]
--no-relative

当从项目的子目录中运行时,可以排除目录外的变化,并通过这个选项显示相对于它的路径名。当你不在子目录中时(例如在纯仓库中),你可以通过 <路径> 参数来指明要使输出相对于哪个子目录。--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<正则表达式>
--ignore-matching-lines=<正则表达式>

忽略所有行均匹配 <正则表达式> 的更改。 此选项可指定多次。

--inter-hunk-context=<行数>

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

-W
--function-context

在每个修改中的上下文行显示整个函数。函数名称的确定方式与 git diff 计算补丁头的方式相同(参见 gitattributes[5] 中的 自定义区块头 )。

--exit-code

让程序以类似 diff(1) 的代码退出。也就是说,如果有差异则返回1,否则返回0。

--quiet

禁用程序的所有输出。暗含 --exit-code 选项。禁用那些退出代码不被信任的外部差异辅助程序的执行,即它们的相应配置选项 diff.trustExitCodediff.<驱动程序>.trustExitCode 或环境变量 GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE 设置为 false。

--ext-diff

允许执行外部差异器。如果你用 gitattributes[5] 设置了一个外部差异驱动程序,你需要在 git-log[1] 和相关命令中使用这个选项。

--no-ext-diff

禁止使用外部差异器。

--textconv
--no-textconv

允许(或不允许)在比较二进制文件时运行外部文本转换过滤器。详情请参见 gitattributes[5] 。由于文本转换过滤器通常是单向转换,因此产生的差异适合人类用户使用,但不能应用(apply)。因此默认情况下,只有 git-diff[1]git-log[1] 启用文本转换过滤器,而 git-format-patch[1] 或 diff plumbing 命令则不启用。

--ignore-submodules[=<when>]

在生成差异时忽略子模块的修改。<when> 可以是 "none"、"untracked"、"dirty " 或 "all","all" 是默认选项。使用 "none" 会在子模块包含未跟踪或修改的文件,或者它的HEAD 与上级项目中记录的提交不同时,认为它被修改了,并且可以用来覆盖 git-config[1]gitmodules[5]忽略 选项的设置。当使用 "untracked" 时,当子模块只包含未跟踪的内容时,它们不会被认为是有改动的(但它们仍然会被扫描是否有被修改的内容)。使用 "dirty" 会忽略所有对子模块工作树的修改,只有存储在上级项目中的提交的修改才会被显示出来(这是在1.7.0之前的行为)。使用 "all" 会隐藏所有对子模块的修改。

--src-prefix=<前缀>

显示给定的源前缀而不是 "a/"。

--dst-prefix=<前缀>

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

--no-prefix

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

--default-prefix

Use the default source and destination prefixes ("a/" and "b/"). This overrides configuration variables such as diff.noprefix, diff.srcPrefix, diff.dstPrefix, and diff.mnemonicPrefix (see 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>

树对象的 id。

--cached

完全不考虑磁盘文件。

--merge-base

与其直接比较 <目录树对象>,不如使用 <目录树对象> 和 HEAD 之间的合并基数。 <目录树对象> 必须是一个提交。

-m

默认情况下,索引中有记录但未签出的文件会被报告为已删除。 这个标记会让 git diff-index 认为所有未签出的文件都是最新的。

原始输出格式

"git-diff-index","git-diff-tree","git-diff-files" 和 "git diff --raw" 的原始输出格式非常相似。

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

git-diff-index <目录树对象>

比较 <目录树对象> 和文件系统上的文件。

git-diff-index --cached <目录树对象>

比较 <目录树对象> 和索引。

git-diff-tree [-r] <目录树对象 1> <目录树对象 2> [<模式>…​]

比较由两个参数传递的目录树。

git-diff-files [<模式>…​]

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

"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. sha1 表示 "dst"(目标文件);0{40} 表示删除、未合并或 “工作目录树与索引不同步”。

  9. 空格。

  10. 状态,在可选值 "score" 之后。

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

  12. "src" 的路径

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

  14. "dst" 的路径;仅当状态为 C 或 R 时存在。

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

可能的状态字母为:

  • A:文件新增部分

  • C:复制到一个新文件

  • D:文件删除部分

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

  • R:文件重命名

  • T:文件类型改变

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

  • X:"unknown"(未知)更改类型(可能为错误,请报告)

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

如果文件是文件系统上的新文件,并且与索引不同步,则 <sha1> 将显示为全 0。

例如:

:100644 100644 5be4a4a 0000000 M file.c

如果没有 -z 选项,带 “不常见” 字符的路径名会被加上引号,正如配置变量 core.quotePath 所解释的那样(参见 git-config[1])。 使用 -z 选项,文件名将被逐字输出,并以 NUL 字节结束。

合并的差异格式

"git-diff-tree"、"git-diff-files" 和 "git-diff --raw" 可以使用 -c--cc 选项来生成差异输出,也可以用于合并提交。其输出与上面描述的格式有以下不同:

  1. 每个父提交都有一个冒号

  2. 有更多的 "src" 文件模式和 "src" sha1

  3. 状态是每个父提交的状态字符的合并

  4. 无可选的分数("score")数字

  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

请注意 combined diff 只列出了从所有父提交中修改过的文件。

使用选项 -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. 它的后面是一个或多个扩展头信息行:

    old mode <模式>
    new mode <模式>
    deleted file mode <模式>
    new file mode <模式>
    copy from <路径>
    copy to <路径>
    rename from <路径>
    rename to <路径>
    similarity index <数字>
    dissimilarity index <数字>
    index <哈希>..<哈希> <模式>

    文件模式被打印为 6 位八进制数字,包括文件类型和文件权限位。

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

    相似性指数是未改变的行占比,而不相似性指数是改变的行占比。它是四舍五入的整数,后有百分号。因此,100%的相似度指数指为两个文件相等,而 100% 的不相似度意味着入新文件中没有旧文件中的行。

    索引行包括改变前和改变后的 blob 对象名称。如果文件模式没有变化,则包含 <模式>;否则,分别显示新旧模式。

  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] 中的 “定义自定义 hunk-header”,以了解如何针对特定语言进行定制。

合并的差异格式

任何生成差异的命令都可以使用 -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. 它的后面是一个或多个扩展头信息行(本例显示的是与两个父提交的合并):

    index <哈希>,<哈希>..<哈希>
    mode <模式>,<模式>..<模式>
    new file mode <模式>
    deleted file mode <模式>,<模式>

    mode<模式>,<模式>..<模式> 行仅在 <模式> 中至少有一个与其余的不同时才会出现。包含有关检测到的内容移动的信息 (重命名和复制检测) 的扩展标头设计为使用两个 <目录树对象> 的 diff,不能用于组合的 diff 格式。

  3. 它的后面是两行源文件/目标文件的头信息:

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

    与传统 ‘统一’ diff 格式的双行标题类似,/dev/null 用于表示已创建或已删除的文件。

    但是,如果提供了 --combined-all-paths 选项,你就会得到一个 N+1 行的源文件/目标文件头,其中 N 是合并提交中的父提交数量:

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

    如果重命名或复制检测处于活动状态,这种扩展格式可能很有用,可以让你在不同的父提交中看到文件的原始名称。

  4. 修改了文件块头信息的格式,以防止不小心将其送入 patch -p1。合并的差异格式是为审查合并提交的修改而创建的,并不是为了应用。这个变化类似于扩展的 "索引" 头信息的变化:

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

    块中有(父提交数量+1)@ 字符,用于合并的差异格式。

与传统的 "统一" 差异格式不同,这种格式显示两个文件 A 和 B 的列,其中有 -(减号 — 在 A 中出现,但在 B 中删除),+(加号 — 在 A 中缺少,但在 B 中增加),或 " "(空格 — 不变)前缀,这种格式比较两个或多个文件与一个文件 X,并显示 X 与其中每个文件的差异。文件中的每一个都有一列被前置在输出行中,以指出 X 的行与它的不同之处。

第 N 列中的 - 字符意味着该行出现在文件 N 中,但它没有出现在结果文件中。第 N 列中的 + 字符意味着该行出现在结果文件中,而文件 N 中没有该行(换句话说,从该父提交的角度来看,该行是被添加的)。

在上面的输出示例中,两个文件中的函数签名都被改变了(因此从文件 1 和文件 2 中都有表示删除的 -,而 ++ 表示被添加的一行没有出现在文件 1 或文件 2 中)。另外还有 8 行与文件 1 中的相同,但没有出现在文件 2 中(因此前缀为 +)。

当用 git diff-tree -c 显示时,它将合并提交的父提交文件与合并结果进行比较(即文件 1 …​ 文件 N 是父提交文件)。当用 git diff-files -c 显示时,它将两个未解决的合并父提交文件与工作树文件进行比较(即文件 1 是阶段 2 ,又称 "我们的版本",文件 2 是阶段 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. 完整路径名;

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

  8. 完整路径名(仅在重命名/复制时存在);

  9. 一个 NUL 字符。

在重命名的情况下,完整路径前多出的 NUL 为了让读取输出的脚本能够判断,当前被读取的记录是单路径记录还是重命名/复制记录,而不需要提前读取。在读完增删行数后,读至 NUL 会得到路径名,但如果先读到 NUL,记录将显示两个路径。

运行模式

你可以选择是完全信任索引文件(使用 --cached 标志),还是要求 diff 逻辑将任何与统计状态不匹配的文件显示为 "暂定更改"。 这两种操作都非常有用。

缓存模式

如果指定了 --cached,则可以询问:

向我显示 HEAD 和当前索引
内容(即我使用 '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 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        commit.c
+100644 blob    4161aecc6700a2eb579e842af0b7f22b98443f74        git-commit.c

不难看出,以上是重命名。

事实上,git diff-index --cached 应当 总是完全等同于实际执行 git write-tree 并进行比较。只不过,这个方法更适合只想查看当前位置的情况。

因此,当你问自己 “我已经标记了哪些内容要提交,与之前的树有什么不同” 时,使用 git diff-index --cached 基本上是非常有用的。

非缓存模式

“非缓存” 模式采用的是另一种方法,而且可能是两种模式中最有用的一种,因为它的功能无法用 git write-tree + git diff-tree 来模拟。因此这是默认模式。 非缓存版本提出的问题是:

向我显示 HEAD 与当前已签出树之间的差异 -
索引内容 _ 和未更新的文件

这显然也是一个非常有用的问题,因为它会告诉你*可能*提交的内容。同样,输出结果与 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 意味着要获得真正的差异,需要直接查看工作目录中的对象,而不是进行对象间的差异。

Note
与其他同类命令一样,git diff-index 实际上并不查看文件内容。所以也许 kernel/sched.c 实际上并没有改变,只是你看了一下而已。无论哪种情况,都需要 git update-index 来使索引同步。
Note
你可以让各种文件同时显示为 “已更新” 和 “仍在工作目录中”。由于 “已更新” 的文件会显示有效的 sha1,而 “未与索引同步” 的文件则会显示特殊的全零 sha1,因此你总能分辨出哪个文件处于哪种状态。

GIT

属于 git[1] 文档

scroll-to-top