不久之前,我发布了一个问题,要求就修复由于大量二进制文件很慢的仓库的计划提供反馈。这个问题(不是必读的):Fixing up a git repo that is slowed because of big binary files
我遵循了我的计划,并经历了意想不到的副作用。
我们回购的新鲜克隆最初耗时2-3小时。想出服务器开始交换,并在做完 git config pack.windowMemory 100m&& git config pack.packSizeLimit 200m ,克隆时间下降到~15分钟。
我认为我仍然会执行剩余的计划,所以我为我们的二进制类型禁用了delta compresson,并在repo上运行了 git repack -a -d -F 。 / p>
在此之后,回购的新鲜克隆需要大约20分钟,所以它实际上变得更糟。但真正的问题是每次有人已经克隆了repo尝试推送提交时,他们会“自动打包存储库以获得最佳性能。”。
关于可能出错的问题以及如何/应该如何修复的想法?
答案 0 :(得分:4)
您的回购邮件的大小和pack.packSizeLimit
的低值可能会使包的数量始终高于gc.autopacklimit
。因此,增加其中任何一个以确保gc不会运行每次提交。
我不确定packSizeLimit
会以什么方式影响记忆,但我不相信它会产生任何重大影响。如果您的实验显示不正确,请纠正我。直接影响内存使用的参数是pack.windowMemory
和pack.deltaCacheSize
。
答案 1 :(得分:0)
什么是重新包装?本地克隆,远程?请记住,本地和远程是单独的,这可能意味着您正在获取解压缩的东西然后在本地打包...需要在本地复制远程的配置(并再试一次,我可能会完全关闭碱)。
答案 2 :(得分:0)
您可能想重试相同的 git repack
,这次使用 Git 2.32(2021 年第二季度,将近 8 年之后)及其新的 --geometric=<n>
选项:
"git repack
"(man) 到目前为止只能将阳光下的所有东西重新打包成一个包(或按大小拆分)。
引入了一种更聪明的策略来降低重新打包存储库的成本。
参见 commit 14e7b83(2021 年 3 月 19 日)、commit 2a15964、commit 13d746a、commit dab3247、commit f25e33c(2021 年 3 月 5 日)和 commit 0fabafd 、commit 339bce2、commit c9fff00、commit f62312e(2021 年 2 月 22 日)由 Taylor Blau (ttaylorr
)。
请参阅 commit ccae01c 的 Junio C Hamano (gitster
)(2021 年 3 月 5 日)。
请参阅 commit 20b031f 的 commit 6325da1、commit fbf20ae、commit 60bb5f2、Jeff King (peff
)(2021 年 2 月 22 日)。
(由 Junio C Hamano -- gitster
-- 于 commit 2744383 合并,2021 年 3 月 24 日)
首先:find_kept_pack_entry()
packfile
:引入“find_kept_pack_entry()
”合著者:Jeff King
签字人:Jeff King
签字人:Taylor Blau
审核人:Jeff King
未来的调用者将需要一个函数来为给定的对象 ID 填充“struct pack_entry
”,但仅从它在任何保留包中的位置开始。
特别是,一种新的 'git repack
'(man) 模式可确保生成的包按对象计数形成几何级数,将标记它不想要的包重新打包为“保持在核心中”,并且一旦它访问任何保留的包中的对象,它就会想要停止可达性遍历。
但是,它不想在非保留包或 .keep 包处停止遍历。
明显的替代方法是 'find_pack_entry()
',但这还不够,因为它只返回它找到的第一个包,它可能会或可能不会被保留(并且 mru 缓存使它无法预测你是哪个如果有选择,就会得到)。
简而言之,您可以遍历所有包以寻找每个包中的对象,但它会随着包的数量而扩展,这可能会令人望而却步。
引入'find_kept_pack_entry()
',一个类似于'find_pack_entry()
'的函数,但只填充保留包中的对象。
那么:git pack-objects --stdin-packs
builtin/pack-objects.c
:添加“--stdin-packs”选项推荐人:Jeff King
签字人:Taylor Blau
审核人:Jeff King
在即将到来的提交中,'git repack
'(man) 将要创建一个包,其中包含某些包(包含的包)中的所有对象<强>排除某些其他包中的任何对象(排除的包)。
这个调用者可以自己迭代这些包,并将它找到的对象直接通过标准输入提供给 'git pack-objects
'(man),但这种方法有一些缺点:
git pack-objects
”的调用者自己实现包迭代。但最大的缺点是缺乏可达性遍历。
因为调用者直接传入一个对象列表,这些对象没有得到分配给它们的 namehash,这会对 delta 选择过程产生负面影响,导致 'git pack-objects
' 甚至无法找到好的 delta当它们存在时。
调用者可以自己制定可达性遍历,但以这种方式驱动“git pack-objects
”的唯一方法是进行完整遍历,然后在遍历完成后移除排除包中的对象。< br/>
这可能对关心性能的调用者不利,尤其是在具有许多对象的存储库中。
引入 'git pack-objects --stdin-packs
'(man) 来解决这四个问题。
'git pack-objects --stdin-packs
' 需要 stdin 上的包名称列表,其中 'pack-xyz.pack
' 表示该包已包含,而 '^pack-xyz.pack
' 表示该包已排除。
生成的包包含至少一个包含的包中存在的所有对象,并且不存在于任何排除的包中。
git pack-objects
现在包含在其 man page 中:
--stdin-packs
读取包文件的基本名称(例如,pack-1234abcd.pack
)
来自标准输入,而不是对象名称或修订版
参数。
生成的包包含列在列表中的所有对象
包含的包(那些不是以 ^
开头的),不包括任何
排除包中列出的对象(以 ^
开头)。
与 --revs
不兼容,或暗示 --revs
的选项(例如
--all
),但兼容的 --unpacked
除外。
最后:git repack --geometric=<n>
builtin/repack.c
:添加“--geometric”选项推荐人:Derrick Stolee
签字人:Taylor Blau
审核人:Jeff King
通常对两者都有用:
此补丁在“git repack
”(man) 中实现了“--geometric=' 选项。
这允许调用者指定他们希望每个包至少是前一个最大包的因子倍(按对象计数)。
具体来说,假设存储库有“n”个包文件,标记为 P1、P2、...,直到 Pn。
每个包文件的对象计数等于“objects(Pn)
”。
几何因子为“r
”时,应该是:
objects(Pi) > r*objects(P(i-1))
对于 [1, n]
中的所有 i,包按以下顺序排序
objects(P1) <= objects(P2) <= ... <= objects(Pn).
由于找到真正的最佳重新打包是 NP-hard,我们沿两个方向对其进行近似:
我们假设在开始重新打包之前有一个包的截断,其中截断右边的所有东西已经形成了一个几何级数(或者不存在截断,一切都必须是重新打包)。
我们假设所有小于截止计数的东西都必须重新打包。
这构成了我们的基本假设,但它也可能导致甚至“重”包被重新打包,例如,如果我们有 6 个包含以下对象数量的包:
1、1、1、2、4、32
然后我们将截断点放在 '1, 1' 和 '1, 2, 4, 32' 之间,将前两个包卷成一个包含 2 个对象的包。
这打破了我们的进步并离开了我们:
2, 1, 2, 4, 32
^
(其中“^
”表示我们拆分的位置)。
为了恢复进程,我们将拆分向前移动(朝向更大的包)
将每个包加入我们的新包直到几何级数
已恢复。
在这里,看起来像:
2, 1, 2, 4, 32 ~> 3, 2, 4, 32 ~> 5, 4, 32 ~> ... ~> 9, 32
^ ^ ^ ^
这样做的优点是不会过于频繁地重新打包重装包,同时一次只创建一个新包。
另一个问题是我们假设松散的、索引的和 reflog 的对象是无关紧要的,并将它们混入我们创建的任何新包中。
这可能会导致非幂等结果。
git repack
现在包含在其 man page 中:
-g=<factor>
--geometric=<factor>
排列产生的包结构,使每个连续的包
包含至少 <factor>
倍的对象数作为
下一个最大的包。
git repack
通过确定需要的包文件的“剪切”来确保这一点
重新包装成一个以确保几何级数。它
选择最小的一组包文件,以便与许多较大的包文件一样
可能会留下包文件(按该包中包含的对象计数)
完好无损。
与其他重新打包模式不同,要打包的对象集是确定的 唯一地通过“卷起”的一组包;换句话说, 确定需要组合的包以恢复几何 进展。
当指定 --unpacked
时,松散对象隐式包含在
这种“汇总”,而不考虑它们的可达性。这是主题
将来改变。此选项(意味着完全不同的
重新打包模式)不能保证与所有其他组合一起使用
git repack
的选项)。
Test HEAD^ HEAD
-----------------------------------------------------------------------------------------------
5303.5: repack (1) 57.34(54.66+10.88) 56.98(54.36+10.98) -0.6%
5303.6: repack with kept (1) 57.38(54.83+10.49) 57.17(54.97+10.26) -0.4%
5303.11: repack (50) 71.70(88.99+4.74) 71.62(88.48+5.08) -0.1%
5303.12: repack with kept (50) 72.58(89.61+4.78) 71.56(88.80+4.59) -1.4%
5303.17: repack (1000) 217.19(491.72+14.25) 217.31(490.82+14.53) +0.1%
5303.18: repack with kept (1000) 246.12(520.07+14.93) 217.08(490.37+15.10) -11.8%
<块引用>
和 --stdin-packs
情况,它的扩展性好一点(尽管
即使是 1,000 包也没有那么多):
5303.7: repack with --stdin-packs (1) 0.00(0.00+0.00) 0.00(0.00+0.00) =
5303.13: repack with --stdin-packs (50) 3.43(11.75+0.24) 3.43(11.69+0.30) +0.0%
5303.19: repack with --stdin-packs (1000) 130.50(307.15+7.66) 125.13(301.36+8.04) -4.1%