Git 如何计算要提取的提交

How does Git calculate commits to fetch

我知道 git fetch 的作用以及该命令的用法。

我对内部结构感兴趣:Git 如何确定要传输的确切提交?

例如下面的情况

本地仓库:

A - B - C - D master
     \  \- E - F feature1
      \- G feature2

来源:

A - B - C - D - D1 - D2 master
     \  \- E - F - F1 - F2 feature1
      \- G - G1 feature2

git fetch 需要下载提交 D1、D2、F1、F2 和 G1。

天真地,我的 git 客户端可以将本地提交 SHA(A、B、C、D、E、F、G)列表发送到远程存储库。远程存储库会找到所有不在我的列表中的 SHA(D1、D2、F1、F2、G1)并将它们发回给我。对于大型存储库,这将涉及发送大量数据并进行大量计算。发送到远程仓库的数据将与提交总数成正比。

我确信使用了更聪明的方法。

只发送每个分支(D、F、G)的尖端的 SHA 是否足够?跟踪 parents 远程回购可以确定回购共享的提交并确定丢失的提交。发送到远程仓库的数据将与(未合并的)分支总数成正比,通常远低于提交数。

它是否适用于所有情况(分支落后、领先、变基)?

还有其他想法吗?我期待一个基于图论的漂亮解决方案:-)

Is sending just the SHAs of tip of each branch (D, F, G) sufficient?

经常,是的,但不总是。在这种情况下,它完美地工作:接收方 Git 可以宣布它具有这三个哈希 ID,并且由于发送方 Git 具有这些提交,发送方 Git 可以由此推断,只要接收方 Git 不是 shallow 存储库,接收方 Git 就有那些提交 和所有前任 .

“不总是”的线索在上面的陈述中:如果接收Git是一个浅克隆,它可能在这里缺少一些祖先。如果接收方 Git 中的 branch-tip-commits 用于发送方 不存在 的提交,则它们的哈希 ID 不会向发送方传达任何信息。

对于这些情况,我们求助于“拥有”和“想要”。发送方将他的 ref-names 和哈希 ID 发送给接收方。接收者可以判断他是否有那些 objects。如果没有,而接收者想要它们,他会发出信号表示他“想要”它们。发件人将需要为这些提交的 parents 提供额外的哈希 ID;接收者将表明他是否拥有它们。在所有情况下,拥有一些提交哈希 ID 表明一个人拥有所有祖先,除了 shallow-repository 情况(这些使明显的优化变得一团糟,我没有深入研究 Git来源查看是否有更多浅克隆的特殊情况——移植点在接收器中是已知的,但我在协议描述中看不到任何允许宣布它们的内容。