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

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

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

假设我们有一个包含以下提交的存储库:(字母代表 SHA-1 ID,drefs/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 mastergit 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/

相关文章:

如果存在具有不同扩展名的文件,则 Gitignore 文件

git - 在 GIT 推送上接收电子邮件

Git:如何执行硬推送

git - 并发git pull 到同一个本地存储库

git - Git中的FETCH_HEAD是什么意思?

git - merge 、更新和 pull Git 分支而不使用 checkout

git - 如何知道一个标签是否快进到 BARE 存储库中的另一个标签?

java - Android Studio 中的某些 Java 文件未显示在 GitHub Desktop 上

git - 我可以删除历史记录并保留最近 git 提交的 sha 吗?

git pull 与 git push -f 类似/相反?