English ▾ 主题 ▾ 最新版本 ▾ git-log 上次更新于 2.49.0

名称

git-log - 显示提交日志

概要

git log [<options>] [<revision-range>] [[--] <path>…​]

描述

显示提交日志。

列出通过给定提交的 parent 链接可到达的提交,但排除通过前面带有 ^ 的提交可到达的提交。 默认情况下,输出按时间倒序排列。

您可以将其视为一个集合运算。 从命令行上的任何给定提交可到达的提交形成一个集合,然后从前面带有 ^ 的任何给定提交可到达的提交将从该集合中减去。 剩余的提交将出现在命令的输出中。 各种其他选项和路径参数可用于进一步限制结果。

因此,以下命令

$ git log foo bar ^baz

意味着“列出从 foobar 可到达的所有提交,但不是从 baz 可到达的所有提交”。

特殊符号“<commit1>..<commit2>”可以用作“^<commit1> <commit2>”的简写。 例如,可以互换使用以下任一命令

$ git log origin..HEAD
$ git log HEAD ^origin

另一种特殊符号是“<commit1>…​<commit2>”,它对于合并非常有用。 产生的提交集合是两个操作数之间的对称差。 以下两个命令是等效的

$ git log A B --not $(git merge-base --all A B)
$ git log A...B

该命令采用适用于 git-rev-list[1] 命令的选项来控制显示的内容和方式,以及适用于 git-diff[1] 命令的选项来控制每个提交引入的更改的显示方式。

选项

--follow

继续列出文件在重命名后的历史记录(仅适用于单个文件)。

--no-decorate
--decorate[=short|full|auto|no]

打印显示的任何提交的 ref 名称。 如果指定了 short,则不会打印 ref 名称前缀 refs/heads/refs/tags/refs/remotes/。 如果指定了 full,则将打印完整的 ref 名称(包括前缀)。 如果指定了 auto,那么如果输出将发送到终端,则 ref 名称的显示方式就像给定了 short 一样,否则不显示 ref 名称。 选项 --decorate--decorate=short 的简写。 如果配置了 log.decorate,则默认为该配置值,否则为 auto

--decorate-refs=<pattern>
--decorate-refs-exclude=<pattern>

对于每个候选引用,如果它与任何给定的 --decorate-refs-exclude 模式匹配,或者如果它与任何给定的 --decorate-refs 模式不匹配,则不要将其用于装饰。 log.excludeDecoration 配置选项允许从装饰中排除引用,但显式的 --decorate-refs 模式将覆盖 log.excludeDecoration 中的匹配项。

如果未给出这些选项或配置设置中的任何一个,则如果引用匹配 HEADrefs/heads/refs/remotes/refs/stash/refs/tags/,则将其用作装饰。

--clear-decorations

指定后,此选项将清除所有先前的 --decorate-refs--decorate-refs-exclude 选项,并将默认装饰过滤器放宽为包含所有引用。 如果配置值 log.initialDecorationSet 设置为 all,则假定此选项。

--source

打印出命令行上给出的每个提交到达的 ref 名称。

--[no-]mailmap
--[no-]use-mailmap

使用 mailmap 文件将作者和提交者的姓名以及电子邮件地址映射到规范的真实姓名和电子邮件地址。 请参阅 git-shortlog[1]

--full-diff

如果没有此标志,git log -p <path>... 会显示触及指定路径的提交,以及关于相同指定路径的 diff。 有了此标志,将显示触及指定路径的提交的完整差异; 这意味着“<path>…​”仅限制提交,而不限制这些提交的差异。

请注意,这会影响所有基于 diff 的输出类型,例如,--stat 等生成的输出类型。

--log-size

在每个提交的输出中包含一行“log size <number>”,其中 <number> 是该提交消息的长度(以字节为单位)。 旨在通过允许工具提前分配空间来加速从 git log 输出中读取日志消息的工具。

-L<start>,<end>:<file>
-L:<funcname>:<file>

跟踪 <file> 中由 <start>,<end> 给定的行范围或由函数名称正则表达式 <funcname> 给定的行范围的演变。 您不能给出任何路径规范限制符。 目前这仅限于从单个修订版开始的遍历,即,您只能给出零个或一个正修订版参数,并且 <start><end> (或 <funcname>)必须存在于起始修订版中。 您可以多次指定此选项。 意味着 --patch。 可以使用 --no-patch 抑制补丁输出,但其他差异格式(即 --raw--numstat--shortstat--dirstat--summary--name-only--name-status--check)目前尚未实现。

<start><end> 可以采用以下形式之一

  • number

    如果 <start><end> 是一个数字,则它指定一个绝对行号(行从 1 开始计数)。

  • /regex/

    此格式将使用与给定的 POSIX 正则表达式匹配的第一行。 如果 <start> 是一个正则表达式,它将从上一个 -L 范围的末尾开始搜索(如果有),否则从文件的开头开始搜索。 如果 <start>^/regex/,它将从文件的开头开始搜索。 如果 <end> 是一个正则表达式,它将从 <start> 给定的行开始搜索。

  • +offset 或 -offset

    这仅对 <end> 有效,并将指定 <start> 给定的行之前或之后的行数。

如果 :<funcname> 出现在 *<start>* 和 *<end>* 的位置,它是一个正则表达式,表示从第一个匹配 *<funcname>* 的 funcname 行到下一个 funcname 行的范围。:<funcname> 从前一个 -L 范围的结尾开始搜索,如果不存在,则从文件开头搜索。^:<funcname> 从文件开头搜索。函数名的确定方式与 git diff 计算补丁块头的方式相同(参见 gitattributes[5] 中的*定义自定义块头*)。

<revision-range>

仅显示指定修订范围内的提交。如果未指定 <revision-range>,则默认为 HEAD(即,指向当前提交的整个历史记录)。origin..HEAD 指定所有从当前提交(即 HEAD)可以到达的提交,但不包括从 origin 可以到达的提交。有关拼写 <revision-range> 的完整列表,请参阅 gitrevisions[7] 的 *指定范围* 部分。

[--] <path>…​

仅显示足以解释与指定路径匹配的文件是如何产生的提交。有关详细信息和其他简化模式,请参阅下面的*历史简化*。

路径可能需要以 -- 为前缀,以便在出现混淆时将其与选项或修订范围分隔开。

提交限制

除了使用描述中解释的特殊表示法指定应列出的提交范围之外,还可以应用额外的提交限制。

通常,使用更多的选项会进一步限制输出(例如,--since=<date1> 限制为晚于 <date1> 的提交,将其与 --grep=<pattern> 一起使用会进一步限制为日志消息中包含匹配 <pattern> 的行的提交),除非另有说明。

请注意,这些选项在提交排序和格式化选项(例如 --reverse)之前应用。

-<number>
-n <number>
--max-count=<number>

限制要输出的提交的数量。

--skip=<number>

在开始显示提交输出之前跳过 *number* 个提交。

--since=<date>
--after=<date>

显示特定日期之后的提交。

--since-as-filter=<date>

显示特定日期之后的所有提交。这将访问范围内的所有提交,而不是在第一个早于特定日期的提交处停止。

--until=<date>
--before=<date>

显示特定日期之前的提交。

--author=<pattern>
--committer=<pattern>

将提交输出限制为具有匹配指定模式(正则表达式)的 author/committer 标头行的提交。如果有多个 --author=<pattern>,则选择作者匹配任何给定模式的提交(对于多个 --committer=<pattern> 也是如此)。

--grep-reflog=<pattern>

将提交输出限制为具有匹配指定模式(正则表达式)的 reflog 条目的提交。如果有多个 --grep-reflog,则选择 reflog 消息匹配任何给定模式的提交。除非使用了 --walk-reflogs,否则使用此选项会报错。

--grep=<pattern>

将提交输出限制为具有匹配指定模式(正则表达式)的日志消息的提交。如果有多个 --grep=<pattern>,则选择消息匹配任何给定模式的提交(但请参阅 --all-match)。

--notes 生效时,来自注释的消息将被视为日志消息的一部分进行匹配。

--all-match

将提交输出限制为匹配所有给定的 --grep 的提交,而不是至少匹配一个的提交。

--invert-grep

将提交输出限制为日志消息不匹配 --grep=<pattern> 指定的模式的提交。

-i
--regexp-ignore-case

匹配正则表达式限制模式时不考虑字母大小写。

--basic-regexp

将限制模式视为基本正则表达式;这是默认设置。

-E
--extended-regexp

将限制模式视为扩展正则表达式,而不是默认的基本正则表达式。

-F
--fixed-strings

将限制模式视为固定字符串(不要将模式解释为正则表达式)。

-P
--perl-regexp

将限制模式视为 Perl 兼容的正则表达式。

对这些类型的正则表达式的支持是一个可选的编译时依赖项。如果 Git 在编译时没有支持这些类型,则提供此选项会导致它崩溃。

--remove-empty

当给定路径从树中消失时停止。

--merges

仅打印合并提交。这与 --min-parents=2 完全相同。

--no-merges

不打印具有多个父级的提交。这与 --max-parents=1 完全相同。

--min-parents=<number>
--max-parents=<number>
--no-min-parents
--no-max-parents

仅显示至少(或最多)具有那么多个父级提交的提交。特别是,--max-parents=1--no-merges 相同,--min-parents=2--merges 相同。--max-parents=0 给出所有根提交,--min-parents=3 给出所有章鱼合并。

--no-min-parents--no-max-parents 再次重置这些限制(为无限制)。等效形式为 --min-parents=0(任何提交都有 0 个或更多父级)和 --max-parents=-1(负数表示没有上限)。

--first-parent

在查找要包含的提交时,在看到合并提交时仅跟踪第一个父级提交。当查看特定主题分支的演变时,此选项可以提供更好的概述,因为合并到主题分支中往往只是为了不时地适应更新的上游,并且此选项允许您忽略通过此类合并带入到您的历史记录中的各个提交。

此选项还会将合并提交的默认差异格式更改为 first-parent,有关详细信息,请参见 --diff-merges=first-parent

--exclude-first-parent-only

在查找要排除的提交(使用 *^*)时,在看到合并提交时仅跟踪第一个父级提交。这可用于查找主题分支中从它与远程分支分离的点开始的更改集,前提是任意合并可以是有效的主题分支更改。

--not

反转所有后续修订说明符的 *^* 前缀(或缺少前缀)的含义,直到下一个 --not。如果在 --stdin 之前在命令行上使用,则通过 stdin 传递的修订不受其影响。相反,如果通过标准输入传递,则在命令行上传递的修订不受其影响。

--all

假装 refs/ 中的所有引用以及 HEAD 都作为 *<commit>* 在命令行上列出。

--branches[=<pattern>]

假装 refs/heads 中的所有引用都作为 *<commit>* 在命令行上列出。如果给定了 *<pattern>*,则将分支限制为与给定的 shell glob 匹配的分支。如果模式缺少 *?*、*\* 或 *[*,则意味着末尾的 */*\*。

--tags[=<pattern>]

假装 refs/tags 中的所有引用都作为 *<commit>* 在命令行上列出。如果给定了 *<pattern>*,则将标签限制为与给定的 shell glob 匹配的标签。如果模式缺少 *?*、*\* 或 *[*,则意味着末尾的 */*\*。

--remotes[=<pattern>]

假装 refs/remotes 中的所有引用都作为 *<commit>* 在命令行上列出。如果给定了 *<pattern>*,则将远程跟踪分支限制为与给定的 shell glob 匹配的分支。如果模式缺少 *?*、*\* 或 *[*,则意味着末尾的 */*\*。

--glob=<glob-pattern>

假装与 shell glob *<glob-pattern>* 匹配的所有引用都作为 *<commit>* 在命令行上列出。如果缺少,则自动预先添加前导 refs/。如果模式缺少 *?*、*\* 或 *[*,则意味着末尾的 */*\*。

--exclude=<glob-pattern>

不包括下一个 --all--branches--tags--remotes--glob 否则会考虑的与 *<glob-pattern>* 匹配的引用。此选项的重复累积排除模式,直到下一个 --all--branches--tags--remotes--glob 选项(其他选项或参数不清除累积的模式)。

应用于 --branches--tags--remotes 时,给定的模式不应以 refs/headsrefs/tagsrefs/remotes 开头,并且应用于 --glob--all 时,它们必须以 refs/ 开头。如果需要尾随的 */*\*,则必须显式给出。

--exclude-hidden=[fetch|receive|uploadpack]

通过查阅适当的 fetch.hideRefsreceive.hideRefsuploadpack.hideRefs 配置以及 transfer.hideRefs(请参见 git-config[1]),不包括会被 git-fetchgit-receive-packgit-upload-pack 隐藏的引用。此选项影响下一个伪引用选项 --all--glob,并在处理它们后清除。

--reflog

假装 reflog 中提到的所有对象都作为 <commit> 在命令行上列出。

--alternate-refs

假装作为备用存储库的引用提示提及的所有对象都在命令行中列出。备用存储库是指对象目录在 objects/info/alternates 中指定的任何存储库。包含的对象集可以通过 core.alternateRefsCommand 等进行修改。请参见 git-config[1]

--single-worktree

默认情况下,当有多个工作区时,以下选项将检查所有工作区(请参见 git-worktree[1]):--all--reflog--indexed-objects。此选项强制它们仅检查当前工作区。

--ignore-missing

在输入中看到无效的对象名称时,假装没有给出错误的输入。

--bisect

假设坏的二分引用 refs/bisect/bad 已被列出,并且紧随其后的是 --not 和好的二分引用 refs/bisect/good-* 在命令行上。

--stdin

除了从命令行获取参数之外,也从标准输入读取它们。这接受提交和伪选项,例如 --all--glob=。当看到 -- 分隔符时,以下输入被视为路径,并用于限制结果。通过标准输入读取的标志(例如 --not)仅对以相同方式传递的参数有效,并且不会影响任何后续的命令行参数。

--cherry-mark

类似于 --cherry-pick(见下文),但用 = 标记等价的提交,而不是省略它们,并用 + 标记非等价的提交。

--cherry-pick

当提交集合通过对称差异限制时,忽略任何引入与“另一侧”的另一个提交相同更改的提交。

例如,如果您有两个分支 AB,一个通常的方式来列出仅存在于其中一个分支上的提交是使用 --left-right (参见下面 --left-right 选项的描述中的示例)。但是,它会显示从另一个分支 cherry-picked 的提交(例如,“b 上的第 3 个”可能从 A 分支 cherry-picked 过来的)。 使用此选项,这些提交对将从输出中排除。

--left-only
--right-only

仅列出对称差异的相应侧的提交,即仅列出那些会被 --left-right 标记为 <> 的提交。

例如,--cherry-pick --right-only A...B 忽略 B 中那些在 A 中或与 A 中的提交在补丁上等价的提交。 换句话说,这将列出 git cherry A B 中的 + 提交。更准确地说,--cherry-pick --right-only --no-merges 给出了确切的列表。

--cherry

--right-only --cherry-mark --no-merges 的同义词;用于将输出限制到我们这边的提交,并标记那些已经应用于分叉历史的另一边的提交,可以使用 git log --cherry upstream...mybranch,类似于 git cherry upstream mybranch

-g
--walk-reflogs

不遍历提交的祖先链,而是遍历 reflog 条目,从最新的条目到较旧的条目。当使用此选项时,您不能指定要排除的提交(即,^commitcommit1..commit2commit1...commit2 表示法不能使用)。

使用 --pretty 格式,而不是 onelinereference (原因很明显),这会导致输出有两行额外的从 reflog 获取的信息。 输出中的 reflog 设计器可以显示为 ref@{<Nth>}(其中 <Nth> 是 reflog 中的反向时间顺序索引),也可以显示为 ref@{<timestamp>}(带有该条目的 <timestamp>),具体取决于一些规则

  1. 如果起点指定为 ref@{<Nth>},则显示索引格式。

  2. 如果起点指定为 ref@{now},则显示时间戳格式。

  3. 如果两者都没有使用,但在命令行上给出了 --date,则以 --date 请求的格式显示时间戳。

  4. 否则,显示索引格式。

--pretty=oneline 下,提交消息以同一行上的此信息为前缀。 此选项不能与 --reverse 组合使用。 另请参阅 git-reflog[1]

--pretty=reference 下,此信息将根本不会显示。

--merge

显示范围 HEAD...<other> 中涉及冲突路径的提交,其中 <other>MERGE_HEADCHERRY_PICK_HEADREVERT_HEADREBASE_HEAD 中第一个存在的伪引用。 仅当索引具有未合并的条目时才有效。 当解决来自三向合并的冲突时,可以使用此选项来显示相关的提交。

--boundary

输出排除的边界提交。 边界提交以 - 为前缀。

历史简化

有时您只对历史的某些部分感兴趣,例如修改特定 <path> 的提交。 但是*历史简化*有两个部分,一部分是选择提交,另一部分是如何进行选择,因为有多种简化历史的策略。

以下选项选择要显示的提交

<paths>

修改给定 <paths> 的提交被选择。

--simplify-by-decoration

被某些分支或标签引用的提交被选择。

请注意,可以显示额外的提交以提供有意义的历史记录。

以下选项会影响执行简化的方式

默认模式

将历史简化为解释树的最终状态的最简单历史。 最简单是因为如果最终结果相同,它会修剪一些侧分支(即合并具有相同内容的分支)

--show-pulls

包括来自默认模式的所有提交,以及任何对于第一个父级不是 TREESAME 但对于后面的父级是 TREESAME 的合并提交。 此模式有助于显示“首次引入”分支更改的合并提交。

--full-history

与默认模式相同,但不修剪某些历史记录。

--dense

仅显示选定的提交,加上一些具有有意义的历史记录的提交。

--sparse

显示简化历史记录中的所有提交。

--simplify-merges

--full-history 的附加选项,用于从生成历史记录中删除一些不必要的合并,因为没有选定的提交为此合并做出贡献。

--ancestry-path[=<commit>]

当给出要显示的提交范围(例如,commit1..commit2commit2 ^commit1)以及该范围内的提交 <commit> 时,仅显示该范围内是 <commit> 的祖先、<commit> 的后代或 <commit> 本身的提交。 如果未指定提交,请使用 commit1 (范围的排除部分)作为 <commit>。 可以多次传递; 如果是这样,如果提交是给定的任何提交,或者它是其中一个提交的祖先或后代,则包含该提交。

下面是更详细的解释。

假设您将 foo 指定为 <paths>。 我们将调用修改 foo 的提交为 !TREESAME,其余为 TREESAME。 (在为 foo 过滤的 diff 中,它们看起来分别不同且相等。)

在下文中,我们将始终参考相同的示例历史记录来说明简化设置之间的差异。 我们假设您正在此提交图中为文件 foo 进行过滤

	  .-A---M---N---O---P---Q
	 /     /   /   /   /   /
	I     B   C   D   E   Y
	 \   /   /   /   /   /
	  `-------------'   X

历史 A---Q 的水平线被认为是每个合并的第一个父级。 提交是

  • I 是初始提交,其中 foo 存在内容“asdf”,并且文件 quux 存在内容“quux”。 初始提交与空树进行比较,因此 I 是 !TREESAME。

  • A 中,foo 仅包含 “foo”。

  • B 包含与 A 相同的更改。 它的合并 M 是微不足道的,因此对所有父级都是 TREESAME。

  • C 不会更改 foo,但它的合并 N 将其更改为 “foobar”,因此它对任何父级都不是 TREESAME。

  • Dfoo 设置为 “baz”。 它的合并 O 将来自 ND 的字符串组合为 “foobarbaz”; 也就是说,它对任何父级都不是 TREESAME。

  • Equux 更改为 “xyzzy”,其合并 P 将字符串组合为 “quux xyzzy”。 PO 是 TREESAME,但对 E 不是。

  • X 是一个独立的根提交,它添加了一个新文件 side,而 Y 修改了它。 YX 是 TREESAME。 它的合并 Qside 添加到 P,并且 QP 是 TREESAME,但对 Y 不是。

rev-list 向后遍历历史记录,根据是否使用 --full-history 和/或父级重写(通过 --parents--children)来包含或排除提交。 以下设置可用。

默认模式

如果提交对任何父级都不是 TREESAME,则包含它们(尽管可以更改,请参见下面的 --sparse)。 如果提交是合并,并且对一个父级是 TREESAME,则仅跟随该父级。 (即使有几个 TREESAME 父级,也仅跟随其中一个。) 否则,跟随所有父级。

这导致

	  .-A---N---O
	 /     /   /
	I---------D

注意,如果有一个 TREESAME 父级可用,则仅跟随 TREESAME 父级的规则如何完全从考虑中删除了 BC 通过 N 考虑,但它是 TREESAME。 根提交与空树进行比较,因此 I 是 !TREESAME。

父/子关系仅在 --parents 中可见,但这不会影响在默认模式下选择的提交,因此我们显示了父行。

--full-history 没有父级重写

此模式与默认模式的不同之处在于一点:始终跟踪合并的所有父提交,即使它与其中一个父提交是 TREESAME(树相同)的。即使合并的多个分支都有包含的提交,这并不意味着合并本身也被包含!在示例中,我们得到

	I  A  B  N  D  O  P  Q

M 被排除,因为它与两个父提交都是 TREESAME 的。ECB 都被遍历了,但只有 B 是 !TREESAME 的,所以其他的没有显示。

请注意,如果没有父节点重写,实际上不可能讨论提交之间的父/子关系,所以我们将它们显示为断开的。

--full-history with parent rewriting(使用父节点重写的完整历史)

只有当普通提交是 !TREESAME 时才会被包含(尽管这可以改变,请参见下面的 --sparse)。

合并始终会被包含。但是,它们的父列表会被重写:沿着每个父节点,剪除掉未被包含的提交。这导致了

	  .-A---M---N---O---P---Q
	 /     /   /   /   /
	I     B   /   D   /
	 \   /   /   /   /
	  `-------------'

与上面没有重写的 --full-history 相比。请注意,E 因为它是 TREESAME 的而被剪除,但是 P 的父列表被重写为包含 E 的父节点 ICN,以及 XYQ 也发生了同样的事情。

除了上述设置外,您还可以更改 TREESAME 是否影响包含

--dense

如果提交与任何父提交都不是 TREESAME 的,则该提交将被包含。

--sparse

所有被遍历的提交都会被包含。

请注意,如果没有 --full-history,这仍然会简化合并:如果其中一个父提交是 TREESAME 的,我们只跟踪这一个,因此合并的其他分支永远不会被遍历。

--simplify-merges

首先,以与使用父节点重写的 --full-history 相同的方式构建历史图(参见上文)。

然后,根据以下规则,将每个提交 C 简化为其在最终历史中的替代项 C'

  • C' 设置为 C

  • 用其简化版本 P' 替换 C' 的每个父提交 P。在此过程中,删除是其他父提交的祖先,或者与空树 TREESAME 的根提交的父提交,并删除重复项,但要注意不要删除我们 TREESAME 的所有父提交。

  • 如果在此父节点重写之后,C' 是根提交或合并提交(有零个或 >1 个父提交),边界提交,或 !TREESAME,则它保持不变。否则,它将被其唯一的父提交替换。

将此与使用父节点重写的 --full-history 进行比较,可以最好地展示此选项的效果。该示例变为

	  .-A---M---N---O
	 /     /       /
	I     B       D
	 \   /       /
	  `---------'

请注意 NPQ--full-history 相比的主要区别

  • N 的父列表中移除了 I,因为它 是另一个父提交 M 的祖先。尽管如此,N 仍然存在,因为它不是 !TREESAME。

  • P 的父列表中同样移除了 I。然后完全移除了 P,因为它只有一个父提交并且是 TREESAME。

  • Q 的父列表将 Y 简化为 X。然后移除了 X,因为它是 TREESAME 根提交。然后完全移除了 Q,因为它只有一个父提交并且是 TREESAME。

还有另一种简化模式可用

--ancestry-path[=<commit>](祖先路径)

将显示的提交限制为 <commit> 的祖先或 <commit> 的后代,或 <commit> 本身。

作为一个用例示例,请考虑以下提交历史

	    D---E-------F
	   /     \       \
	  B---C---G---H---I---J
	 /                     \
	A-------K---------------L--M

常规的 D..M 计算 M 的祖先的集合,但不包括 D 的祖先。这对于查看自 D 以来导致 M 的历史发生了什么很有用,即“M 拥有什么 D 中不存在的东西”。在本示例中,结果将是所有提交,除了 AB(当然还有 D 本身)。

但是,当我们想找出 M 中哪些提交被 D 引入的错误污染并需要修复时,我们可能只想查看 D..M 中实际上是 D 的后代的子集,即排除 CK。这正是 --ancestry-path 选项的作用。应用于 D..M 范围,它会导致

		E-------F
		 \       \
		  G---H---I---J
			       \
				L--M

我们也可以使用 --ancestry-path=D 代替 --ancestry-path,当应用于 D..M 范围时,这意味着相同的事情,但更明确。

如果我们对该范围内给定的主题以及受该主题影响的所有提交感兴趣,我们可能只想查看 D..M 的子集,该子集在其祖先路径中包含该主题。因此,例如,使用 --ancestry-path=H D..M 将导致

		E
		 \
		  G---H---I---J
			       \
				L--M

--ancestry-path=K D..M 将导致

		K---------------L--M

在讨论另一个选项 --show-pulls 之前,我们需要创建一个新的示例历史。

用户在查看简化历史时面临的一个常见问题是,他们知道某个提交以某种方式更改了文件,但该提交未出现在该文件的简化历史中。让我们演示一个新示例,并展示诸如 --full-history--simplify-merges 之类的选项在这种情况下如何工作

	  .-A---M-----C--N---O---P
	 /     / \  \  \/   /   /
	I     B   \  R-'`-Z'   /
	 \   /     \/         /
	  \ /      /\        /
	   `---X--'  `---Y--'

对于此示例,假设 I 创建了 file.txt,该文件被 ABX 以不同的方式修改。单亲提交 CZY 不会更改 file.txt。合并提交 M 是通过解决合并冲突以包含来自 AB 的更改而创建的,因此它与两者都不是 TREESAME 的。但是,合并提交 R 是通过忽略 M 处的 file.txt 的内容并仅获取 X 处的 file.txt 的内容而创建的。因此,RX 是 TREESAME 的,但与 M 不是。最后,创建 N 的自然合并解析是获取 R 处的 file.txt 的内容,因此 NR 是 TREESAME 的,但与 C 不是。合并提交 OP 与它们的第一个父提交是 TREESAME 的,但与它们的第二个父提交 ZY 不是。

使用默认模式时,NR 都有一个 TREESAME 父提交,因此会遍历这些边,而忽略其他边。生成的历史图是

	I---X

使用 --full-history 时,Git 会遍历每一条边。这将发现提交 AB 以及合并 M,但也会显示合并提交 OP。使用父节点重写,生成的图是

	  .-A---M--------N---O---P
	 /     / \  \  \/   /   /
	I     B   \  R-'`--'   /
	 \   /     \/         /
	  \ /      /\        /
	   `---X--'  `------'

在这里,合并提交 OP 贡献了额外的噪音,因为它们实际上没有对 file.txt 做出更改。它们只是合并了一个基于较旧版本的 file.txt 的主题。这是在使用工作流程的存储库中的一个常见问题,在这种工作流程中,许多贡献者并行工作并将他们的主题分支沿着单个主干合并:许多不相关的合并出现在 --full-history 结果中。

使用 --simplify-merges 选项时,提交 OP 将从结果中消失。这是因为可以从 OP 的第一个父提交访问它们重写的第二个父提交。这些边被移除,然后提交看起来像与它们的父提交是 TREESAME 的单亲提交。提交 N 也会发生这种情况,从而产生如下的历史视图

	  .-A---M--.
	 /     /    \
	I     B      R
	 \   /      /
	  \ /      /
	   `---X--'

在此视图中,我们看到了来自 ABX 的所有重要的单亲更改。我们还看到了仔细解析的合并 M 和未仔细解析的合并 R。通常,这些信息足以确定为什么提交 AB 从默认视图中的历史中“消失”了。但是,这种方法存在一些问题。

第一个问题是性能。与任何先前的选项不同,--simplify-merges 选项需要遍历整个提交历史才能返回单个结果。这使得该选项对于非常大的存储库来说难以使用。

第二个问题是审计问题。当许多贡献者在同一个存储库上工作时,哪个合并提交将更改引入到重要分支中非常重要。上面的问题合并 R 不太可能是用于合并到重要分支中的合并提交。相反,合并 N 用于将 RX 合并到重要分支中。此提交可能包含有关为什么更改 X 在其提交消息中覆盖来自 AB 的更改的信息。

--show-pulls

除了默认历史中显示的提交外,还显示每个与它的第一个父提交不是 TREESAME 的但与后面的父提交是 TREESAME 的合并提交。

当合并提交被 --show-pulls 包含时,该合并被视为从另一个分支“拉取”了更改。在此示例中使用 --show-pulls(且没有其他选项)时,生成的图是

	I---X---R---N

在这里,合并提交 RN 被包含,因为它们分别将提交 XR 拉入基本分支。这些合并是 AB 未出现在默认历史中的原因。

--show-pulls--simplify-merges 配对时,该图包含所有必要的信息

	  .-A---M--.   N
	 /     /    \ /
	I     B      R
	 \   /      /
	  \ /      /
	   `---X--'

请注意,由于可以从 R 访问 M,因此从 NM 的边被简化了。但是,N 仍然出现在历史中,因为它“拉取”了更改 R 进入主分支。

--simplify-by-decoration 选项允许您仅查看历史拓扑的大图,方法是省略未被标记引用的提交。如果(1)它们被标记引用,或者(2)它们更改了命令行上给定的路径的内容,则提交被标记为 !TREESAME(换句话说,在上面描述的历史简化规则之后保留)。所有其他提交都标记为 TREESAME(可以简化)。

提交排序

默认情况下,提交按时间倒序显示。

--date-order

在显示任何父提交之前,先显示其所有子提交,否则按提交时间戳顺序显示提交。

--author-date-order

在显示任何父提交之前,先显示其所有子提交,否则按作者时间戳顺序显示提交。

--topo-order

在显示任何父提交之前,先显示其所有子提交,并避免在多个历史记录行中混合显示提交。

例如,在这样的提交历史中

    ---1----2----4----7
	\	       \
	 3----5----6----8---

其中数字表示提交时间戳的顺序,带有 --date-ordergit rev-list 和 friends 按时间戳顺序显示提交:8 7 6 5 4 3 2 1。

使用 --topo-order,它们将显示 8 6 5 3 7 4 2 1(或 8 7 4 2 6 5 3 1);一些较旧的提交在较新的提交之前显示,以避免显示来自两个并行开发轨道的混合在一起的提交。

--reverse

按相反的顺序输出选择显示的提交(请参阅上面的“提交限制”部分)。不能与 --walk-reflogs 组合使用。

对象遍历

这些选项主要针对 Git 存储库的打包。

--no-walk[=(sorted|unsorted)]

仅显示给定的提交,但不遍历其祖先。如果指定了范围,则无效。如果给出了参数 unsorted,则提交将按照它们在命令行中给出的顺序显示。否则(如果给出了 sorted 或没有给出参数),则提交将按提交时间的倒序显示。不能与 --graph 组合使用。

--do-walk

覆盖先前的 --no-walk

提交格式

--pretty[=<格式>]
--format=<格式>

以给定的格式美化打印提交日志的内容,其中<格式>可以是 onelineshortmediumfullfullerreferenceemailrawformat:<string>tformat:<string>。 当<格式>不是上述任何一个,并且包含%placeholder时,它的行为就像给定了--pretty=tformat:<格式> 一样。

有关每种格式的更多详细信息,请参阅“美化格式”部分。 当省略=<格式>部分时,默认值为medium

注意:您可以在存储库配置中指定默认的美化格式(请参阅 git-config[1])。

--abbrev-commit

不显示完整的 40 字节十六进制提交对象名称,而是显示一个唯一命名该对象的前缀。 "--abbrev=<n>"(如果显示,也会修改 diff 输出)选项可用于指定前缀的最小长度。

这应该使 "--pretty=oneline" 对于使用 80 列终端的人来说更具可读性。

--no-abbrev-commit

显示完整的 40 字节十六进制提交对象名称。 这会否定 --abbrev-commit,无论是显式的还是由其他选项(如 "--oneline")暗示的。 它还会覆盖 log.abbrevCommit 变量。

--oneline

这是 "--pretty=oneline --abbrev-commit" 一起使用的简写。

--encoding=<编码>

提交对象记录了在其编码头中用于日志消息的字符编码; 可以使用此选项来告诉命令以用户首选的编码重新编码提交日志消息。 对于非管道命令,这默认为 UTF-8。 请注意,如果一个对象声称以 X 编码,并且我们以 X 输出,我们将逐字输出该对象; 这意味着原始提交中的无效序列可能会被复制到输出。 同样,如果 iconv(3) 无法转换提交,我们将安静地逐字输出原始对象。

--expand-tabs=<n>
--expand-tabs
--no-expand-tabs

在输出中显示日志消息之前,执行制表符扩展(将每个制表符替换为足够的空格,以填充到下一个显示列,该列是 <n> 的倍数)。 --expand-tabs--expand-tabs=8 的简写,--no-expand-tabs--expand-tabs=0 的简写,后者禁用制表符扩展。

默认情况下,制表符在以 4 个空格缩进日志消息的美化格式中展开(即medium,这是默认值,fullfuller)。

--notes[=<ref>]

显示注释提交的注释(参见 git-notes[1]),当显示提交日志消息时。 当命令行上没有给出 --pretty--format--oneline 选项时,这是 git loggit showgit whatchanged 命令的默认设置。

默认情况下,显示的注释来自 core.notesRefnotes.displayRef 变量(或相应的环境覆盖)中列出的注释引用。 有关更多详细信息,请参阅 git-config[1]

使用可选的 <ref> 参数,使用 ref 查找要显示的注释。 当 ref 以 refs/notes/ 开头时,它可以指定完整的 refname; 当它以 notes/ 开头时,refs/,否则 refs/notes/ 将作为前缀以形成 ref 的完整名称。

可以组合多个 --notes 选项来控制要显示的注释。 示例:"--notes=foo" 将仅显示来自 "refs/notes/foo" 的注释; "--notes=foo --notes" 将同时显示来自 "refs/notes/foo" 和来自默认注释引用中的注释。

--no-notes

不显示注释。 这通过重置从中显示注释的注释引用列表来否定上面的 --notes 选项。 选项按照在命令行上给出的顺序进行解析,因此例如 "--notes --notes=foo --no-notes --notes=bar" 将仅显示来自 "refs/notes/bar" 的注释。

--show-notes-by-default

除非给出了显示特定注释的选项,否则显示默认注释。

--show-notes[=<ref>]
--[no-]standard-notes

这些选项已弃用。 请改用上面的 --notes/--no-notes 选项。

--show-signature

通过将签名传递给 gpg --verify 来检查已签名提交对象的有效性并显示输出。

--relative-date

--date=relative 的同义词。

--date=<格式>

仅对以人类可读格式显示的日期生效,例如使用 --pretty 时。 log.date 配置变量为 log 命令的 --date 选项设置默认值。 默认情况下,日期以原始时区(提交者或作者的时区)显示。 如果将 -local 附加到格式(例如,iso-local),则改用用户的本地时区。

--date=relative 显示相对于当前时间的日期,例如“2 小时前”。 -local 选项对 --date=relative 没有影响。

--date=local--date=default-local 的别名。

--date=iso(或 --date=iso8601)以类似于 ISO 8601 的格式显示时间戳。 与严格的 ISO 8601 格式的不同之处在于

  • 日期/时间分隔符使用空格而不是 T

  • 时间和时区之间有一个空格

  • 时区的小时和分钟之间没有冒号

--date=iso-strict(或 --date=iso8601-strict)以严格的 ISO 8601 格式显示时间戳。

--date=rfc(或 --date=rfc2822)以 RFC 2822 格式显示时间戳,通常在电子邮件消息中找到。

--date=short 仅以 YYYY-MM-DD 格式显示日期,但不显示时间。

--date=raw 将日期显示为自 epoch 以来的秒数(1970-01-01 00:00:00 UTC),后跟一个空格,然后是时区作为与 UTC 的偏移量(+- 带有四位数字;前两位是小时,后两位是分钟)。 即,好像时间戳是用 strftime("%s %z") 格式化的)。 请注意,-local 选项不会影响 epoch 后的秒数值(始终以 UTC 测量),但会切换随附的时区值。

--date=human 如果时区与当前时区不匹配,则显示时区,如果匹配则不打印整个日期(即跳过打印“今年”的日期的年份,但如果日期在最近几天并且我们可以只说它是星期几,则也跳过整个日期本身)。 对于较旧的日期,小时和分钟也被省略。

--date=unix 将日期显示为 Unix epoch 时间戳(自 1970 年以来的秒数)。 与 --raw 一样,这始终以 UTC 为单位,因此 -local 无效。

--date=format:... 将格式 ... 提供给您的系统 strftime,但 %s、%z 和 %Z 除外,这些由内部处理。 使用 --date=format:%c 以您的系统区域设置的首选格式显示日期。 有关格式占位符的完整列表,请参阅 strftime 手册。 使用 -local 时,正确的语法是 --date=format-local:...

--date=default 是默认格式,基于 ctime(3) 输出。 它显示单行,包含星期几的三个字母,月份的三个字母,日期,以“HH:MM:SS”格式的小时-分钟-秒,后跟 4 位数年份,加上时区信息,除非使用本地时区,例如 Thu Jan 1 00:00:00 1970 +0000

--parents

也打印提交的父级(格式为“commit parent…”)。 还启用了父级重写,请参阅上面的历史简化

--children

也打印提交的子级(格式为“commit child…”)。 还启用了父级重写,请参阅上面的历史简化

--left-right

标记提交可以从对称差异的哪一侧访问。 来自左侧的提交以 < 为前缀,来自右侧的提交以 > 为前缀。 如果与 --boundary 结合使用,则这些提交以 - 为前缀。

例如,如果您有此拓扑

	     y---b---b  branch B
	    / \ /
	   /   .
	  /   / \
	 o---x---a---a  branch A

您将获得如下输出

	$ git rev-list --left-right --boundary --pretty=oneline A...B

	>bbbbbbb... 3rd on b
	>bbbbbbb... 2nd on b
	<aaaaaaa... 3rd on a
	<aaaaaaa... 2nd on a
	-yyyyyyy... 1st on b
	-xxxxxxx... 1st on a
--graph

在输出的左侧绘制一个基于文本的提交历史图形表示。 这可能会导致在提交之间打印额外的行,以便正确绘制图形历史记录。 不能与 --no-walk 结合使用。

这启用了父级重写,请参阅上面的历史简化

默认情况下,这暗示了 --topo-order 选项,但也可以指定 --date-order 选项。

--show-linear-break[=<barrier>]

当不使用 --graph 时,所有历史分支都会被展平,这可能会难以看出两个连续的提交不属于线性分支。 在这种情况下,此选项会在它们之间放置一个屏障。 如果指定了 <barrier>,则它是将显示的字符串,而不是默认字符串。

美化格式

如果提交是合并,并且如果美化格式不是onelineemailraw,则会在 Author: 行之前插入一行。 此行以 "Merge: " 开头,祖先提交的哈希值以空格分隔打印。 请注意,如果您限制了历史记录的视图,则列出的提交不一定是直接父级提交的列表:例如,如果您只对与某个目录或文件相关的更改感兴趣。

有几种内置格式,您可以通过将 `pretty.<name>` 配置选项设置为另一个格式名称,或者设置为 `format:` 字符串来定义其他格式,如下所述(请参阅 git-config[1])。以下是内置格式的详细信息

  • oneline

    <hash> <title-line>

    设计得尽可能紧凑。

  • short

    commit <hash>
    Author: <author>
    <title-line>
  • medium

    commit <hash>
    Author: <author>
    Date:   <author-date>
    <title-line>
    <full-commit-message>
  • full

    commit <hash>
    Author: <author>
    Commit: <committer>
    <title-line>
    <full-commit-message>
  • fuller

    commit <hash>
    Author:     <author>
    AuthorDate: <author-date>
    Commit:     <committer>
    CommitDate: <committer-date>
    <title-line>
    <full-commit-message>
  • reference

    <abbrev-hash> (<title-line>, <short-author-date>)

    此格式用于在提交消息中引用另一个提交,与 `--pretty='format:%C(auto)%h (%s, %ad)'` 相同。默认情况下,日期使用 `--date=short` 格式化,除非明确指定了另一个 `--date` 选项。与任何带有格式占位符的 `format:` 一样,其输出不受 `--decorate` 和 `--walk-reflogs` 等其他选项的影响。

  • email

    From <hash> <date>
    From: <author>
    Date: <author-date>
    Subject: [PATCH] <title-line>
    <full-commit-message>
  • mboxrd

    与 *email* 类似,但是提交消息中以 "From " 开头的行(前面有零个或多个 ">")会用 ">" 引用,以免被误认为是新提交的开始。

  • raw

    *raw* 格式会完全按照提交对象中存储的方式显示整个提交。值得注意的是,无论是否使用 `--abbrev` 或 `--no-abbrev`,哈希都会以完整形式显示,并且 *parents* 信息会显示真实的父提交,而不考虑 grafts 或历史简化。请注意,此格式会影响提交的显示方式,但不会影响 diff 的显示方式,例如使用 `git log --raw`。要在原始 diff 格式中获取完整的对象名称,请使用 `--no-abbrev`。

  • format:<format-string>

    *format:<format-string>* 格式允许您指定要显示的信息。它的工作方式有点像 printf 格式,但值得注意的是,您使用 *%n* 而不是 *\n* 来获取换行符。

    例如,format:"The author of %h was %an, %ar%nThe title was >>%s<<%n" 将显示如下内容

    The author of fe6e0ee was Junio C Hamano, 23 hours ago
    The title was >>t4119: test autocomputing -p<n> for traditional diff input.<<

    占位符是

    • 扩展为单个文字字符的占位符

      %n

      换行符

      %%

      原始的 %

      %x00

      %x 后跟两个十六进制数字将被替换为具有该十六进制数字值的字节(我们将在本文档的其余部分中称其为“文字格式代码”)。

    • 影响后续占位符格式的占位符

      %Cred

      将颜色切换为红色

      %Cgreen

      将颜色切换为绿色

      %Cblue

      将颜色切换为蓝色

      %Creset

      重置颜色

      %C(…​)

      颜色规范,如 git-config[1] 的 "CONFIGURATION FILE" 部分的 Values 下所述。默认情况下,仅当为日志输出启用颜色时(通过 `color.diff`、`color.ui` 或 `--color`,并在我们进入终端时遵守前者的 `auto` 设置),才会显示颜色。`%C(auto,...)` 被接受为默认设置的历史同义词(例如,`%C(auto,red)`)。指定 `%C(always,...)` 即使在没有其他方式启用颜色时也会显示颜色(尽管可以考虑直接使用 `--color=always` 为整个输出启用颜色,包括此格式和 git 可能着色的任何其他内容)。单独的 `auto`(即 `%C(auto)`)将打开下一个占位符上的自动着色,直到颜色再次切换。

      %m

      左侧 (<)、右侧 (>) 或边界 (-) 标记

      %w([<w>[,<i1>[,<i2>]]])

      切换换行,类似于 git-shortlog[1] 的 -w 选项。

      %<( <N> [,trunc|ltrunc|mtrunc])

      使下一个占位符至少占用 N 列宽度,必要时在右侧填充空格。如果输出长于 N 列,可以选择在左侧 (ltrunc) 以省略号 *..* 截断 `..ft`,中间 (mtrunc) `mi..le`,或结尾 (trunc) `rig..`。注意 1:截断仅在 N >= 2 时才能正确工作。注意 2:N 和 M(见下文)值周围的空格是可选的。注意 3:表情符号和其他宽字符将占用两个显示列,这可能会超出列边界。注意 4:分解的字符组合标记可能会在填充边界处错位。

      %<|( <M> )

      使下一个占位符至少占用到第 M 列显示位置,必要时在右侧填充空格。使用负 M 值来表示从终端窗口右侧边缘测量的列位置。

      %>( <N> ), %>|( <M> )

      分别类似于 *%<( <N> )*,*%<|( <M> )*,但左侧填充空格

      %>>( <N> ), %>>|( <M> )

      分别类似于 *%>( <N> )*,*%>|( <M> )*,除非下一个占位符占用的空间多于给定的空间,并且其左侧有空格,则使用这些空格

      %><( <N> ), %><|( <M> )

      分别类似于 *%<( <N> )*,*%<|( <M> )*,但在两侧都填充(即文本居中)

    • 扩展为从提交中提取的信息的占位符

      %H

      提交哈希

      %h

      缩写的提交哈希

      %T

      树哈希

      %t

      缩写的树哈希

      %P

      父哈希

      %p

      缩写的父哈希

      %an

      作者姓名

      %aN

      作者姓名(尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %ae

      作者电子邮件

      %aE

      作者电子邮件(尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %al

      作者电子邮件本地部分(*@* 符号之前的部分)

      %aL

      作者本地部分(请参阅 *%al*)尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %ad

      作者日期(格式尊重 --date= 选项)

      %aD

      作者日期,RFC2822 样式

      %ar

      作者日期,相对

      %at

      作者日期,UNIX 时间戳

      %ai

      作者日期,类似 ISO 8601 的格式

      %aI

      作者日期,严格的 ISO 8601 格式

      %as

      作者日期,短格式 (YYYY-MM-DD)

      %ah

      作者日期,人类可读的风格(类似于 git-rev-list[1]--date=human 选项)

      %cn

      提交者姓名

      %cN

      提交者姓名(尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %ce

      提交者电子邮件

      %cE

      提交者电子邮件(尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %cl

      提交者电子邮件本地部分(*@* 符号之前的部分)

      %cL

      提交者本地部分(请参阅 *%cl*)尊重 .mailmap,请参阅 git-shortlog[1]git-blame[1]

      %cd

      提交者日期(格式尊重 --date= 选项)

      %cD

      提交者日期,RFC2822 样式

      %cr

      提交者日期,相对

      %ct

      提交者日期,UNIX 时间戳

      %ci

      提交者日期,类似 ISO 8601 的格式

      %cI

      提交者日期,严格的 ISO 8601 格式

      %cs

      提交者日期,短格式 (YYYY-MM-DD)

      %ch

      提交者日期,人类可读的风格(类似于 git-rev-list[1]--date=human 选项)

      %d

      引用名称,如 git-log[1] 的 --decorate 选项

      %D

      没有 " (",")" 包装的引用名称。

      %(decorate[:<options>])

      具有自定义修饰的引用名称。`decorate` 字符串后可以跟一个冒号和零个或多个逗号分隔的选项。选项值可以包含文字格式代码。这些必须用于逗号 (%x2C) 和右括号 (%x29),因为它们在选项语法中起作用。

      • prefix=<value>:显示在引用名称列表之前。默认为 " ("。

      • suffix=<value>:显示在引用名称列表之后。默认为 ")"。

      • separator=<value>:显示在引用名称之间。默认为 ", "。

      • pointer=<value>:显示在 HEAD 和它指向的分支之间(如果存在)。默认为 " -> "。

      • tag=<value>:显示在标签名称之前。默认为 "tag: "。

    例如,要生成没有包装或标签注释的修饰,并使用空格作为分隔符

    + %(decorate:prefix=,suffix=,tag=,separator= )

    %(describe[:<options>])

    人类可读的名称,如 git-describe[1];对于无法描述的提交,则为空字符串。`describe` 字符串后可以跟一个冒号和零个或多个逗号分隔的选项。当同时添加或删除标签时,描述可能不一致。

    • tags[=<bool-value>]:不只考虑带注释的标签,还要考虑轻量级标签。

    • abbrev=<number>:不使用缩写对象名称的默认十六进制位数(将根据存储库中对象的数量而变化,默认值为 7),而是使用 <number> 位数,或形成唯一对象名称所需的位数。

    • match=<pattern>:仅考虑与给定的 `glob(7)` 模式匹配的标签,不包括 "refs/tags/" 前缀。

    • exclude=<pattern>:不考虑与给定的 `glob(7)` 模式匹配的标签,不包括 "refs/tags/" 前缀。

    %S

    命令行中给出的引用名称,用于确定提交(如 git log --source),仅适用于 git log

    %e

    编码

    %s

    主题

    %f

    经过清理的主题行,适合作为文件名

    %b

    正文

    %B

    原始正文(未换行的主题和正文)

    %N

    提交说明

    %GG

    来自 GPG 的签名提交的原始验证消息

    %G?

    对于好的(有效的)签名,显示 "G";对于坏的签名,显示 "B";对于具有未知有效性的好的签名,显示 "U";对于已过期的好的签名,显示 "X";对于由已过期的密钥创建的好的签名,显示 "Y";对于由已撤销的密钥创建的好的签名,显示 "R";如果无法检查签名(例如,缺少密钥),则显示 "E";如果没有签名,则显示 "N"

    %GS

    显示签名提交的签名者姓名

    %GK

    显示用于签署签名提交的密钥

    %GF

    显示用于签署签名提交的密钥的指纹

    %GP

    显示用于签署签名提交的子密钥所属的主密钥的指纹

    %GT

    显示用于签署签名提交的密钥的信任级别

    %gD

    reflog 选择器,例如,refs/stash@{1}refs/stash@{2 minutes ago};格式遵循为 -g 选项描述的规则。@ 之前的部分是在命令行上给出的引用名称(因此 git log -g refs/heads/master 将产生 refs/heads/master@{0})。

    %gd

    缩短的 reflog 选择器;与 %gD 相同,但 refname 部分为了便于人类阅读而缩短(因此 refs/heads/master 仅变为 master)。

    %gn

    reflog 身份名称

    %gN

    reflog 身份名称(尊重 .mailmap,参见 git-shortlog[1]git-blame[1]

    %ge

    reflog 身份电子邮件

    %gE

    reflog 身份电子邮件(尊重 .mailmap,参见 git-shortlog[1]git-blame[1]

    %gs

    reflog 主题

    %(trailers[:<options>])

    显示正文的 trailers,由 git-interpret-trailers[1] 解释。trailers 字符串后可以跟一个冒号和零个或多个逗号分隔的选项。如果提供了多个选项,则最后一次出现优先。

    • key=<key>: 仅显示具有指定 <key> 的 trailers。匹配不区分大小写,并且尾随冒号是可选的。如果多次给出选项,则显示与任何键匹配的 trailer 行。此选项自动启用 only 选项,以便隐藏 trailer 块中的非 trailer 行。 如果不希望这样做,可以使用 only=false 禁用。 例如,%(trailers:key=Reviewed-by) 显示键为 Reviewed-by 的 trailer 行。

    • only[=<bool>]: 选择是否应包含 trailer 块中的非 trailer 行。

    • separator=<sep>: 指定插入在 trailer 行之间的分隔符。默认为换行符。字符串 <sep> 可以包含上面描述的文字格式代码。要使用逗号作为分隔符,必须使用 %x2C,否则它将被解析为下一个选项。 例如,%(trailers:key=Ticket,separator=%x2C ) 显示所有键为 "Ticket" 的 trailer 行,并用逗号和空格分隔。

    • unfold[=<bool>]: 使其行为如同给出了 interpret-trailer 的 --unfold 选项一样。 例如,%(trailers:only,unfold=true) 展开并显示所有 trailer 行。

    • keyonly[=<bool>]: 仅显示 trailer 的键部分。

    • valueonly[=<bool>]: 仅显示 trailer 的值部分。

    • key_value_separator=<sep>: 指定插入在每个 trailer 的键和值之间的分隔符。默认为 ": "。 否则,它与上面的 separator=<sep> 共享相同的语义。

注意
某些占位符可能取决于传递给修订遍历引擎的其他选项。例如,除非我们正在遍历 reflog 条目(例如,通过 git log -g),否则 %g* reflog 选项将插入一个空字符串。如果命令行上尚未提供 --decorate,则 %d%D 占位符将使用“短”装饰格式。

布尔选项接受可选值 [=<bool-value>]--type=bool git-config[1] 采用的值,例如 yesoff,都被接受。在没有 =<value> 的情况下给出布尔选项等同于给出带有 =true 的布尔选项。

如果在占位符的 % 之后添加 +(加号),则仅当占位符展开为非空字符串时,才会在展开之前立即插入换行符。

如果在占位符的 % 之后添加 -(减号),则仅当占位符展开为空字符串时,才删除紧接在展开之前的所有连续换行符。

如果在占位符的 % 之后添加一个 ` ` (空格),则仅当占位符展开为非空字符串时,才会在展开之前立即插入一个空格。

  • tformat

    tformat: 格式的工作方式与 format: 完全相同,不同之处在于它提供“终止符”语义而不是“分隔符”语义。换句话说,每个提交都附加了消息终止符字符(通常是换行符),而不是在条目之间放置分隔符。这意味着单行格式的最终条目将使用新行正确终止,就像“oneline”格式一样。例如

    $ git log -2 --pretty=format:%h 4da45bef \
      | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
    4da45be
    7134973 -- NO NEWLINE
    
    $ git log -2 --pretty=tformat:%h 4da45bef \
      | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
    4da45be
    7134973

    此外,任何包含 % 的无法识别的字符串都将被解释为好像它前面带有 tformat:。例如,以下两者是等效的

    $ git log -2 --pretty=tformat:%h 4da45bef
    $ git log -2 --pretty=%h 4da45bef

DIFF 格式

默认情况下,git log 不会生成任何 diff 输出。可以使用以下选项来显示每次提交所做的更改。

请注意,除非显式给出 --diff-merges 变体之一(包括短 -m-c--cc--dd 选项),否则即使选择了 --patch 之类的 diff 格式,合并提交也不会显示 diff,也不会匹配 -S 之类的搜索选项。例外情况是使用 --first-parent 时,在这种情况下,first-parent 是合并提交的默认格式。

-p
-u
--patch

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

-s
--no-patch

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

-m

以默认格式显示合并提交的差异。这类似于 --diff-merges=on,但除非同时给出 -p,否则 -m 不会产生任何输出。

-c

为合并提交生成组合的差异输出。 --diff-merges=combined -p 的快捷方式。

--cc

为合并提交生成密集的组合差异输出。 --diff-merges=dense-combined -p 的快捷方式。

--dd

为合并提交和常规提交生成相对于第一个父级的差异。 --diff-merges=first-parent -p 的快捷方式。

--remerge-diff

为合并提交生成 remerge-diff 输出。 --diff-merges=remerge -p 的快捷方式。

--no-diff-merges

--diff-merges=off 的同义词。

--diff-merges=<format>

指定用于合并提交的差异格式。除非使用 --first-parent,否则默认为“off”,在这种情况下,first-parent 是默认值。

支持以下格式

off, none

禁用合并提交的差异输出。 可用于覆盖隐含值。

on, m

使合并提交的差异输出以默认格式显示。 可以使用 log.diffMerges 配置变量更改默认格式,其默认值为 separate

first-parent, 1

显示相对于第一个父级的完整差异。 这与 --patch 为非合并提交生成的格式相同。

separate

显示相对于每个父级的完整差异。 为每个父级生成单独的日志条目和差异。

combined, c

同时显示从每个父级到合并结果的差异,而不是一次显示一个父级与结果之间的成对差异。 此外,它仅列出从所有父级修改过的文件。

dense-combined, cc

通过省略父级中内容只有两种变体且合并结果选择其中一种而未修改的无趣的代码块,进一步压缩 --diff-merges=combined 产生的输出。

remerge, r

重新合并双亲合并提交以创建一个临时树对象——可能包含带有冲突标记等的文件。 然后,在该临时树和实际合并提交之间显示差异。

使用此选项发出的输出可能会发生变化,并且它与其他选项的交互也可能会发生变化(除非明确记录)。

--combined-all-paths

使组合的差异(用于合并提交)列出所有父级中的文件名。 因此,它仅在使用 --diff-merges=[dense-]combined 时有效,并且可能仅在检测到文件名更改时才有用(即,当请求了重命名或复制检测时)。

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

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

--output=<文件>

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

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

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

--raw

对于每个提交,使用原始差异格式显示更改的摘要。请参阅 git-diff[1] 的“原始输出格式”部分。这与以原始格式显示日志本身不同,您可以使用 --format=raw 实现这一点。

--patch-with-raw

-p --raw 的同义词。

-t

在 diff 输出中显示 tree 对象。

--indent-heuristic

启用启发式算法,该算法移动 diff hunk 边界以使补丁更易于阅读。这是默认设置。

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

此算法扩展了 patience 算法以“支持低频公共元素”。

例如,如果您将 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 会影响所有生成 stat 图的命令,而设置 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 分别用于添加或删除可执行位)在 diffstat 中。该信息位于文件名部分和图形部分之间。 意味着 --stat

--numstat

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

--shortstat

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

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

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

changes

通过计算从源中删除或添加到目标的行来计算 dirstat 数字。 这会忽略文件中的纯代码移动量。 换句话说,重新排列文件中的行不会像其他更改那样被计数。 这是未给出参数时的默认行为。

lines

通过执行基于行的常规差异分析并对删除/添加的行数求和来计算 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

用 *NUL* 而不是换行符分隔提交。

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

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

--name-only

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

--name-status

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

--submodule[=<格式>]

指定如何显示子模块中的差异。 当指定 --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

忽略行尾空白字符的更改。

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

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

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

在生成补丁格式输出时,在“index”行上显示完整的 pre- 和 post-image 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>]

如果生成差异,则检测并报告每个提交的重命名。有关在遍历历史记录时跟踪跨重命名的文件,请参见 --follow。如果指定了 <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

省略删除的preimage,即仅打印标头,而不打印preimage和/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>

查找更改文件中指定 *<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,否则没有 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

忽略行尾空白字符的更改。

-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] 中的“定义自定义块标头”)。

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

使用 -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 选项生成的结果与传统的 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>

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

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

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

    index 行包括更改前后的 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-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 <hash>,<hash>..<hash> mode <mode>,<mode>..<mode> new file mode <mode> deleted file 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. Chunk 头部格式已修改,以防止人们意外地将其馈送到 patch -p1。 创建组合差异格式是为了审查合并提交更改,而不是为了应用它。 更改类似于扩展的 index 头部中的更改

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

    在组合差异格式的 chunk 头部中,有(父级数量 + 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 是 stage 2 又名 "我们的版本",file2 是 stage 3 又名 "他们的版本")。

示例

git log --no-merges

显示整个提交历史,但跳过任何合并

git log v2.6.12.. include/scsi drivers/scsi

显示自版本 v2.6.12 以来,更改了 include/scsidrivers/scsi 子目录中任何文件的所有提交

git log --since="2 weeks ago" -- gitk

显示过去两周内对文件 gitk 所做的更改。 -- 是必要的,以避免与名为 gitk分支 混淆

git log --name-status release..test

显示 "test" 分支中但尚未在 "release" 分支中的提交,以及每个提交修改的路径列表。

git log --follow builtin/rev-list.c

显示更改了 builtin/rev-list.c 的提交,包括在文件被赋予当前名称之前发生的那些提交。

git log --branches --not --remotes=origin

显示任何本地分支中但不在 origin 的任何远程跟踪分支中的所有提交(您拥有的但 origin 没有的)。

git log master --not --remotes=*/master

显示本地 master 中但不在任何远程存储库 master 分支中的所有提交。

git log -p -m --first-parent

显示包括更改差异的历史记录,但仅从“主分支”的角度出发,跳过来自合并分支的提交,并显示合并引入的更改的完整差异。 只有在遵循严格的策略(即在停留在单个集成分支时合并所有主题分支)时,这才有意义。

git log -L '/int main/',/^}/:main.c

显示文件 main.c 中的函数 main() 随时间推移的演变过程。

git log -3

限制要显示的提交数为 3。

讨论

Git 在某种程度上对字符编码是不可知的。

  • blob 对象的内容是不加解释的字节序列。 在核心级别没有编码转换。

  • 路径名以 UTF-8 规范化形式 C 编码。这适用于树对象、索引文件、引用名称,以及命令行参数、环境变量和配置文件中的路径名(.git/config (请参阅 git-config[1])、gitignore[5]gitattributes[5]gitmodules[5]))。

    请注意,Git 在核心级别只是将路径名视为非 NUL 字节序列,没有路径名编码转换(Mac 和 Windows 除外)。 因此,即使在使用传统扩展 ASCII 编码的平台和文件系统上,使用非 ASCII 路径名也大多有效。 但是,在此类系统上创建的存储库在基于 UTF-8 的系统(例如 Linux、Mac、Windows)上将无法正常工作,反之亦然。 此外,许多基于 Git 的工具只是简单地假设路径名为 UTF-8,并且无法正确显示其他编码。

  • 提交日志消息通常以 UTF-8 编码,但也支持其他扩展 ASCII 编码。 这包括 ISO-8859-x、CP125x 和许多其他编码,但包括 UTF-16/32、EBCDIC 和 CJK 多字节编码(GBK、Shift-JIS、Big5、EUC-x、CP9xx 等)。

虽然我们鼓励提交日志消息以 UTF-8 编码,但核心和 Git Porcelain 都被设计为不强制项目使用 UTF-8。 如果特定项目的所有参与者都觉得使用传统编码更方便,则 Git 不会禁止它。 但是,需要记住一些事项。

  1. 如果给它的提交日志消息看起来不像有效的 UTF-8 字符串,则 git commitgit commit-tree 会发出警告,除非您明确说明您的项目使用传统编码。 说明这一点的方 式是在 .git/config 文件中包含 i18n.commitEncoding,如下所示

    [i18n]
    	commitEncoding = ISO-8859-1

    使用上述设置创建的提交对象会在其 encoding 头部中记录 i18n.commitEncoding 的值。 这有助于以后查看它们的其他人。 缺少此头部表示提交日志消息以 UTF-8 编码。

  2. git loggit showgit blame 及其类似命令会查看提交对象的 encoding 头部,并尝试将日志消息重新编码为 UTF-8,除非另有说明。 您可以使用 .git/config 文件中的 i18n.logOutputEncoding 指定所需的输出编码,如下所示

    [i18n]
    	logOutputEncoding = ISO-8859-1

    如果您没有此配置变量,则改为使用 i18n.commitEncoding 的值。

请注意,我们故意选择不在进行提交时重新编码提交日志消息以在提交对象级别强制使用 UTF-8,因为重新编码为 UTF-8 不一定是可逆操作。

配置

有关核心变量,请参阅 git-config[1],有关与差异生成相关的设置,请参阅 git-diff[1]

format.pretty

--format 选项的默认值。 (请参阅上面的漂亮格式。)默认为 medium

i18n.logOutputEncoding

显示日志时要使用的编码。 (请参阅上面的讨论。)如果设置了,则默认为 i18n.commitEncoding 的值,否则默认为 UTF-8。

本节中此行以上的所有内容都不包含在 git-config[1] 文档中。 以下内容与其中找到的内容相同

log.abbrevCommit

如果为 true,则使 git-log[1]git-show[1]git-whatchanged[1] 假定 --abbrev-commit。 您可以使用 --no-abbrev-commit 覆盖此选项。

log.date

log 命令设置默认的日期时间模式。 为 log.date 设置值类似于使用 git log--date 选项。 有关详细信息,请参阅 git-log[1]

如果格式设置为 "auto:foo" 且使用了分页器,则日期格式将使用 "foo" 格式。否则,将使用 "default" 格式。

log.decorate

打印 log 命令显示的任何提交的引用名称。如果指定了 short,则不打印引用名称前缀 refs/heads/refs/tags/refs/remotes/。如果指定了 full,则打印完整的引用名称(包括前缀)。如果指定了 auto,那么如果输出到终端,则引用名称的显示方式如同给定了 short,否则不显示引用名称。这与 git log--decorate 选项相同。

log.initialDecorationSet

默认情况下,git log 仅显示某些已知引用命名空间的修饰。如果指定了 all,则显示所有引用作为修饰。

log.excludeDecoration

从日志修饰中排除指定的模式。这类似于 --decorate-refs-exclude 命令行选项,但可以通过 --decorate-refs 选项覆盖配置选项。

log.diffMerges

设置当指定 --diff-merges=on 时使用的差异格式,详情请参阅 git-log[1] 中的 --diff-merges。默认为 separate

log.follow

如果为 true,当给定单个 <path> 时,git log 的行为将如同使用了 --follow 选项。这与 --follow 具有相同的限制,即它不能用于跟踪多个文件,并且在非线性历史记录中效果不佳。

log.graphColors

一个颜色列表,以逗号分隔,可以用于在 git log --graph 中绘制历史记录线。

log.showRoot

如果为 true,初始提交将显示为一个大型创建事件。这相当于对空树的差异。像 git-log[1]git-whatchanged[1] 这样的工具通常隐藏根提交,现在将显示它。默认为 True。

log.showSignature

如果为 true,则使 git-log[1]git-show[1]git-whatchanged[1] 假定 --show-signature

log.mailmap

如果为 true,则使 git-log[1]git-show[1]git-whatchanged[1] 假定 --use-mailmap,否则假定 --no-use-mailmap。默认为 True。

notes.mergeStrategy

解决注释冲突时默认选择哪种合并策略。必须是 manualourstheirsunioncat_sort_uniq 之一。默认为 manual。 有关每种策略的更多信息,请参阅 git-notes[1] 的“NOTES MERGE STRATEGIES”部分。

可以通过将 --strategy 选项传递给 git-notes[1] 来覆盖此设置。

notes.<name>.mergeStrategy

当将注释合并到 refs/notes/<name> 中时,选择哪种合并策略。这将覆盖更通用的 notes.mergeStrategy。 有关可用策略的更多信息,请参阅 git-notes[1] 中的“NOTES MERGE STRATEGIES”部分。

notes.displayRef

在使用 git log 系列命令显示提交消息时,除了 core.notesRefGIT_NOTES_REF 设置的默认值之外,还从哪些引用(如果是一个 glob 或多次指定,则是多个引用)读取注释。

可以使用 GIT_NOTES_DISPLAY_REF 环境变量覆盖此设置,该变量必须是以冒号分隔的引用或 glob 列表。

对于不存在的引用将发出警告,但与任何引用都不匹配的 glob 将被静默忽略。

可以使用 git-log[1] 系列命令的 --no-notes 选项或这些命令接受的 --notes=<ref> 选项禁用此设置。

core.notesRef 的有效值(可能被 GIT_NOTES_REF 覆盖)也隐式添加到要显示的引用列表中。

notes.rewrite.<command>

当使用 <command>(当前为 amendrebase)重写提交时,如果此变量为 false,则 git 不会将注释从原始提交复制到重写的提交。默认为 true。另请参阅下面的 notes.rewriteRef

可以使用 GIT_NOTES_REWRITE_REF 环境变量覆盖此设置,该变量必须是以冒号分隔的引用或 glob 列表。

notes.rewriteMode

在重写期间复制注释时(请参阅 notes.rewrite.<command> 选项),确定如果目标提交已经有注释该怎么办。 必须是 overwriteconcatenatecat_sort_uniqignore 之一。默认为 concatenate

可以使用 GIT_NOTES_REWRITE_MODE 环境变量覆盖此设置。

notes.rewriteRef

在重写期间复制注释时,指定应复制其注释的(完全限定)引用。可以是 glob,在这种情况下,将复制所有匹配引用中的注释。您也可以多次指定此配置。

没有默认值;您必须配置此变量才能启用注释重写。将其设置为 refs/notes/commits 以启用默认提交注释的重写。

可以使用 GIT_NOTES_REWRITE_REF 环境变量覆盖。 有关其格式的进一步说明,请参阅上面的 notes.rewrite.<command>

GIT

git[1] 套件的一部分

scroll-to-top