7

有没有办法硬链接包含多个 Git 存储库的文件夹中的所有重复对象?

解释:

我在我的公司服务器(Linux 机器)上托管了一个 Git 服务器。这个想法是有一个主要的规范存储库,每个用户都没有推送访问权限,但是每个用户都派生了规范存储库(将规范克隆到用户的主目录,从而实际上创建了硬链接)。

/canonical/Repo /Dev1/Repo(最初克隆时硬链接到 /canonical/Repo 的对象) /Dev2/Repo(最初克隆时硬链接到 /canonical/Repo 的对象)

这一切都很好。问题出现在:

Dev1:将一个巨大的提交推送到他在服务器上的 fork (/Dev1/Repo) Dev2:在他的本地系统上获取它,进行自己的更改并将其推送到他自己的服务器上的 fork (/Dev2/Repo)

(现在同一个“巨大”文件驻留在服务器上的两个开发人员的分支中。它不会自动创建硬链接。)

这疯狂地占用了我的服务器空间!

如何在两个分叉之间或规范的对象之间创建硬链接,以便节省服务器空间,并且每个开发人员在从他/她的本地计算机上的分叉克隆时获取所有数据?

4

2 回答 2

4

现在,相同的“巨大”文件驻留在服务器上开发人员的两个分支中。它不会自动创建硬链接

实际上,在 Git 2.20 中,这个问题可能会消失,因为delta Islands是一种进行 delta 计算的新方法,因此存在于一个分叉中的对象不会与不出现在同一个分叉存储库中的另一个对象形成增量.

请参阅Christian Couder ( ) 的提交 fe0ac2f提交 108f530提交 f64ba53(2018 年 8 月 16 日。 帮助者:Jeff King ( )Duy Nguyen ( )。 请参阅Jeff King ( )的提交 9eb0986提交 16d75fa提交 28b8a73提交 c8d521f(2018 年 8 月 16 日) 。 帮助者:Jeff King ( )Duy Nguyen ( )(由Junio C Hamano 合并 -- --提交 f3504eachriscool
peffpclouds
peff
peffpclouds
gitster, 2018 年 9 月 17 日)

添加delta-islands.{c,h}

允许用户“分叉”现有存储库的托管服务提供商希望这些分叉共享尽可能多的磁盘空间。

替代方案是一种现有的解决方案,可以将所有分叉中的所有对象保存到一个唯一的中央存储库中,但这可能有一些缺点。
特别是在打包中央存储库时,将在来自不同分支的对象之间创建增量。

这会使克隆或获取分叉变得更慢且 CPU 密集度更高,因为 Git 可能必须为许多对象计算新的增量以避免从不同的分叉发送对象。

因为效率低下主要出现在一个对象与另一个不存在于同一个分叉中的对象之间进行区分时,我们将对象划分为出现在同一个分叉中的集合,并定义“增量岛”。
在查找 delta base 时,我们不允许将同一岛之外的对象视为其基础。

所以“增量岛”是一种将来自不同分支的对象存储在同一个存储库和包文件中的方法,而不会在来自不同分支的对象之间存在增量。

该补丁实现了“ delta-islands.{c,h}”中的 delta 孤岛机制,但尚未使用它。

struct object_entry不过,在“”中的“ ”中添加了一些新字段pack-objects.h

Documentation/git-pack-objects.txt:三角洲岛

三角洲群岛

在可能的情况下,pack-objects尝试重用现有的磁盘增量,以避免不得不即时搜索新的增量。这是服务获取的重要优化,因为这意味着服务器可以完全避免膨胀大多数对象,而直接从磁盘发送字节。

当一个对象被存储为一个接收者没有的基础(并且我们还没有发送)的增量时,这种优化就不起作用了。在这种情况下,服务器会“破坏”增量并必须找到一个新的增量,这具有很高的 CPU 成本。因此,磁盘上增量关系中的对象集与客户端将获取的对象匹配对于性能很重要。

在普通存储库中,这往往会自动工作。
这些对象大多可以从分支和标签中访问,这就是客户端获取的内容。我们在服务器上发现的任何增量都可能位于客户端拥有或将拥有的对象之间。

但是在某些存储库设置中,您可能有几个相关但独立的参考提示组,客户端倾向于独立获取这些组。

例如,假设您在单个共享对象存储中托管存储库的多个“分支”,并让客户端通过 GIT_NAMESPACE 将它们视为单独的存储库或使用替代机制的单独存储库。

天真的重新打包可能会发现对象的最佳增量是针对仅在另一个分叉中找到的基础。
但是当客户端获取时,他们将没有基础对象,我们必须在运行中找到一个新的增量。

如果您在外部有许多引用refs/heads/并且refs/tags/指向相关对象(例如,refs/pull或被refs/changes某些托管服务提供商使用),则可能存在类似的情况。默认情况下,客户端仅获取头和标签,并且无法按原样发送仅在其他组中找到的对象的增量。

Delta 岛通过允许您将 ref 分组到不同的“岛”来解决这个问题

Pack-objects 计算哪些对象可以从哪些岛屿到达,并拒绝从一个对象A与一个不存在于所有A岛屿中的基础进行增量。这会导致包稍微大一些(因为我们错过了一些 delta 机会),但保证了一个岛的获取不会由于跨越岛边界而不得不在运行中重新计算 delta。


但是有一个副作用:一些命令更加冗长。Git 2.23(2019 年第三季度)修复了这个问题。

请参阅Jeff King ( ) 的提交 bdbdf42(2019 年 6 月 20 日(由Junio C Hamano 合并 -- --提交 a4c8352中,2019 年 7 月 9 日)peff
gitster

delta-islands: 尊重progress国旗

delta island 代码总是打印“ Marked %d islands”,即使进度已被--no-progress或通过将 stderr 发送到非 tty 来抑制。

让我们将progress布尔值传递给load_delta_islands().
我们已经为进度表做了同样的事情resolve_tree_islands()

于 2018-09-22T16:40:25.010 回答
3

我决定这样做:

 shared-objects-database.git/
foo.git/
  objects/info/alternate (will have ../../shared-objects-database.git/objects)
bar.git/
  objects/info/alternate (will have ../../shared-objects-database.git/objects)
baz.git/
  objects/info/alternate (will have ../../shared-objects-database.git/objects)

所有的分支都将在其 objects/info/alternates 文件中有一个条目,该条目给出了对象数据库存储库的相对路径。

使对象数据库成为存储库很重要,因为我们可以保存具有相同名称存储库的不同用户的对象和引用。

脚步:

  1. git init --bare shared-object-database.git
  2. 每次推送到任何 fork(通过 post-recieve)或运行 cronjob 时,我都会运行以下代码行

    for r in list-of-forks
        do
    

    ( cd "$r" && git push ../shared-objects-database.git "refs/ :refs/remotes/$r/ " && echo ../../shared-objects-database.git/objects >objects /info/alternates # 为了保存,我每次都将“胖”对象添加到备用对象中)完成

然后在下一个“git gc”中,alternate 中已经存在的 fork 中的所有对象都将被删除。

git repack -adl也是一种选择!

这样我们节省了空间,以便两个用户在服务器上各自的分叉上推送相同的数据将共享对象。

我们需要在共享对象数据库中设置gc.pruneExpire变量。never只是为了安全!

要偶尔修剪对象,请将所有分叉作为远程对象添加到共享、获取和修剪!Git 将完成剩下的工作!

(我终于找到了适合我的解决方案!(未在生产中测试!:p 感谢这篇文章。)

于 2014-09-18T13:18:18.343 回答