我看过here但无法完全弄清楚我想知道的事情:git push
或 git pull
如何找出另一端缺少哪些提交对象?
假设我们有一个包含以下提交的存储库:(字母代表 SHA-1 ID,d
是 refs/heads/master
)
a -> b -> c -> d
相比之下, Remote 有这些:
a -> e -> f -> g
根据 git 文档,远程会告诉我们它的 refs/heads/master
位于 g
,但由于我们不知道那个提交,所以实际上并没有告诉我们任何事情。这如何足以找出缺失的数据?
在另一个方向上,文档说:
At this point, the fetch-pack process looks at what objects it has and responds with the objects that it needs by sending “want” and then the SHA-1 it wants. It sends all the objects it already has with “have” and then the SHA-1. At the end of this list, it writes “done” to initiate the upload-pack process to begin sending the packfile of the data it needs:
这解释了远程如何确定要发送的数据,但这不会影响包含许多对象的存储库的 pull 性能吗?否则,文本中的实际含义是什么?
显然,数据传输的方式因方向(推与 pull )而异。这种设计选择遇到了哪些挑战以及如何应对,我如何理解文档中的描述?
最佳答案
神奇之处在于 ID。一个提交 ID 由很多东西组成,但基本上它是一个 SHA-1 hash。
- 内容(一切,不仅仅是差异)
- 作者
- 日期
- 记录消息
- parent 身份
更改其中任何一项,您需要使用新 ID 创建新提交。请注意,父 ID 已包括在内。
这对 Git 意味着什么?这意味着如果我告诉你我提交了“ABC123”而你提交了“ABC123”,我们就知道我们有相同的提交内容、相同的作者、相同的日期、相同的消息和相同的 parent 。这些 parent 具有相同的 ID,因此他们具有相同的内容、相同的作者、相同的日期、相同的消息、和相同的 parent 。等等。如果 ID 匹配,它们必须具有相同的历史记录,则无需进一步检查。这是 Git 的一大优势,它深深地融入了它的设计中,没有它你就无法理解 Git。
pull 是一个 fetch 加上一个 merge。 git pull origin master
是 git fetch origin
加上 git merge master origin/master
(或者 rebase
和 --rebase
).提取看起来像这样......
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] 嘿 remote,你有哪些分支?
- [远程] 我在 G 上修复了错误。
- [local] 我在 G 也有 bug 修复!完毕。还有什么?
- [remote] 我有专长。
- [local] 我没有特征,我也没有。我的 parent 是什么?
- [remote] 我的 parent 是 H.
- [local] 我没有 H,H 的 parent 是谁?
- [远程] H 的父级是 J。
- [local] 我没有 J。J 的 parent 是什么人?
- [远程] J 的 parent 是 E。
- [local] 我有 E!请将 J、H 和 I 发给我。
- [远程] 好的,他们来了。
- [local] 将 J、H 和 I 添加到 repo 并将来源/特征放在 I 上好的,你还有什么?
- [远程] 我在 J 有硕士。
- [local] 我在 E 有 master,你已经把 J 发给我了。将 origin/master 移到 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
来完成 pull ,这将快进到 J。
推送是类似的,除了过程是反向的(本地发送提交到远程)并且它只会快进。
这就是Pro Git refers to as "the dumb protocol"当您的远程是一个简单的 HTTP 服务器时使用。 The Smart Protocol是更经常使用的,不那么冗长,并且有很多优化。但您可以看到两者都非常高效。不需要传达整个历史,他们只需要发送 20 字节的哈希键,直到找到共同的祖先。
这里有一些资源和进一步阅读。
关于git - Git 如何确定需要在存储库之间发送哪些对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28139358/