【问题标题】:git log --reflog vs git reflog [closed]git log --reflog vs git reflog [关闭]
【发布时间】:2020-08-16 21:45:29
【问题描述】:

在玩了rm 等之后,我的git reflog 不再显示过去的提交。

但是,git log --reflog 仍然可以显示它们。

如果git log --reflog 不依赖于git reflog,它如何显示悬空提交?

【问题讨论】:

  • 当你说 my reflog 时,你在看多少个 reflog?只有HEAD 的那个?只是master 的那个?全部?
  • @torek, reflog 现在是空的,而它曾经有很多行。
  • 让我尝试另一种表达方式:您如何查看 reflog?具体来说,你使用什么命令?并且:有不止一个 reflog。
  • @torek,git reflog,输出为空。 git log --reflog 显示过去的提交。

标签: git git-reflog


【解决方案1】:

TL;DR

Reflogs 不保存提交祖先:reflogs 保存名称更新历史记录。它是保存提交祖先的提交图git log 想要一些起点,但是在得到它们之后,它会查看提交图。 git log --reflog 通常会更改起始点集,但如果您已删除所有 reflog(或从未有过任何引用日志,例如,在裸克隆中),则不会:您将获得标准的单一起点,HEAD .

请注意,reflog 条目最终会过期,默认情况下会在 90 天后过期,*graph 永远不会过期。一个新的克隆没有 reflog 历史记录,但具有所有图形链接——并且git log --reflog 仍然显示多个提交。


*某些条目的默认有效期为 30 天,大多数为 90 天,而对于 refs/stash 的特殊 reflog,则从不。详细信息超出了此答案的范围。


实验性:

rm .git/logs/HEAD

删除了 HEAD reflog,但git reflog 仍然显示一些数据。另一方面:

rm -r .git/logs

删除所有引用日志,之后 git reflog 不显示任何内容。

此时,人们可能希望git log --reflog 找不到任何东西。但是,显然这使用了相同的“将HEAD 本身添加为默认”行为。所以现在没有引用日志,git log --reflog 相当于:

git log HEAD

显示当前提交及其祖先。使用:

git log --no-walk --reflog

您只会看到HEAD 标识的一个提交。

这意味着答案:

log --reflog 如果不依赖 reflog,它是如何工作的?

是它没有做任何普通的git log 不再做的事情:

  • 当您向 git log 提供特定的起始提交时,Git 会显示这些提交以及可从这些提交访问的提交,而不使用 HEAD 作为起点。 (添加--no-walk 可以更清楚地说明这一点。)

  • 当您提供任何特定的起始提交时,git log 使用HEAD 作为其起始点。 (同样,添加--no-walk 可以更清楚地说明这一点。)

(当您确实有一些 reflog(这是正常情况)时,--reflog 参数提供 reflog 值作为起点,这会禁用“使用 HEAD 作为起点”操作。如果现在一切都有意义,你可以在这里停下来!)

潜在的混乱来源

在使用 Git 时,了解 commit 为您做了什么,以及像 masterreflog 条目这样的分支名称 是很重要的 喜欢master@{3},为你服务。

每个 Git 提交都包含您所有文件的完整快照,但这还不是全部。每个提交还包含一些元数据。这些元数据中的大部分——关于提交的信息——非常明显,因为它显示在git log 输出中。这包括提交者的姓名、电子邮件地址、日期和时间戳,以及他们提供的日志消息。

每个提交本身也有一个唯一的哈希 ID。这个哈希 ID 本质上是提交的“真实名称”。这就是 Git 在其包含所有提交和其他支持 Git 对象的大型数据库中查找实际提交对象的方式。

master 这样的分支名称仅包含一个特定提交的哈希 ID。根据定义,这一次提交是分支中的 last 提交。但是一个提交,比如master 分支中的最后一个,可以保存一个提交哈希ID。每个提交在其元数据中都有一个哈希 ID 列表。这些是提交的父母

大多数提交只有一个父哈希 ID。这将这些提交形成简单的后向链。我们可以画出这样的链条:

... <-F <-G <-H   <-- master

如果我们使用大写字母来代替提交哈希 ID。这里Hmasterlast 提交的哈希ID。提交H 本身在其元数据中包含先前提交G 的实际哈希ID。所以给定提交H,Git 可以使用这个哈希ID 来查找提交G。这反过来又提供了提交 F 的哈希 ID。

实际上,Git 可以让这条链倒退。这就是git log 通常所做的。使用--no-walk 告诉git log向我展示提交,但不要向后遍历它们的链;只显示我通过命令行特别选择的提交。 因此,使用--no-walk,您将只看到您选择的提交,而不是它们的祖先。

Reflogs 和分支名称一样,都包含哈希 ID。 reflog 被组织成每个名称(分支名称、标签名称等)的一个日志,以及一个用于特殊名称 HEAD 的日志。这些至少目前存储在.git/logs 目录中的普通文件中。每个日志都有条目(在这种情况下,每个文件一行),每个条目对应于名称在较早时间解析为的哈希 ID。您可以使用这些来访问较早的值,因此 master@{1} 告诉 Git 使用一步较早的值:在最近更新名称 master 之前,它解析为某个哈希 ID;现在它解析为一些(可能不同的)哈希 ID;我们希望退一步。名称 master@{2} 告诉 Git 我们想要后两步的值。

请注意,这些是名称更新步骤,而不是向后提交箭头步骤。 有时master@{1}master~1 相同,master@{2}master~2 相同,等等——但有时这些是不同的。后缀语法 master~2master^2 在提交图上与 / 一起操作。后缀语法master@{<em>number</em>} 在主引用日志上使用 / 操作。

(分支名称master@{0} 的当前值不在master reflog 中,因为它在master 本身中。更新master 将采用当前值并将其添加到日志中,然后设置新值。)

您可以使用git reflog 让 Git 溢出部分或全部 reflog 的内容。如果根本没有 reflogs——如果你将它们全部删除就会出现这种情况——这里什么都不会出现,因为不再有任何保存的值。但是,所有名称仍然有它们的值,HEAD 仍然存在并包含一个分支名称,例如master

更多细节

注意git log 的作用方式,它一次只能真正显示一个提交。为了处理这个问题,它使用priority queue。例如,您可以运行:

git log <hash1> <hash2> <hash3>

使用三个实际的哈希,或者:

git log master develop feature/tall

使用名称来查找哈希 ID,或者:

git log master master@{1} master@{2}

它使用两个 reflog 条目(加上分支名称)来查找哈希 ID。

在所有情况下,Git 都会将所有哈希 ID 插入优先级队列。

使用--reflog 作为命令行参数告诉git log 从引用日志中获取所有值并将它们插入到队列中。

如果队列中没有任何内容,Git 会将解析 HEAD 的结果插入到哈希 ID。

此时,队列大概不是空的,因为如果不出意外,我们通过解析名称HEAD得到一个哈希ID。1

git log 命令现在进入一个循环,该循环一直运行到队列为空。这个循环的工作原理如下:

  • 从队列中取出最高优先级的提交。
  • 使用提供给git log 的任何选择类型参数来决定是否显示此提交。如果是,则显示提交。 (例如,git log --grep 选择显示提交,其日志消息包含给定的字符串或模式。)
  • 如果--no-walk 生效,我们就完成了这个提交。否则,根据--first-parent 标志和选择的任何历史简化选择此提交的部分或全部父项放入队列。

(请注意,如果一个提交现在或曾经在队列中,git log 不会将其放回队列中,因此您不会看到相同的提交两次。队列中的优先级是受git log 的排序选项影响。)

因此,对于--reflog,如果有引用日志,我们会从引用日志条目中给git log 多个起点。如果没有任何引用日志,git log 使用其标准默认值:HEAD 开头

无论我们是否使用--refloggit log 现在都使用提交本身中的父链接来遍历提交。这不取决于我们提供的参数,当然--no-walk 除外。2


1如果根本没有提交,或者我们在 git checkout --orphan 创建的“未出生分支”上,此时队列将为空,但 git log 将有尝试解析名称 HEAD 时出错。

2此外,使用 -g--walk-reflogs 参数,git log 不会遍历 提交图。相反,它会遍历 reflog 条目。

--walk-reflogs--reflog 之间的区别在于,--walk-reflogs 将整个优先级队列的东西完全抛弃:Git 查看 reflogs。这也改变了一些输出格式。事实上,git reflog 真的只是运行git log -g

【讨论】:

  • re "git log HEAD 显示当前提交及其祖先";但它不显示后代。 git reflog 的输出为空时,git log --reflog 如何显示后代?
  • 我扩展了很多答案,但 TL;DR 是:reflogs 不持有提交祖先; reflogs 保存名称更新历史。它是保存提交祖先的提交图。还要注意,reflog 条目最终会过期,默认情况下会在 90 天后过期。图表永不过期。新克隆没有 reflog 历史记录,但具有所有图形链接。
  • 老实说,我会将 TL;DR 版本放在您答案的顶部
  • @DaemonPainter:好主意,完成了。
猜你喜欢
  • 2013-07-25
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 2018-08-10
  • 2015-10-25
  • 2017-03-05
  • 2017-07-17
  • 1970-01-01
相关资源
最近更新 更多