我看过here,但无法弄清楚我想知道的事情:git push
或git pull
如何找出另一边缺少的提交对象?
假设我们有一个包含以下提交的存储库:(字母代表SHA-1 ID,d
是refs/heads/master
)
a -> b -> c -> d
相反,遥控器有这些:
a -> e -> f -> g
根据git文档,遥控器会告诉我们它的refs/heads/master
位于g
,但由于我们不知道该提交,这实际上并没有告诉我们什么。如何找出缺失的数据呢?
另一方面,文件说:
此时,fetch-pack进程会查看它拥有的对象,并通过发送“want”然后发送它想要的SHA-1来响应它所需的对象。它使用“have”发送它已经拥有的所有对象,然后发送SHA-1。在此列表的末尾,它写入“done”以启动upload-pack进程以开始发送所需数据的packfile:
这解释了远程如何确定要发送的数据,但这不会影响具有许多对象的存储库的性能吗?否则,文本中实际意味着什么?
显然,数据传输的方式根据方向(推动与拉动)而有很大差异。这个设计选择面临的挑战是什么以及如何?我如何理解他们在文档中的描述?
答案 0 :(得分:11)
神奇的是ID。提交ID由许多内容组成,但基本上它是SHA-1 hash。
更改其中任何一项,您需要使用新ID创建新提交。请注意,包含父ID。
这对Git意味着什么?这意味着如果我告诉你我已经提交了“ABC123”并且您提交了“ABC123”,我们知道我们拥有相同的内容,相同的作者,相同的日期,相同的消息和相同的父母相同的提交。这些父母具有相同的ID,因此他们具有相同的内容,相同的作者,相同的日期,相同的消息,和相同的父母。等等。如果ID匹配,它们必须具有相同的历史记录,则无需进一步检查该行。这是Git的强大优势之一,它深深地融入了它的设计中,没有它你就无法理解Git。
pull是一个fetch加上一个合并。 git pull origin master
为git 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]
现在本地看起来像这样......
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。
推送类似,除了进程反向(本地发送提交到远程)并且它只会快进。
当你的远程服务器是一个简单的HTTP服务器时,这就是Pro Git refers to as "the dumb protocol"。 The Smart Protocol是经常使用的,不那么繁琐,并且有许多优化。但是你可以看到它们是如何非常高效的。没有必要传达整个历史记录,他们只需要发送20个字节的哈希键,直到找到共同的祖先。
以下是一些消息来源和进一步阅读。