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