假设我在 git repo 中运行以下命令:
git rev-list --objects HEAD^..HEAD
此命令仅给我由 HEAD 引用而不是由 HEAD^ 引用的对象。
但是,如果有一个对象被HEAD^^
和 引用HEAD
,但没有被 引用HEAD^
,那么该对象会出现在输出中吗?
根据实验,答案似乎是肯定的。
但是,文档似乎没有指定意图,所以我不确定我的实验结果是否是偶然的。
更新我目前的理解以澄清这个问题:
- 我理解这
<old>..<new>
相当于^<old> <new>
,这意味着采取所有可从 到达<new>
但不可从 到达的提交<old>
。 - (实现 A1)从哲学上讲,如果我们将这个概念逐字扩展为“提交引用的树和 blob”,那么的“语义正确”行为
git rev-list --objects ^<old> <new>
是“找到所有可从 到达但<new>
不可从 到达的对象(提交、树和 blob)<old>
。 - 从字面上理解,这意味着具有以下属性的 blob X 不应该出现在 中
git rev-list --objects HEAD^..HEAD
,因为从 可访问的完整对象集HEAD^
包括 blob X。- 由拥有的树引用
HEAD^^
- 由拥有的树引用
HEAD
- 没有被所拥有的树直接引用
HEAD^
- 由拥有的树引用
- 然而,我的实验表明,blob X确实出现在 的输出中
git rev-list --objects HEAD^..HEAD
,这意味着以下替代实现(称之为 A2):- 获取范围内的提交所引用的所有对象
<old>..<new>
。 - 仅删除提交引用的对象
<old>
而不是其所有祖先并返回此集合。
- 获取范围内的提交所引用的所有对象
因此,我的问题可以改写为:的行为是否git rev-list --objects <old>..<new>
等同于 A1、A2,或者其他有时表现得像 A1、有时表现得像 A2 的东西?
是的,对此有两种解读,但其中一种在实践中更有用。
这个想法是为了有效地找到需要发送以获取或推送的对象,这意味着权衡每次进行的详尽搜索的成本,以及有时(实际上很少)发送已经拥有的对象的成本。
最容易看出如果你说
git rev-list --boundary @^..
:rev-list 在到达(已识别)边界提交时停止查找,不管它是否也在进行--objects
处理。两种方式都有成本。两种方式都能达到相同的结果。总体而言,更便宜的方式也更安全,因为另一个存储库可能比较浅显,实际上并没有您刚刚检查过的所有历史记录。最好只查看另一个存储库告诉您它拥有的内容,即它提供的获取/推送边界标记。
编辑:一些快速检查表明,
--objects
除了明确列出的边界提交之外,不假定拥有任何对象。同样,从安全角度来看,这才有意义,远程服务器没有说他们有更深的历史记录,不要指望他们有它。