一台机器上相同存储库的多个副本
Multiple copies of same repository on a machine
我有一台本地计算机,上面有同一个 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/objects,但这意味着 .bare 存储库必须在本地可用(所以它不能是 GitHub,对吧?)
git clone --depth <n>
- 这将减少 repo 的大小,但也会将本地历史记录减少到 n 个对象。
git clone --shallow-since
- 据我了解,它的工作方式与 --depth
选项类似,但会存储自指定时间以来的提交。
git clone --separate-dir
- 我自己的想法是使用同一个地方来存储所有 .git 目录。 (因此,在进行克隆时,20 个存储库中的每一个都会 link 到同一个地方。还不知道是否可行,只是分享我的想法。
--depth
是否意味着存储库最多有 n 次提交,或者仅在克隆时检查,然后存储库可以随时间增长?
您可以尝试将 .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会突然报变化
git clone --local
- Each repository will share .git/objects with a bare repository, but this implies .bare repository mush be available locally (so it cant be GitHub, right?)
不太对,不。您可以将其与任何本地克隆一起使用,无论是否裸机。但总的来说,如果这完全有效,您也不需要 --local
:您可以从本地路径名克隆。
例如,假设 userA
,其主目录是 /home/userA
,克隆了 GitHub 存储库,制作了一个完整的非裸克隆。进一步假设 userB
可以 从 /home/userA
读取 。因此,用户 B 可以:
git clone /home/userA/BigRepository
创建./BigRepository
。如果他在他的主目录中执行此操作,他将得到 /home/userB/BigRepository
,其中包含与 userA
的克隆相同的所有提交。
因为 Git 会创建硬链接,如果用户 A 现在 删除 他的存储库,他不会重新获得他的 space (所以如果磁盘配额是实际上,用户 A 没有取回他的配额)。用户 B 仍然具有指向用户 A 所拥有的文件的链接。一切仍然有效;只是制作第一个克隆的人拥有 "paid for" 适当的存储库的初始存储。
(用户 B "pays for" 他自己的 工作树 。他共享 .git/objects
文件 ,包括pack 文件,用户 A 创建。这些文件都是只读的,在任何时候,无论用户 B 是否共享用户 A 的文件,所以用户 B 不能 write 对那些文件并不重要。)
这个过程的一个非常小的缺点是用户 B 可能想要更改他的 origin
URL 以指向 GitHub 存储库而不是到用户 A 的克隆,并且在他这样做之前,他不会看到用户 A 看到的同一组远程跟踪名称(origin/*
名称)。
用户 C 可以使用前面的任一存储库重复此过程。
git clone --depth <n>
- which will reduce the size of the repo, but also reduce local history to n objects.
大多数情况下,是的。尽管 n 在技术上是错误的:
Will --depth
imply that repositories will have at most n commits, or is it checked only when cloning, and then the repository can grow with time?
它们不仅随着时间的推移而增长,数字 n 并不代表您的建议。它是深度,而不是提交次数。本例中的深度是指图遍历的技术术语。
记住 Git 使用 commit 作为它的基本存储单元。 (提交可以进一步细分,但出于我们的目的,它们是单位。)每个提交都有一个唯一的哈希 ID,并且可以表示为图中的节点或顶点。每个提交还存储其直接前任提交的哈希 ID:这些形成单向边或 arcs 链接节点,因此形成图的其余部分。
我们可以像这样绘制图形的位:
... <-F <-G <-H
其中每个字母代表一个提交哈希 ID。每个提交中存储的哈希 ID 充当指向早期提交的指针。为了方便地找到这个链的 end,我们——或者 Git——建立一个 分支名称,或者其他形式的名称,指向链中的 last 提交:
...--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
每个 "snip" 点代表一个 浅移植 ,我们知道那里有 更多提交,但我们我故意 省略了 那些提交。省略的提交的哈希 ID 被写入 .git/shallow
并且 Git 知道,当它访问其父项列在 .git/shallow
中的提交时,不会试图找到父提交。
--depth
参数选择剪辑点。这发生在 git fetch
的时候——git clone
是一个花哨的六部分包装器,其中包括 git fetch
作为第五步。剪辑点保留在那里,它们所在的位置,除非并且直到您 运行 a git fetch
带有特定参数以加深或进一步浅化存储库。新提交以通常的方式添加并使图表更深,包括任何用户 运行.
的任何 git fetch
操作
git clone --shallow-since
- as I understand it will work similarly to --depth
option but will store commits since the specified time.
是的:它只是一种更有用且不易混淆的设置 "snip" 点的方法。
git clone --separate-dir
你是说 --separate-git-dir
。这没有实际意义:您在此处指定的目录由克隆操作创建和填充。如果与任何较早的选项结合使用,那将有助于减少 space 的需要,否则它只会将工作树与适当的存储库分开。
在标准设置中,存储库本身出现在 中 工作树中名为 .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
克隆,以便它获得每个引用并可以更轻松地更新。 (我在之前的工作中对此进行了一些试验,这里有一些问题使得更新变得棘手,所以这可能不像你一开始想象的那么有用。)
一旦 "reference clone" 存在,每个用户都可以:
git clone --reference <path> <github-url>
他们的 Git 将联系位于 GitHub 的 Git,并从中获取他们制作完整克隆所需的信息。但是,他们并没有真正制作完整的克隆,而是检查参考克隆以查看它是否已经拥有他们想要的对象。无论何时何地,参考克隆已经拥有这些对象,它们的 Git 将仅 使用 现有参考克隆中的那些现有对象。
这意味着 git clone
本身运行速度非常快,几乎不使用额外的磁盘 space。制作原始的 ~3GB 参考克隆可能需要几分钟甚至几小时,但是当其中一位用户执行此 git clone --reference
操作时,它应该会在几秒钟内完成。此外,它 "cleanly" 的工作原理是,如果他们需要来自 GitHub 的新对象,他们只需照常从 GitHub 获取它们。因为没有提交——没有 Git 任何类型的对象,真的——可以 改变 ,参考克隆仅用于提供 你 最初放入它。新对象逐渐扩展每个用户的存储库。
(您可以在将来更新参考克隆。然后个人用户可以重新克隆以减少他们的磁盘使用量。这里棘手的部分是您必须确保没有对象,也没有打包文件, 在你更新它和他们重新克隆的时间之间从参考克隆中消失。你可以改为只制作一个 new 参考克隆,等到所有用户都重新克隆了新的参考克隆,然后删除原始参考,以避免这种棘手。)
我有一台本地计算机,上面有同一个 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/objects,但这意味着 .bare 存储库必须在本地可用(所以它不能是 GitHub,对吧?)git clone --depth <n>
- 这将减少 repo 的大小,但也会将本地历史记录减少到 n 个对象。git clone --shallow-since
- 据我了解,它的工作方式与--depth
选项类似,但会存储自指定时间以来的提交。git clone --separate-dir
- 我自己的想法是使用同一个地方来存储所有 .git 目录。 (因此,在进行克隆时,20 个存储库中的每一个都会 link 到同一个地方。还不知道是否可行,只是分享我的想法。
--depth
是否意味着存储库最多有 n 次提交,或者仅在克隆时检查,然后存储库可以随时间增长?
您可以尝试将 .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会突然报变化
git clone --local
- Each repository will share .git/objects with a bare repository, but this implies .bare repository mush be available locally (so it cant be GitHub, right?)
不太对,不。您可以将其与任何本地克隆一起使用,无论是否裸机。但总的来说,如果这完全有效,您也不需要 --local
:您可以从本地路径名克隆。
例如,假设 userA
,其主目录是 /home/userA
,克隆了 GitHub 存储库,制作了一个完整的非裸克隆。进一步假设 userB
可以 从 /home/userA
读取 。因此,用户 B 可以:
git clone /home/userA/BigRepository
创建./BigRepository
。如果他在他的主目录中执行此操作,他将得到 /home/userB/BigRepository
,其中包含与 userA
的克隆相同的所有提交。
因为 Git 会创建硬链接,如果用户 A 现在 删除 他的存储库,他不会重新获得他的 space (所以如果磁盘配额是实际上,用户 A 没有取回他的配额)。用户 B 仍然具有指向用户 A 所拥有的文件的链接。一切仍然有效;只是制作第一个克隆的人拥有 "paid for" 适当的存储库的初始存储。
(用户 B "pays for" 他自己的 工作树 。他共享 .git/objects
文件 ,包括pack 文件,用户 A 创建。这些文件都是只读的,在任何时候,无论用户 B 是否共享用户 A 的文件,所以用户 B 不能 write 对那些文件并不重要。)
这个过程的一个非常小的缺点是用户 B 可能想要更改他的 origin
URL 以指向 GitHub 存储库而不是到用户 A 的克隆,并且在他这样做之前,他不会看到用户 A 看到的同一组远程跟踪名称(origin/*
名称)。
用户 C 可以使用前面的任一存储库重复此过程。
git clone --depth <n>
- which will reduce the size of the repo, but also reduce local history to n objects.
大多数情况下,是的。尽管 n 在技术上是错误的:
Will
--depth
imply that repositories will have at most n commits, or is it checked only when cloning, and then the repository can grow with time?
它们不仅随着时间的推移而增长,数字 n 并不代表您的建议。它是深度,而不是提交次数。本例中的深度是指图遍历的技术术语。
记住 Git 使用 commit 作为它的基本存储单元。 (提交可以进一步细分,但出于我们的目的,它们是单位。)每个提交都有一个唯一的哈希 ID,并且可以表示为图中的节点或顶点。每个提交还存储其直接前任提交的哈希 ID:这些形成单向边或 arcs 链接节点,因此形成图的其余部分。
我们可以像这样绘制图形的位:
... <-F <-G <-H
其中每个字母代表一个提交哈希 ID。每个提交中存储的哈希 ID 充当指向早期提交的指针。为了方便地找到这个链的 end,我们——或者 Git——建立一个 分支名称,或者其他形式的名称,指向链中的 last 提交:
...--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
每个 "snip" 点代表一个 浅移植 ,我们知道那里有 更多提交,但我们我故意 省略了 那些提交。省略的提交的哈希 ID 被写入 .git/shallow
并且 Git 知道,当它访问其父项列在 .git/shallow
中的提交时,不会试图找到父提交。
--depth
参数选择剪辑点。这发生在 git fetch
的时候——git clone
是一个花哨的六部分包装器,其中包括 git fetch
作为第五步。剪辑点保留在那里,它们所在的位置,除非并且直到您 运行 a git fetch
带有特定参数以加深或进一步浅化存储库。新提交以通常的方式添加并使图表更深,包括任何用户 运行.
git fetch
操作
git clone --shallow-since
- as I understand it will work similarly to--depth
option but will store commits since the specified time.
是的:它只是一种更有用且不易混淆的设置 "snip" 点的方法。
git clone --separate-dir
你是说 --separate-git-dir
。这没有实际意义:您在此处指定的目录由克隆操作创建和填充。如果与任何较早的选项结合使用,那将有助于减少 space 的需要,否则它只会将工作树与适当的存储库分开。
在标准设置中,存储库本身出现在 中 工作树中名为 .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
克隆,以便它获得每个引用并可以更轻松地更新。 (我在之前的工作中对此进行了一些试验,这里有一些问题使得更新变得棘手,所以这可能不像你一开始想象的那么有用。)
一旦 "reference clone" 存在,每个用户都可以:
git clone --reference <path> <github-url>
他们的 Git 将联系位于 GitHub 的 Git,并从中获取他们制作完整克隆所需的信息。但是,他们并没有真正制作完整的克隆,而是检查参考克隆以查看它是否已经拥有他们想要的对象。无论何时何地,参考克隆已经拥有这些对象,它们的 Git 将仅 使用 现有参考克隆中的那些现有对象。
这意味着 git clone
本身运行速度非常快,几乎不使用额外的磁盘 space。制作原始的 ~3GB 参考克隆可能需要几分钟甚至几小时,但是当其中一位用户执行此 git clone --reference
操作时,它应该会在几秒钟内完成。此外,它 "cleanly" 的工作原理是,如果他们需要来自 GitHub 的新对象,他们只需照常从 GitHub 获取它们。因为没有提交——没有 Git 任何类型的对象,真的——可以 改变 ,参考克隆仅用于提供 你 最初放入它。新对象逐渐扩展每个用户的存储库。
(您可以在将来更新参考克隆。然后个人用户可以重新克隆以减少他们的磁盘使用量。这里棘手的部分是您必须确保没有对象,也没有打包文件, 在你更新它和他们重新克隆的时间之间从参考克隆中消失。你可以改为只制作一个 new 参考克隆,等到所有用户都重新克隆了新的参考克隆,然后删除原始参考,以避免这种棘手。)