一般来说,git push
不会推送任何未引用的对象。
可能有特定的案例/优化可能会这样做,因为从来没有任何明确的承诺。但在实践中,事实并非如此。
请注意,在您的 rebase 之后,本地存储库有一个新的(不同的哈希 ID)提交E'
:
C--D--E [reflog / ORIG_HEAD access only]
/
...--A--B
\
E' <-- somebranch (HEAD)
当您运行git push <othergit> somebranch
到其他 Git 时,其他 Git 会将其分支提示提交哈希 ID 呈现给您的 Git,而您的 Git 会将提交的哈希 ID 呈现E'
给它们。他们显然还没有,E'
因为你只是自己做的,所以他们说他们想要它(或没有它),你的 Git 呈现B
给他们;如果他们没有那个,他们也会接受那个承诺,A
如果需要的话,他们也会接受这个承诺,依此类推。
在某些时候,您的 Git 达到了他们确实拥有的一些提交,或者用完了提交哈希 ID 来发送。您的两个 Git 现在就要发送的内容达成一致,并且 - 作为这些协商的结果 - 您的 Git 知道他们已经拥有哪些提交,并且从中也知道他们也拥有哪些树和 blob 对象(暗示他们拥有,例如, 提交A
,因此所有早期的提交也是如此)。
你的 Git 现在——通常是1——准备了一个所谓的瘦包。这是您看到“计数对象”和“压缩对象”内容的地方。精简包仅包含重建您发送的提交所需的那些对象:在我们的特定示例中,提交E'
和B
,例如。A
这包括他们没有的树和 blob 对象——提交的存在并不暗示——但不包括他们拥有的树和 blob 对象。
这就是使包成为“瘦”包的原因:允许瘦包对丢失的对象进行增量压缩。假设提交A
有一些文件由 10 兆字节的 blob 对象表示,并且提交B
和/或E'
有一些文件不是 100% 相同,但共享该 10 兆字节对象的 99%。瘦包的新对象可以进行增量压缩,即从对象 _____ 中取出 9.9 MB(用哈希 ID 填写空白)并添加剩余的 100 kB。普通包必须包含这个“基础对象”,但薄包没有。
接收 Git 必须:
- 拿进来的薄包
- 检查传入的提交,并决定是否接受它们
- 如果它们被接受,则“修复”薄包装或将对象转换为松散(未包装)的对象。
接收 Git 现在拥有新提交所需的所有对象,可以是松散对象,也可以是新的固定、不再精简的包。假设是后者,这个不再精简的包存储在该存储库中,因此新对象(如果需要,可能加上从其他包中检索到的一些对象)现在都在该存储库中,在这个现在常规的包中。
(在某些时候重新包装会变得有利可图。这部分变得相当复杂。)
1这取决于您的 Git 和他们的 Git 之间用于通信的协议。另一种选择是一次上传每个对象,这在通过网络发送的字节方面往往非常浪费,因此人们现在通常不使用旧协议。