名称

git-replay - 实验性:在新基上重放提交,也适用于裸仓库

概要

(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance <branch>) <revision-range>…​

描述

获取提交范围并将它们重放到新位置。 不会触及工作树和索引,也不会更新任何引用。 此命令的输出旨在用作 git update-ref --stdin 的输入,该命令将更新相关的分支(请参阅下面的 OUTPUT 部分)。

此命令是实验性的。 行为可能会改变。

选项

--onto <newbase>

创建新提交的起始点。 可以是任何有效的提交,而不仅仅是现有的分支名称。

当指定 --onto 时,输出中的 update-ref 命令会将修订范围中的分支更新为指向新提交,类似于 git rebase --update-refs 更新受影响范围中的多个分支的方式。

--advance <branch>

创建新提交的起始点;必须是分支名称。

当指定 --advance 时,输出中的 update-ref 命令会将作为参数传递给 --advance 的分支更新为指向新提交(换句话说,这模仿了 cherry-pick 操作)。

<revision-range>

要重放的提交范围。 可以传递多个 <revision-range>,但在 --advance <branch> 模式下,它们应该只有一个尖端,以便清楚 <branch> 应该指向哪里。 请参阅 git-rev-parse[1] 中的“指定范围”以及下面的“提交限制”选项。

提交限制

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

通常,使用更多选项会进一步限制输出(例如,--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=<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

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

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

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

当应用于 --branches--tags--remotes 时,给定的模式不应以 refs/headsrefs/tagsrefs/remotes 开头,并且当应用于 --glob--all 时,它们必须以 refs/ 开头。如果打算使用尾随的 /*,则必须明确给出。

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

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

--reflog

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

--alternate-refs

假装作为备用存储库的 ref 提示提到的所有对象都在命令行中列出。备用存储库是指其对象目录在 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-pick 的提交(例如,“b 上的第 3 个”可能从分支 A cherry-pick)。使用此选项,此类提交对将从输出中排除。

--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 中第一个现有的伪引用。仅当索引具有未合并的条目时才有效。此选项可用于在解决 3 向合并中的冲突时显示相关提交。

--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 父项时才跟随该父项的规则如何完全从考虑中删除了 BC 通过 N 进行考虑,但它是 TREESAME。根提交会与一个空树进行比较,因此 I 是 !TREESAME。

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

--full-history,不进行父级重写

此模式与默认模式的不同之处在于:始终跟随合并的所有父项,即使它对其中一个父项是 TREESAME。即使合并的多个方面都有包含的提交,这并不意味着合并本身是!在示例中,我们得到

	I  A  B  N  D  O  P  Q

M 被排除,因为它对两个父项都是 TREESAME。ECB 都被遍历,但只有 B 是 !TREESAME,因此其他的不显示。

请注意,如果没有父级重写,则实际上不可能讨论提交之间的父/子关系,因此我们将它们显示为断开连接。

--full-history,进行父级重写

只有在普通提交是 !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

  • C' 的每个父项 P 替换为其简化项 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 及其朋友以时间戳顺序显示提交: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>]
--format=<format>

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

有关每种格式的一些其他详细信息,请参见“漂亮格式”部分。 当省略 =<format> 部分时,它默认为 medium

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

--abbrev-commit

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

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

--no-abbrev-commit

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

--oneline

这是将“--pretty=oneline --abbrev-commit”一起使用的简写形式。

--encoding=<encoding>

提交对象在其编码标头中记录了用于日志消息的字符编码; 此选项可用于告诉命令以用户首选的编码重新编码提交日志消息。 对于非 plumbing 命令,这默认为 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])。 这是 git loggit showgit whatchanged 命令的默认设置,当命令行上没有给出 --pretty--format--oneline 选项时。

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

使用可选的 <ref> 参数,使用该引用查找要显示的注释。 当引用以 refs/notes/ 开头时,该引用可以指定完整的引用名称; 当它以 notes/ 开头时,refs/ 和其他情况下 refs/notes/ 会被添加到前缀以形成引用的完整名称。

可以组合多个 --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=<format>

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

--date=relative 显示相对于当前时间的日期,例如“2 hours ago”(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 时间戳(自 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>,它将是显示的字符串,而不是默认字符串。

输出

当没有冲突时,此命令的输出可用作 git update-ref --stdin 的输入。 它的形式是

update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}

其中更新的 refs 数量取决于传递的参数和正在重放的历史的形状。 使用 --advance 时,更新的 refs 数量始终为一个,但对于 --onto,它可以是一个或多个(支持同时重定位多个分支)。

退出状态

对于成功的、无冲突的重放,退出状态为 0。 当重放有冲突时,退出状态为 1。 如果由于某种错误导致重放无法完成(或开始),则退出状态为 0 或 1 之外的某个值。

示例

要简单地将 mybranch 重定位到 target

$ git replay --onto target origin/main..mybranch
update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}

要将来自 mybranch 的提交 cherry-pick 到 target 上

$ git replay --advance target origin/main..mybranch
update refs/heads/target ${NEW_target_HASH} ${OLD_target_HASH}

请注意,前两个示例重放了完全相同的提交,并且在完全相同的新基础之上,它们唯一的区别在于第一个示例提供了使 mybranch 指向新提交的指令,第二个示例提供了使 target 指向它们的指令。

如果你有一堆分支,一个依赖于另一个,并且你真的想重定位整个集合呢?

$ git replay --contained --onto origin/main origin/main..tipbranch
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}

在调用 git replay 时,不需要使用语法 A..B 指定要重放的提交范围;任何范围表达式都可以

$ git replay --onto origin/main ^base branch1 branch2 branch3
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}

这将同时重定位 branch1branch2branch3,它们自 base 以来的所有提交,并将它们重放到 origin/main 之上。 这三个分支可能在 base 之上有它们共同的提交,但这不必是这种情况。

GIT

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

scroll-to-top