32

我有一个相对较大的 git 存储库位于本地网络上一个较旧的慢速主机上的虚拟机中的情况,在该主机上进行初始克隆需要相当长的时间。

ravn@bamboo:~/git$ git clone gitosis@gitbox:git00
Initialized empty Git repository in /home/ravn/git/git00/.git/
remote: Counting objects: 89973, done.
remote: Compressing objects: 100% (26745/26745), done.
remote: Total 89973 (delta 50970), reused 85013 (delta 47798)
Receiving objects: 100% (89973/89973), 349.86 MiB | 2.25 MiB/s, done.
Resolving deltas: 100% (50970/50970), done.
Checking out files: 100% (11722/11722), done.
ravn@bamboo:~/git$

gitosis 中没有特定于 git 的配置更改。

有什么方法可以将接收位加速到网络的能力?


编辑:我需要新的存储库与上游存储库正确连接。据我了解,这需要 git 进行克隆,因此在 git 之外复制原始位将不起作用。

4

6 回答 6

31

附言。公平警告:

git通常被认为非常快。你应该尝试从 darcs、bazaar、hg 克隆一个完整的 repo(上帝禁止:TFS 或颠覆......)。此外,如果您经常从头开始克隆完整的存储库,那么您无论如何都会做错事。您可以随时git remote update获得增量更改。

有关保持完整回购同步的各种其他方法,请参阅,例如

(包含指向其他相关 SO 帖子的链接)

愚蠢的副本

如前所述,您可以使用“哑”文件传输复制存储库。

这肯定不会浪费时间进行压缩、重新包装、分解和/或过滤。

另外,你会得到

  • 挂钩
  • 配置(远程、推送分支、设置(空白、合并、别名、用户详细信息等)
  • stash (另请参阅Can I fetch a stash from a remote repo into a local branch?
  • 重新缓存
  • 引用日志
  • 备份(来自过滤器分支,例如)和其他各种东西(来自 rebase、bisect 等的中间状态)

这可能是也可能不是您需要的,但很高兴知道这一事实


Git clone 默认优化带宽。由于 git clone 在默认情况下不会镜像所有分支(请参阅 参考资料--mirror),因此仅按原样转储包文件是没有意义的(因为这可能会发送超出所需的数量)。

当分发给真正大量的客户时,请考虑使用bundles

如果你想要一个没有服务器端成本的快速克隆,git 方式bundle create. 您现在可以分发捆绑包,甚至无需涉及服务器。如果您的意思bundle... --all不仅仅是简单git clone,请考虑bundle ... master减少音量。

git bundle create snapshot.bundle --all # (or mention specific ref names instead of --all)

而是分发快照包。这是两全其美的结果,当然您不会从上面的项目符号列表中获得项目。在接收端,只需

git clone snapshot.bundle myclonedir/

压缩配置

您可以通过减少/删除压缩来降低服务器负载。看看这些配置设置(我假设pack.compression可以帮助你降低服务器负载)

核心压缩

整数 -1..9,表示默认压缩级别。-1 是 zlib 默认值。0 表示不压缩,1..9 是各种速度/大小的权衡,9 是最慢的。如果设置,这将为其他压缩变量提供默认值,例如 core.loosecompression 和 pack.compression。

core.loosecompression

整数 -1..9,表示不在包文件中的对象的压缩级别。-1 是 zlib 默认值。0 表示不压缩,1..9 是各种速度/大小的权衡,9 是最慢的。如果未设置,则默认为 core.compression。如果未设置,则默认为 1(最佳速度)。

打包压缩

整数 -1..9,表示包文件中对象的压缩级别。-1 是 zlib 默认值。0 表示不压缩,1..9 是各种速度/大小的权衡,9 是最慢的。如果未设置,则默认为 core.compression。如果未设置,则默认为 -1,zlib 默认值,这是“速度和压缩之间的默认折衷(目前相当于 6 级)。”

请注意,更改压缩级别不会自动重新压缩所有现有对象。您可以通过将 -F 选项传递给 git-repack(1) 来强制重新压缩。

给定充足的网络带宽,这实际上导致更快的克隆。不要忘记git-repack -F何时决定对其进行基准测试!

于 2011-11-18T10:23:55.693 回答
29

使用深度创建浅克隆。

git clone --depth 1 <repository>
于 2014-06-06T16:56:32.773 回答
7

git clone --depth=1 ... 2014 年的建议将在 2019 年第二季度使用 Git 2.22 变得更快。
这是因为,在初始的“ git clone --depth=...”部分克隆期间,为枚举和跳过承诺对象(根据定义是从另一端获取的所有对象)的大部分连接检查花费周期是没有意义的。
这已经被优化了。

clone:对部分克隆进行更快的对象检查

对于部分克隆,做一个完整的连接检查是浪费的;我们跳过承诺对象(对于部分克隆,它们是所有已知对象),并枚举它们以将它们从连接检查中排除在大型存储库上可能会花费大量时间。

最多,我们想确保我们得到任何想要的 refs 引用的对象。
对于部分克隆,只需检查这些对象是否已转移。

结果:

 Test                          dfa33a2^         dfa33a2
 -------------------------------------------------------------------------
 5600.2: clone without blobs   18.41(22.72+1.09)   6.83(11.65+0.50) -62.9%
 5600.3: checkout of result    1.82(3.24+0.26)     1.84(3.24+0.26) +1.1%

快 62%!


在 Git 2.26(2020 年第一季度)中,现在在部分克隆中禁用了不需要的连接检查。

请参阅Jonathan Tan ( ) 的提交 2df1aa2提交 5003377(2020 年 1 月 12 日(由Junio C Hamano 合并 -- --提交 8fb3945中,2020 年 2 月 14 日)jhowtan
gitster

connected: 验证部分克隆的承诺性

签字人:Jonathan Tan
审核人:Jonathan Nieder

提交dfa33a298d (" clone: do faster object check for partial clones", 2019-04-21, Git v2.22.0-rc0 -- merge ) 优化了克隆时完成的连通性检查,--filter仅检查 refs 直接指向的对象是否存在.
但这还不够:它们还需要是承诺对象。
通过检查这些对象是否是 Promisor 对象(即它们出现在 Promisor 包中)来使此检查更加健壮。

和:

fetch: 放弃全连接检查是否--filter

签字人:Jonathan Tan
审核人:Jonathan Nieder

如果指定了过滤器,我们不需要对刚刚获取的包文件的内容进行完整的连通性检查;我们只需要检查引用的对象是否是承诺对象。

这显着加快了对具有许多 Promisor 对象的存储库的获取速度,因为在连接检查期间,所有 Promisor 对象都被枚举(以将它们标记为 UNINTERESTING),这需要大量时间。


而且,仍然使用 Git 2.26(2020 年第一季度),对象可达性位图机制和部分克隆机制还没有准备好一起工作,因为部分克隆使用的一些对象过滤标准本质上依赖于对象遍历,但位图机制是绕过该对象遍历的优化

然而,在某些情况下,他们可以一起工作,并且他们被教导过。

请参阅Junio C Hamano ( ) 的提交 20a5fd8(2020 年 2 月 18 日。 参见提交3AB3185提交84243DA提交4F3BD56提交CC4AA28 ,COC4AA28,提交2AAEB9A,6663AE0,提交4EB707E,commit EA047A8,commits 608d9c9 ,commit 55cb10f,commit 55cb10f,commit 55cb10f commit 792f811 commits d9020 and d90220,and d90220 , fe 9020 , fe 90fe 90fe551cf8b(2020 年 2 月 13 日)作者:杰夫·金(gitster
peff.
(由Junio C Hamano 合并 -- gitster--0df82d9 提交中,2020 年 3 月 2 日)

pack-bitmap: 实现BLOB_LIMIT过滤

签字人:杰夫·金

就像之前实现的提交BLOB_NONE一样,我们可以BLOB_LIMIT通过查看结果中任何 blob 的大小并适当地取消设置它们的位来支持过滤器。
这比稍微贵一点,BLOB_NONE,但仍然产生明显的加速(这些结果在git.git上):

Test                                         HEAD~2            HEAD
------------------------------------------------------------------------------------
5310.9:  rev-list count with blob:none       1.80(1.77+0.02)   0.22(0.20+0.02) -87.8%
5310.10: rev-list count with blob:limit=1k   1.99(1.96+0.03)   0.29(0.25+0.03) -85.4%

实现类似于BLOB_NONE一个,除了我们必须在遍历 blob 类型位图时逐个对象(因为我们无法屏蔽匹配项,但必须单独查找每个 blob 的大小) .
using 的技巧ctz64()来自show_objects_for_type(),它同样需要找到单个位(但希望快速跳过没有 blob 的大块)。


Git 2.27(2020 年第二季度)将简化部分克隆存储库中的提交祖先连接性检查,其中假定“承诺”对象可以从承诺者远程存储库中按需延迟获取。

请参阅Jonathan Tan ( ) 的提交 2b98478(2020 年 3 月 20 日(由Junio C Hamano 合并 -- --提交 0c60105中,2020 年 4 月 22 日)jhowtan
gitster

connected:总是使用部分克隆优化

签字人:Jonathan Tan
审核人:Josh Steadmon

使用50033772d5 (" connected: verify promisor-ness of partial clone", 2020-01-30, Git v2.26.0-rc0 -- merge in batch #5 ) 中的快速路径(检查承诺包)check_connected()现在通过慢速路径 (rev-list) > - 如果所有要检查的对象都在承诺包中找到,则快速路径和慢速路径都会通过;

  • 否则,快速路径肯定不会通过。

这意味着我们总是可以在需要执行慢速路径时尝试快速路径。

快速路径当前由一个标志保护;因此,删除该标志。
此外,使快速路径回退到慢速路径 - 如果快速路径失败,失败的 OID 和所有剩余的 OID 将被传递到 rev-list。

主要的用户可见的好处是从部分克隆中获取的性能 - 特别是在获取之前完成的连接检查的加速。
特别是,对我计算机上的部分克隆的无操作获取从 7 秒加快到 0.01 秒。这是对2df1aa239c中工作的补充(“ fetch: forgo full connectivity check if --filter”, 2020-01-30, Git v2.26.0-rc0 -- merge在批次#5中列出),它是上述50033772d5。在该提交中,加快了获取后的连接检查。

在这些情况下,添加快速路径可能会导致性能下降:

  • 如果部分克隆或提取到部分克隆失败,Git 将毫无结果地运行rev-list(预计提取的所有内容都会进入承诺包,因此如果没有发生这种情况,rev-list 很可能也会失败) .

  • 在部分克隆服务于接收包的情况下(在我看来,不太可能)由接收包完成的任何连接检查。

我认为这些情况很少见,并且这种情况下的性能下降足够小(额外的对象数据库访问),避免标志的好处超过了这些。


在 Git 2.27(2020 年第 2 季度)中,带有对象过滤器“ --filter=tree:0”的对象遍历现在可以利用可用的包位图。

请参阅Jeff King ( ) 的commit 9639474commit 5bf7f1e(2020 年 5 月 4 日。 请参阅Taylor Blau ( ) 的提交 b0a8d48提交 856e12c(2020 年 5 月 4 日(由Junio C Hamano 合并 -- --commit 69ae8ff中,2020 年 5 月 13 日)peff
ttaylorr
gitster

pack-bitmap.c: 支持'tree:0'过滤

签字人:Taylor Blau

在上一个补丁中,我们可以轻松定义排除特定类型的所有对象的其他过滤器。--filter=tree:<n>当 ' n' 等于时,使用它来实现 ' ' 过滤器的位图级过滤0

位图对一般情况没有帮助,因为对于 ' n > 0' 的值,对象过滤机制需要完整的树遍历才能确定给定树的深度。
缓存它也不是显而易见的,因为同一个树对象可以根据上下文具有不同的深度(例如,树在两次提交之间的目录层次结构中向上移动)。

但是, ' n = 0' 案例可以得到帮助,而这个补丁就是这样做的。
在这棵树中运行p5310.11并在带有内核的 master 上运行,我们可以看到这种情况有很大帮助:

Test                                  master              this tree
--------------------------------------------------------------------------------
5310.11: rev-list count with tree:0   10.68(10.39+0.27)   0.06(0.04+0.01) -99.4%

和:

请参阅Jeff King ( ) 的commit 9639474commit 5bf7f1e(2020 年 5 月 4 日。 请参阅Taylor Blau ( ) 的提交 b0a8d48提交 856e12c(2020 年 5 月 4 日(由Junio C Hamano 合并 -- --commit 69ae8ff中,2020 年 5 月 13 日)peff
ttaylorr
gitster

pack-bitmap: 通过对象过滤器填充遍历

签字人:Jeff King
签字人:Taylor Blau

有时位图遍历仍然需要手动执行一些提交,因为这些提交不包含在位图包文件中(例如,由于自上次完全重新打包后的推送或提交)。

如果我们得到一个对象过滤器,我们不会将它传递给这个遍历。
正确性不是必需的,因为位图代码有自己的过滤器来对位图结果进行后处理(它必须过滤掉位图包文件提到的对象)。

并且使用 blob 过滤器,也没有性能理由传递这些过滤器。填充遍历可以从结果中省略它们,但这不会为我们节省任何时间,因为我们仍然必须遍历每个树条目以查看它是否为 blob。

但是现在我们支持树过滤器,就有了节省的机会。过滤器tree:depth=0意味着我们可以完全避免访问树,因为我们知道我们不会访问它们(或它们指向的任何子树或 blob)。
中的新测试p5310显示了这一点(“部分位图”状态是一种状态HEAD~100,它的祖先都在位图包中,但HEAD~100..HEAD不是)。

以下是结果(针对linux.git):

Test                                                  HEAD^               HEAD
-------------------------------------------------------------------------------------------------
[...]
5310.16: rev-list with tree filter (partial bitmap)   0.19(0.17+0.02)     0.03(0.02+0.01) -84.2%

节省的绝对数量并不,但请记住,我们只省略了 100 个第一父链接(在linux.git此处的版本中,即 894 个实际提交)。

在更病态的情况下,我们可能有更大比例的非位图提交。我没有费心在 perf 脚本中创建这样的案例,因为设置很昂贵,这足以显示节省的百分比。


在 Git 2.32(2021 年第 2 季度)中,对允许某些对象丢失和延迟检索的“承诺包”的处理已得到优化(有点)。

请参阅Jeff King ( )的提交 c1fa951提交 45a187c提交 fcc07e9(2021 年 4 月 13 日) 。(由Junio C Hamano 合并 -- --提交 13158b9中,2021 年 4 月 30 日)peff
gitster

revision: 避免使用 --exclude-promisor-objects 进行解析

签字人:杰夫·金

--exclude-promisor-objects给出时,在遍历任何对象之前,我们遍历任何 Promisor 包中的所有对象,将它们标记为 UNINTERESTING 和 SEEN。
我们将通过迭代包获得的 oid 转换为一个对象parse_object(),但这有两个问题:

  • 很慢;我们正在 zlib 膨胀(并从增量重构)packfile 中每个对象的每个字节
  • 它将树缓冲区附加到它们的结构上,这意味着我们的堆使用量将增长以同时存储每个未压缩的树。
    这可以是千兆字节。

我们显然可以通过在解析树缓冲区后释放它们来修复第二个问题。
但我们可以观察到该函数根本不查看对象内容!我们调用的唯一原因parse_object()是我们需要一个“ struct object”来设置标志。
这里有两个选项:

  • 我们可以通过 查找对象类型oid_object_info(),然后调用相应的lookup_foo()函数
  • 我们可以调用lookup_unknown_object(),它为我们提供了一个OBJ_NONE结构(稍后将object_as_type()通过调用lookup_commit()等自动转换)。

第一个更接近当前代码,但我们确实付出了代价来查找每个对象的类型。
后者在 CPU 中应该更高效,尽管它会浪费一点内存(“未知”对象结构是所有对象类型的联合,因此某些结构比它们需要的大)。
它还存在在lookup_object()直接调用但尚未准备好处理的代码中触发潜在错误的风险OBJ_NONE(这样的代码已经存在错误,但我们使用lookup_unknown_object()的频率太低以至于它可能会被隐藏)。

我在这里选择了第二个选项。
我认为风险并不高(无论如何我们都希望找到并修复任何此类错误),并且总体上应该更有效。

p5600 中的新测试显示了改进(这是在git.git上):

Test                                 HEAD^               HEAD
-------------------------------------------------------------------------------
5600.5: count commits                0.37(0.37+0.00)     0.38(0.38+0.00) +2.7%
5600.6: count non-promisor commits   11.74(11.37+0.37)   0.04(0.03+0.00) -99.7%

这个脚本的改进特别大,因为新克隆的部分 repo 中的每个对象都是一个承诺对象。
因此,在将它们全部标记后,就没有什么可遍历的了。

于 2019-05-13T19:33:34.263 回答
4

在意识到数据传输速度的上限,是在git“外部”建立的ssh连接后,我做了一些实验,发现使用pcsp(Putty scp)的上限是3,0 MB/s因为正确选择了河豚加密方案。原始 ftp 的控制实验表明传输速度为 3.1 MB/s,因此表明这是网络的上限。

这在 vmware 虚拟机管理程序中运行,并且由于执行网络 I/O 的进程使用了​​几乎 100% 的 cpu,这表明瓶颈是 Ubuntu 网卡驱动程序。然后我发现即使安装了 vmware 工具,由于某种原因,内核仍然使用 vlance 驱动程序(模拟 10 MBps 的网卡和 IRQ 等)而不是 vmxnet 驱动程序(直接与管理程序对话)。现在等待更改服务窗口。

换句话说,问题不在于 git,而在于底层的“硬件”。

于 2011-11-21T10:35:51.543 回答
2

我正在对 git clone 进行基准测试。

如果项目包含子模块,则使用 --jobs 选项可以更快:

git clone --recursive --shallow-submodules --depth 1 --branch "your tag or branch" --jobs 5 --  "your remote repo"
于 2019-05-02T07:31:13.223 回答
1

从日志看来您已经完成了克隆,如果您的问题是您需要在不同的机器上多次执行此过程,您可以将存储库目录从一台机器复制到另一台机器。这种方式将保留每个副本与您从中克隆的存储库之间的关系(远程)。

于 2011-11-18T10:06:20.007 回答