【问题标题】:How does Git determine what objects need to be sent between repositories?Git 如何确定需要在存储库之间发送哪些对象?
【发布时间】:2015-03-24 05:32:14
【问题描述】:

我查看了here,但无法完全弄清楚我想知道的事情:git pushgit pull 如何找出另一边缺少哪些提交对象?

假设我们有一个包含以下提交的存储库:(字母代表 SHA-1 ID,drefs/heads/master

a -> b -> c -> d

相比之下,遥控器有这些:

a -> e -> f -> g

根据 git 文档,遥控器会告诉我们它的 refs/heads/master 位于 g,但由于我们不知道该提交,因此实际上并没有告诉我们任何信息。这足以找出丢失的数据吗?


在另一个方向,文件说:

此时,fetch-pack 进程查看它拥有的对象,并通过发送“want”和它想要的 SHA-1 来响应它需要的对象。它发送 它已经拥有的所有对象 带有“have”,然后是 SHA-1。在此列表的末尾,它会写入“完成”以启动上传打包过程,以开始发送所需数据的打包文件:

这解释了远程如何确定要发送哪些数据,但这不会影响具有许多对象的存储库的拉取性能吗?否则,文中究竟是什么意思?


显然,数据传输的方式因方向而异(推与拉)。这种设计选择遇到了哪些挑战以及如何挑战,我如何理解文档中的描述?

【问题讨论】:

    标签: git git-push git-pull git-fetch


    【解决方案1】:

    神奇之处在于 ID。提交 ID 由很多东西组成,但基本上它是一个 SHA-1 hash

    • 内容(一切,不仅仅是差异)
    • 作者
    • 日期
    • 日志消息
    • 父 ID

    更改其中任何一个,您都需要使用新 ID 创建一个新提交。请注意,其中包含父 ID。

    这对 Git 意味着什么?这意味着如果我告诉你我已经提交了“ABC123”并且你已经提交了“ABC123”,我们知道我们有相同的提交,具有相同的内容、相同的作者、相同的日期、相同的消息和相同的父母。这些父母具有相同的 ID,因此他们具有相同的内容、相同的作者、相同的日期、相同的消息,和相同的父母。等等。如果 ID 匹配,它们必须具有相同的历史记录,则无需进一步检查。这是 Git 的一大优势,它深深地融入了它的设计中,没有它你就无法理解 Git。

    拉取是提取加合并。 git pull origin mastergit fetch origin 加上 git merge master origin/master(或 rebase--rebase)。 fetch 看起来像这样......

    remote @ http://example.com/project.git
    
                      F - G [bugfix]
                     /
    A - B - C - D - E - J [master]
                         \
                          H - I [feature]
    
    local
    origin = http://example.com/project.git
    
                      F - G [origin/bugfix]
                     /
    A - B - C - D - E [origin/master] [master]
    
    • [本地] 嘿远程,你有什么分支?
    • [remote] 我在 G 有错误修复。
    • [本地] 我在 G 也有错误修正!完毕。还有什么?
    • [remote] 我在 I 有特色。
    • [本地] 我既没有特征也没有我。我的父母是什么?
    • [remote] 我的父母是 H.
    • [本地] 我没有 H,H 的父母是谁?
    • [remote] H 的父母是 J.
    • [本地] 我没有 J。J 的父母是谁?
    • [remote] J 的父母是 E.
    • [本地] 我有 E!请给我 J、H 和我。
    • [remote] 好的,他们来了。
    • [local] 将 J、H 和 I 添加到 repo 并将 origin/feature 放在 I 上好的,你还有什么?
    • [remote]我在J.有硕士。
    • [本地] 我在 E 有主人,你已经给我发了 J。将原点/主人移到 J。还有什么?
    • [远程] 就是这样!
    • [本地] Kthxbi

    现在本地看起来像这样......

    local
    origin = http://example.com/project.git
    
                      F - G [origin/bugfix]
                     /
    A - B - C - D - E [master] - J [origin/master]
                                  \
                                   H - I [origin/feature]
    

    然后它会做git merge master origin/master来完成拉动,它会快进到J。

    推送是类似的,除了过程是反向的(本地发送提交到远程),它只会快进。

    这就是Pro Git refers to as "the dumb protocol",当您的远程是一个简单的 HTTP 服务器时使用。 The Smart Protocol 的使用频率更高,不那么健谈,并且有很多优化。但是您可以看到两者都非常有效。不需要传达整个历史,他们只需要发送 20 字节的哈希键,直到找到一个共同的祖先。

    这里有一些来源和进一步阅读。

    【讨论】:

    • 你的回答很好,谢谢!如果您不介意,我对如何避免多次往返特别感兴趣。这仅仅是急切地发送例如的问题吗?最多 50 个哈希 (
    • 另外,如果您碰巧有任何答案来源,这些会很棒。我更关心的是“实现类似 git 的同步机制”,所以我完全满意,但未来的读者如果正在寻找“如何详细实现 git 的同步”,可能会喜欢它。
    • @SillyFreak 我添加了一些参考以了解更多细节。对话示例是我在概念上教授它的方式,Pro Git 称之为"The Dumb Protocol"。您想查看"The Smart Protocol" 以获得更有效的示例。
    • Smart 协议是我首先查看、引用并要求澄清的内容。但我会研究示例代码,谢谢。
    • @SillyFreak 我想我现在了解智能协议了。如果您提出有关它的具体问题,我可能会提供帮助。只需在此处链接它们,我一定会看到它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    相关资源
    最近更新 更多