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

cal*_*lys 2 git git-push

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

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

tor*_*rek 5

简短的回答是你不能,不完全是。在git push推送/上传各种 Git 对象时,它以在另一个 Git 存储库中设置一个或多个名称结束。接收 Git 会在git gc之后立即运行。

特别是,运行:

git push remote refspec1 refspec2 ... refspecN

在命令行上,您的 Git 调用其他一些 Git remote(例如通过 URL 获取)。然后,您的 Git 将每个引用规范的源部分标识的对象交付给他们的 Git,或者更准确地说,通过哈希 ID 向他们提供这些对象。您可以在此处放置哈希 ID:remote.remote.pushurl

git push origin a123456:name
Run Code Online (Sandbox Code Playgroud)

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

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

一旦你的 Git 发送了瘦包,另一方就会修复它(增加它并添加一个索引)。他们现在采用您的 Git 的表单请求集:请将 <name> 设置为 <hash>(非强制推送)或相同但没有(强制推送)。如果您运行git push origin a123456:name,该请求会显示设置namea123456

他们要么服从请求/命令,要么拒绝它。如果他们拒绝了它,那么a123456- 您刚刚发送给他们的 - 很可能无法从他们的任何其他参考资料中获得!(一种情况是,同一推送集中的其他内容或更新了其他一些参考以使其a123456可访问。)

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

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

  • 是的,您可以使用接收 Git 允许的一些名称来推送特殊的提交(接收 Git 可以在此处设置自己的约束,但应该始终允许分支和标记名称)。正如我所说,子模块技巧无论如何都不起作用,所以你需要一个不同的技巧,可能只是使用多个父模块,但如果你的实际目标是保留文件内容,你根本不需要对提交进行棘手的黑客攻击,你只需要 blob(您可以通过标签名称保存)和/或树(您也可以通过标签名称保存)。 (2认同)