不运行git prune
或git gc
,git push
会上传任何未引用的对象吗?想象一下这些提交历史:
在提交C中添加了一个新文件,并且从提交d中删除了该文件,现在git rebase --onto B D
将导致:
A <= B <= E
并且该文件仍然在.git/objects中,因为它被两个分离的提交C和d引用。现在这两个事件中发生了什么?
git push <remote> <branch>
现在将远程包含删除,因为文件对象仍然存在吗?将请求拉到远程分叉的主上游。如果1的答案是肯定的,如果C和D从未与上游合并,该文件是否会被合并到上游?
edit:这个问题补充了这里讨论的情况从远程
删除未引用的对象一般情况下,git push
不会推送任何未引用的对象。
可能会在特定的情况下/优化中这样做,因为从来没有任何明确的承诺关于这一点。但实际上,它没有。
请注意,在您的rebase之后,本地存储库有一个新的(不同的哈希ID) commitE'
:
C--D--E [reflog / ORIG_HEAD access only]
/
...--A--B
E' <-- somebranch (HEAD)
当你向其他Git运行git push <othergit> somebranch
时,其他Git将其分支提示提交哈希ID给你的Git,你的Git将提交E'
的哈希ID给他们。他们显然还没有E'
,因为你刚刚自己做了,所以他们说他们想要(或者没有),你的Git给他们提供了B
;如果他们没有,他们也会接受这个提交,如果需要,也会接受A
,以此类推。
在某些时候,你的Git到达了一些他们做的提交,或者用完了提交哈希id来发送。你的两个Git现在就要发送的内容达成一致,并且作为这些协商的结果,你的Git知道它们已经有哪些提交,并从中知道它们也有哪些树和blob对象(这意味着它们有,例如,提交A
,因此也有所有早期的提交)。
你的Git现在——通常是1——准备了一个所谓的薄包。这就是你看到计数对象的地方和"压缩对象"的东西。瘦包只包含那些他们需要重建您发送的提交的对象:例如,在我们的特定示例中,提交E'
和B
。这包括他们没有的树和blob对象——这不是由commitA
的存在所暗示的——但不包括他们所做的所拥有的树和blob对象。
这就是使包装"薄"的原因。包:允许薄包对丢失的对象进行增量压缩。假设提交A
有一些文件由一个10兆字节的blob对象表示,并且提交B
和/或E'
有一些文件不是100%相同,但共享那个10兆字节对象的99%。瘦包的新对象可以进行增量压缩,例如从对象_____(用散列ID填充空白)中获取9.9 MB,并添加这些剩余的100 kB。常规包必须包含这个"基本对象",但瘦包不需要。
接收Git必须:
- 接收传入的薄包
- 检查传入的提交,并决定是否接受它们
- 如果他们被接受,"fix"或将对象转换为松散(未打包)对象。
接收Git现在拥有新提交所需的所有对象,或者作为松散对象,或者在一个新的修复的、不再精简的包中。假设是后者,这个不再瘦的包存储在那个存储库中,所以新对象(如果需要,可能加上从其他包中检索的一些对象)现在都在那个存储库中,在这个现在正规的包中。
(在某种程度上,重新包装包变得有利可图。这部分相当复杂。
1这取决于你的Git和他们的Git之间使用的协议。另一种选择是每次只上传一个对象,这在通过网络发送的字节数方面往往是非常浪费的,所以人们现在通常不使用旧的协议。
当你推送一个分支时,只有当前在该分支上的提交(即从分支尖端可访问的)被传输到远程。