git - 是否可以维护两个具有完全不同内容的本地Git存储库,但将它们推送到同一远程存储库?

标签 git

我是一名研究生,正在尝试将Github用于科学。通常,我可能在不同的服务器上为同一项目执行不同的任务。我并不总是希望所有这些功能都同时在同一台服务器上,但是最好将它们组织在一个远程位置。

是否可以将两个内容不同的目录git push到同一GitHub存储库/起源的中?基本上,在此设置中,我几乎永远不会内容;只需推动它以使自己保持井井有条,并有可能与合作者共享即可。或者也许使用sparse-checkout偶尔克隆单个文件/子目录。

最佳答案

有可能的。

尽管您可以通过仔细的训练使其变得有用,但它并不是特别有用。

Git从根本上说是一个分为两部分的系统:有一个对象数据库,它是一个简单的键/值存储;还有一个命名系统,它是第二个简单的键/值存储。命名系统中的键是引用,它们是诸如refs/heads/masterrefs/heads/branchrefs/tags/v1.2等字符串,其值是哈希ID。对象数据库中的键是哈希ID,其值是Git对象。

事实是,命名系统使用任意键-好吧,除了最重要的refs/要求之外,都是任意键-允许您执行建议的操作。这些键的值的工作方式以及对象数据库键/值系统的工作方式,使其变得不那么有用。

如果您将名称键想象为一个简单的平面表,则可以:

name                value
------------------------------
refs/heads/master   1234567...
refs/heads/branch   fedcba9...

当您运行git push时,git push操作的最后一部分是将一些名称/值对传递到服务器(在本例中为GitHub上),并要求他们在此表中设置这些名称/值对。他们要么接受设置请求,要么拒绝(根据具体情况,即如果您提供两个名称/值对,则他们可以接受一个,而拒绝另一个)。

复杂的是数据库的哈希ID /对象部分。每个哈希ID对其特定对象都是唯一的。有四种对象类型:提交,树,标记和Blob。所有这些都共享一个通用的标头编码(ASCII中的类型名称,ASCII空值,对象的大小编码为不带前导零的十进制数字和全零位字节),后跟特定类型的数据。 (实际的哈希ID只是此标头的SHA-1哈希加上特定于类型的数据字节。)

Blob对象代表原始数据,通常是文件,因此它仅由标头后的原始字节组成。具有相同大小和内容的两个文件具有相同的哈希值,即相同的Blob,因此,如果存在一个文件README,然后另一个文件README~具有相同的内容,则两个文件只有一个存储库Blob。

为了让Git按名称存储文件,它还需要存储文件名,因此它使用树对象来进行存储。树对象具有一种特殊的,众所周知的内部格式,尽管它是二进制的,但实际上是运行git ls-tree时看到的内容:对于树或子树中的每个文件,Git存储一个模式,一个Git对象哈希ID,和一个文件名。 (通过读取对象可以找到对象类型。)

为了使Git在提交中存储快照,它需要存储与该提交关联的树对象。因此,提交对象具有树哈希ID作为其对象数据的一部分。每个提交还记录其父级或父级哈希ID,以便提交对象代表有向无环图。父哈希ID充当提交表示的顶点V的出站边缘E,而G =(V,E)是提交DAG。在此提交DAG中,每个提交都指向一棵树,该树指向子树和/或Blob,因此Git可以使用提交DAG来查找提交,该提交可以通过查找树来获取文件名和Blob ID来提取这些提交的文件。 。

为了存储带注释的标签,Git使用最后一个对象类型,该对象类型还存储一个哈希ID,保存带注释的标签的目标对象。因此,带注释的标签对象指向提交(通常,Git允许每个带注释的标签对象指向任何对象类型,尽管提交是正常的)。

由于所有这些编码,任何Git对象都可以从其他Git对象到达(通过从某个适当的起点遍历提交图),或者无法到达。如果给出了所有Git对象哈希ID的完整列表,则可以使用任何广度优先或深度优先的搜索算法来查找从某个起点可以到达哪些提交,而哪些不是。

这是我们将此对象数据库与引用名称/哈希ID值数据库一起放置的地方。所有这些参考名称及其相应的哈希ID值是图形的入口点。从这些起点哈希值我们可以达到的提交是Git将保留的提交。从这些引用名称无法到达的任何标记或提交都可以进行垃圾回收。通过标记和/或提交对象的垃圾收集而丢失所有引用的所有树和Blob也都可以处理。

因此,如果我们有一个看起来像这样的图:
o <--o <--o   <-- refs/start1
 \
  o <--o    <-- refs/start2
   \
    *

然后我们从两个起点开始,标记那些可实现的 promise ,标记其父母(左侧)可实现,并标记其祖父母可实现。祖父母没有父母-这是一项根本 promise -因此流程停止;并且所有我们未标记的提交都无法到达,可以将其丢弃。在这种情况下,这只是一个提交*

不需要像这样完全连接图形。我们可以有两个不相交的子图:
o--o--o   <-- refs/start1

o--o--o   <-- refs/start2

所有这些提交也都被引用,因此可以安全地进行收集。

当您运行git push时,您的Git会调用另一个Git并提供它,不仅是名称/值对,还包括由这些名称/值对标识的提交(和其他对象)。接收方Git会询问那些尚未提交的提交,然后查看其父ID并在必要时也询问这些提交,依此类推。接收方的Git会要求添加其他树和Blob对象,以使图完整。因此,如果您有两个独立的Git存储库,每个存储库中都有不同的名称,并且每个存储库都有git push,那么您将获得我们在上面看到的那种不相交的子图。

但是,当您运行git clone时,克隆Git会(通常)要求发送Git的所有名称/值对,然后是从这些值可访问的所有提交(和其他对象)。因此,进行克隆的人将获得所有不相交的子图。

您可以设置一个Git存储库,以使其不要求所有名称/值对。该存储库将基于git fetch(而不是git pull,这只是git fetch,后跟第二个Git命令,因此git fetch是有趣的部分),仅采用某些名称/值对,因此仅采用某些提交和其他对象。这样一来,您就可以提取GitHub存储库的部分或全部独立子图。

与使用两个不同的GitHub存储库(每个子图一个)相比,从此操作中获得的好处是在克隆和推送时会遇到很多麻烦:您不能使用直接的git clone,否则您将获得所有内容,以及从分离的存储库中推送,您必须非常小心以避免引用名称冲突。因此,最终结果是您很难使用自己的产品,而带来的收益几乎为零。

关于git - 是否可以维护两个具有完全不同内容的本地Git存储库,但将它们推送到同一远程存储库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47801469/

相关文章:

git - 如何回滚之前的两次提交?

git - 如何在 Visual Studio Code 中执行 git push?

git - 计算 Git 分支上的提交数

git - 如果这些笔记的提交被压扁,有没有办法自动 merge 笔记?

git - Master 和 Branch 显示相同的更改

objective-c - 我应该使用 merge=union 将 .pbxproj 文件与 git merge 吗?

git - 是否可以从 Jenkins 文件中的 Vault 获取凭据?

git - 如何在 sudo 后面锁定 git push origin master

git - 通过补丁添加时,有没有办法在git中添加未跟踪的文件?

git - 将 HG 项目从 Bitbucket 镜像到 Github