Git如何确定需要在存储库之间发送哪些对象?

Sil*_*eak 4 git git-pull git-push git-fetch

我已经看过这里,但无法弄清楚我想知道的事情:如何git pushgit pull弄清楚另一边缺少哪些提交对象?

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

a -> b -> c -> d
Run Code Online (Sandbox Code Playgroud)

相比之下,遥控器具有:

a -> e -> f -> g
Run Code Online (Sandbox Code Playgroud)

根据git文档,遥控器会告诉我们它refs/heads/master处于g,但由于我们不知道该提交,这实际上并没有告诉我们什么.怎么能够找出丢失的数据?


在另一个方向,该文件说:

此时,fetch-pack进程会查看它拥有的对象,并通过发送"want"然后发送它想要的SHA-1来响应它所需的对象.它使用"have" 发送它已经拥有的所有对象,然后发送SHA-1.在此列表的末尾,它写入"done"以启动upload-pack进程以开始发送所需数据的packfile:

这解释了遥控器如何确定要发送的数据,但这不会影响具有许多对象的存储库的性能吗?否则,文本中实际意味着什么呢?


显然,根据方向(推动与拉动),数据传输的方式是非常不同的.这个设计选择遇到了什么以及如何遇到挑战,我如何理解文档中的描述?

Sch*_*ern 11

神奇的是ID.提交ID由许多内容组成,但基本上它是SHA-1哈希.

  • 内容(一切,而不仅仅是差异)
  • 作者
  • 日期
  • 记录消息
  • 家长ID

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

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

拉是一个提取加一个合并. git pull origin mastergit fetch origingit 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]
Run Code Online (Sandbox Code Playgroud)
  • [本地]嘿远程,你有什么分支机构?
  • [遥控]我在G修错了
  • [本地]我也有G的bugfix!完成.还有什么?
  • [遥远]我有我的特色.
  • [本地]我没有特色也没有.我的父母是什么人?
  • [遥远]我的父母是H.
  • [本地]我没有H,H的父母是什么?
  • [遥远] H的父母是J.
  • [本地]我没有J. J的父母是什么?
  • [遥远] J的父母是E.
  • [本地]我有E!请给我J,H和我.
  • [遥远]好的,他们来了.
  • [local] 将J,H和I添加到repo并将原点/功能放在I Ok上,你还有什么?
  • [遥远]我在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]
Run Code Online (Sandbox Code Playgroud)

然后它将git merge master origin/master完成拉动,这将快速前进到J.

推送类似,除了进程反向(本地发送提交到远程)并且它只会快进.

这就是Pro Git所说的"哑协议",当你的遥控器是一个简单的HTTP服务器时使用.智能协议是更经常使用的,远不那么繁琐,并且有许多优化.但是你可以看到它们是如何非常高效的.没有必要传达整个历史记录,他们只需要发送20个字节的哈希键,直到找到共同的祖先.

这是一些来源和进一步阅读.