机器上同一存储库的多个副本

时间:2020-01-29 07:09:34

标签: git github git-clone diskspace

我有一台本地计算机,在该计算机上有同一个GIT存储库的多个副本,每个副本供不同的用户使用。所以看起来可能像这样:

/home/userA/BigRepository
/home/userB/BigRepository
/home/userC/BigRepository
/home/userD/BigRepository
/home/userE/BigRepository

比方说,每个存储库使用约2-3GB,20个用户将使用40-60GB的不必要的冗余数据。用户可以在其私有分支上开发某些东西,但是大多数数据仍然是冗余的。这就是为什么我想优化磁盘使用率。

我想知道什么是最好的方法。


我已经检查过的内容:

  • git clone --local-每个存储库将与裸存储库共享.git /对象,但这意味着.bare存储库必须在本地可用(所以它不能是GitHub,对吧?)
  • git clone --depth <n>-可以减少存储库的大小,但也可以将本地历史记录减少到n个对象。
  • git clone --shallow-since-据我了解,它的工作方式类似于--depth选项,但自指定时间起将存储提交。
  • git clone --separate-dir-我自己的想法,即使用同一位置存储所有.git目录。 (因此,进行克隆时,20个存储库中的每个存储库都将链接到同一位置。不知道是否有可能,只是分享我的想法。

--depth意味着存储库最多具有n次提交,还是仅在克隆时才进行检查,然后存储库会随着时间增长?

2 个答案:

答案 0 :(得分:2)

  • git clone --local-每个存储库将与裸存储库共享.git /对象,但这意味着.bare存储库必须在本地可用(所以它不能是GitHub,对吧?)

不太正确,不。您可以将其与任何本地克隆(无论是否裸露)一起使用。但总的来说,在完全可行的情况下,您也不需要--local:您只需从本地路径名克隆即可。

例如,假设userA(其主目录为/home/userA)克隆了GitHub存储库,从而创建了完整且非裸露的克隆。进一步假设userB可以从/home/userA中读取。用户B因此可以:

git clone /home/userA/BigRepository

创建./BigRepository。如果他在自己的主目录中执行此操作,则会结束/home/userB/BigRepository,其中包含与userA的克隆相同的所有提交。

因为Git会进行硬链接,所以如果用户A现在删除他的存储库,则他不会重新获得其空间(因此,如果磁盘配额有效,则用户A不会收回其配额)。用户B仍然具有指向用户A拥有的文件的链接。所有内容仍然有效;只是谁做了第一个克隆者就为存储库的初始存储“支付了”费用。

(用户B“支付”他自己的工作树。他共享用户A创建的.git/objects 文件,包括打包文件。无论用户B是否共享用户A的文件,文件始终都是只读的,因此用户B无法写入这些文件的事实并不重要。)

此过程的一个很小的缺点是,用户B可能希望更改其origin URL以指向GitHub存储库而不是用户A的克隆,直到这样做为止,他将不会看到与用户A相同的一组远程跟踪名称(origin/*名称)。

用户C可以使用任一先前的存储库重复此过程。

  • git clone --depth <n>-可以减少存储库的大小,但也可以将本地历史记录减少到n个对象。

通常,是的。从技术上讲,在数字 n 上是错误的:

--depth意味着存储库最多具有n次提交,还是仅在克隆时才进行检查,然后存储库会随着时间增长?

它们不仅随着时间增长,数字 n 并不代表您的建议。它是深度,而不是提交次数。在这种情况下,深度是一个技术术语,指的是图形遍历。

请记住,Git使用 commit 作为其基本存储单元。 (提交可以进一步细分,但出于我们的目的,这里是单位。)每个提交都有唯一的哈希ID,并且可以表示为图中的节点或顶点。每个提交还存储其直接上一个提交的哈希ID:这些哈希形成单向边或链接节点的 arcs ,因此形成了图的其余部分。

我们可以像这样绘制图形的位:

... <-F <-G <-H

,每个字母代表一个提交哈希ID。每个提交中存储的哈希ID充当指向较早提交的指针。为了轻松找到该链的 end ,我们或Git建立了一个分支名称或其他某种形式的名称,该名称指向 last em>提交到链中:

...--F--G--H   <-- master

(我们懒惰并绘制连接弧为线,原因很简单,因为不能更改任何提交,因此在这一点上箭头的方向实际上并不重要,尽管在其他时候,重要的是要记住它们固有地指向向后,这迫使Git始终向后工作。

现在,带有这些向后箭头的图形可以在其中具有分叉和联接:

          o--o         o--o--H   <-- branch1
         /    \       /
...--o--o--o---o--o--o--o--K   <-- branch2
         \          /
          o--o--o--o

当我们遍历该图时,我们从末尾开始—在普通图中,我们从头开始,但是Git向后工作—就像提交H一样,按名称指向branch1。如果我们选择--depth 3,Git将选择H和两个较早的提交,以及K和两个较早的提交:

          o--o--H   <-- branch1
         /
<snip>--o--o--K   <-- branch2

我们的--depth 3获得了6次提交,因为从每一端返回3次都使我们从完整图中提取了这些提交。如果我们转到--depth 4,我们将得到:

               o--o--H   <-- branch1
              /
  <snip>--o--o--o--K   <-- branch2
         /
<snip>--o

每个“剪裁”点代表一个浅层移植,我们知道其中有 个提交,但我们故意省略 >这些提交。省略的提交的哈希ID被写入.git/shallow,并且Git知道,当它访问其父列在.git/shallow中的提交时,它不会尝试查找父提交。

--depth参数选择剪切点。这种情况发生在git fetchgit clone是一个精美的六部分包装程序中,其中包括git fetch作为第五步。剪断点将保留在原处,除非并且直到您运行带有特定参数的git fetch来加深或进一步简化存储库。以常规方式添加新的提交,使图更深,包括任何用户运行的所有git fetch操作。

  • git clone --shallow-since-据我了解,它的工作方式类似于--depth选项,但自指定时间起将存储提交。

是的:它只是设置“剪裁”点的一种更有用且更容易混淆的方式。

  • git clone --separate-dir

您的意思是--separate-git-dir。这没有任何实际意义:您在此处指定的目录由克隆操作创建并填充。如果将其与任何较早的选项结合使用,将有助于减少所需的空间,但否则只会将工作树与适当的存储库分开。

在标准设置中,存储库本身在工作树中的 中出现在名为.git的子目录中。对于--separate-git-dir.git仍出现在工作树中,但这一次它是一个文件,其中包含存储库的保存路径。无论哪种方式,每个用户都独立支付存储成本,除非克隆其他用户的存储库暗示使用--local

每个用户都有自己的实际存储库很重要

如果并且当用户A提交 new 时,其Git必须将一个或多个 new 对象写入其.git/objects中。 (由于提交始终是唯一的,因此该操作至少需要写入该对象。它可能还需要写入一些树对象,为此,Git可能必须创建一些Blob对象。)

同时,如果并且当用户B进行新的提交时,他的Git必须将一个或多个新对象写入他的.git/objects中。如果用户A和B从字面上共享Git 存储库,则A和B必须对其他用户的文件和目录具有写权限。可以使这种模式有效,但它还有一个缺点:每个用户必须非常小心,以免偶然踩到其他用户。虽然存储库的大部分(包括拟共享的.git/objects部分)由一旦写入就永远不会更改的对象组成,但其他部分(包括特殊文件.git/HEAD)和许多其他文件(例如作为分支机构的头数据和引用,必须对每个用户都是私有的,否则,这种选择通常是行不通的,只有一个用户可以随时进行任何实际工作。

理论上,这里可以使用git worktree add

但是,它不是设计用于这种用途的。您可以根据需要进行试验:为每个用户添加一个工作树,然后对该用户授予与该用户关联的所有文件的权限(额外的文件位于.git的子目录中)。

为此设计的东西是--reference

用于处理此问题的 --reference选项。使用--reference,您作为计算机的管理员,首先会完整复制GitHub存储库。您可以选择是否创建--bare(这并不是很重要),但是您可能希望将其设置为--mirror的克隆,以便获取所有引用并可以更轻松地对其进行更新。 (我在上一份工作中对此进行了一些试验,这里存在一些使更新变得棘手的问题,因此这可能没有您一开始想的有用。)

此“参考克隆”存在后,每个用户都可以执行以下操作:

git clone --reference <path> <github-url>

他们的Git将与GitHub上的Git联系,并从中获取制作完整克隆所需的信息。但是,他们实际上没有进行完整的克隆,而是会检查参考克隆以查看它是否已经具有所需的对象。无论何时何地,参考克隆都已经具有那些对象,它们的Git只会使用在该现有参考克隆中的那些现有对象。

这意味着git clone本身运行非常快,并且几乎不使用任何额外的磁盘空间。制作原始〜3GB参考克隆可能要花费几分钟甚至几小时,但是当其中一位用户执行此git clone --reference操作时,它应该在几秒钟内完成。而且,它“干净”地工作,因为如果需要从GitHub获得新对象,则只需像往常一样从 GitHub获得它们。因为没有提交(实际上没有任何Git对象可以更改),所以参考克隆仅用于提供您最初放置的所有对象。新对象逐渐扩展了每个用户的存储库。

(将来您可以更新参考克隆。然后,各个用户可以重新克隆以减少其磁盘使用。这里的棘手部分是,您必须确保没有对象和打包文件消失从参考克隆到更新到重新克隆之间的时间,您可以制作一个 new 参考克隆,等到所有用户都重新克隆了新的参考克隆,然后再删除原始参考文献,以避免这种棘手。)

答案 1 :(得分:0)

您可以尝试将.git目录从一个位置符号链接到所有其他工作空间

git clone git@server:BigRepository /home/userA/BigRepository
mkdir /home/userB/BigRepository/
ln -s /home/userA/BigRepository/.git /home/userB/BigRepository/.git

但是,每个人都将更改其他人的分支,即您的master分支可能会意外移动。您的工作区将不会更改,因此您的文件将按预期方式运行。但是Git会突然报告更改。