Git:将所有对象推送到远程存储库(不仅是引用,而且绝对是所有 blob、树和提交)

Git: push all objects to remote repository (not just refs, but absolutely all blobs, trees and commits)

上下文:我(误)使用 Git 不是为了版本控制,而是为了记录文件之间的关系。 Git 的内部数据结构(基本上是一个对象图)正是我所需要的(加密哈希等...),并且有很多非常好的工具来操作数据。

到目前为止我无法做的一件事是将整个图推送到远程存储库。据我了解,git push 仅作用于 refs,而不作用于 objects。有没有一种简单的方法可以将所有对象(提交、树、blob)推送到远程,或者我是否必须先在每个提交上添加一个 ref(例如 branch),然后推送所有分支,然后删除所有分支(本地和远程)?

简短的回答是你不能,不完全是。当 git push 推送/上传各种 Git 对象时,它以在另一个 Git 存储库中设置一个或多个 names 结束。接收 Git 然后倾向于 运行 git gc 紧随其后。

特别是, 运行:

git 推送 <em>远程</em> <em>refspec1 refspec2 ... refspecN</em>

在命令行上,您的 Git 在 remote 调用了其他 Git(通过 URL来自 remote.<em>remote</em>.pushurl 例如)。然后,您的 Git 向他们的 Git 交付由每个 refspec 的源部分标识的对象,或者更准确地说,通过哈希 ID 向他们提供这些对象。您可以将哈希 ID 放在这里:

git push origin a123456:name

a123456 是缩写的哈希 ID。无论命名什么对象,您的 Git 都会将其完整的哈希 ID 提供给另一个 Git。另一个 Git 将检查它是否有对象 a123456。如果是这样,它会告诉您它不需要实际内容;如果没有,您的 Git 将打包内容,现在还必须提供 a123456 需要的任何对象。例如,如果 a123456 是一个提交,你的 Git 必须提供它的树和父提交;另一个 Git 告诉您它是否已经拥有或需要它们,这会根据需要触发更多的对象跟踪。 (这里有一些优化来减少来回通信,但是到这里思路应该很清楚了。)

最终,您的 Git 和他们的 Git 同意,如果您的 Git 发送了一些对象,他们将拥有他们需要接受(或拒绝!)的所有对象您的 Git 的 设置一些名称 请求。然后,您的 Git 将这些对象打包,通常作为 thin pack 来存储这些对象,但会针对您的 Git 对象进行增量压缩知道或假设 他们的 Git 已经基于导致这一点的早期 have/want object-by-hash-ID 对话。 (例如,如果你提供了 a1234356,他们说他们需要它,那么你提供了它的父级 a000000,他们说 啊,我已经有了那个 ,你的 Git 知道他们不仅有对象 a000000 本身,还有它的树和它的所有 blob。此外,如果他们的存储库不浅,他们有所有 a000000parent 提交所有 their 树和 blob!所以你的 Git 可以增量压缩 a123456 的 blob所有这些早期的 blob,以制作这个薄包。它可以完全省略 a123456 中也在 a000000 中的任何 blob,依此类推。)

一旦您的 Git 发送了薄包,另一方就会对其进行修复(加厚并添加索引)。他们现在接受您 Git 的一组请求,其格式为:please set to (非强制推送)或没有 please(强推)。如果你 运行 git push origin a123456:name,那个请求说 set name to a123456.

他们要么服从 request/command,要么拒绝它。如果他们拒绝它,那么a123456——你刚发给他们的——很可能无法从他们的任何其他 参考资料! (一种情况是,当 same 中的其他东西推送设置或更新一些 other 参考以使 a123456 可达。)

当对话结束时,在你的所有 set to 操作之后,他们 运行 git gc。如果您发送给他们的对象是 松散 对象,这些对象将受到默认的 14 天宽限期的保护。但是你给他们发了一个包文件。如果他们在合并要保留的对象的同时重新打包包文件——他们几乎总是这样做——他们将删除任何未引用的对象。

这导致了构成此答案第一句话的有点悲伤的结论。