我正在寻找减少git
存储库大小的方法。在大多数情况下,搜索引导我git gc --aggressive
。我还读到这不是首选方法。
为什么呢?如果我正在运行gc --aggressive
,我应该注意什么?
git repack -a -d --depth=250 --window=250
超过gc --aggressive
。为什么? repack
如何减小存储库的大小?另外,我不太清楚标志--depth
和--window
。
我应该在gc
和repack
之间选择什么?我应该何时使用gc
和repack
?
答案 0 :(得分:65)
如今没有区别:git gc --aggressive
根据Linus 2007年提出的建议运作;见下文。从版本2.11(2016年第4季度)开始,git默认深度为50.大小为250的窗口是好的,因为它扫描每个对象的较大部分,但是250的深度是坏的,因为它使每个链都指向非常深的旧对象,这会减慢所有未来的git操作,从而降低磁盘使用率。
Linus建议(请参阅下面的完整邮件列表帖子)使用git gc --aggressive
只有当你用他的话说“一个真的坏包”或“非常糟糕的三角洲”时“但是”几乎总是如此,在其他情况下,这实际上是一件非常糟糕的事情。“结果甚至可能使您的存储库处于比您开始时更糟糕的状态!
他建议在导入“漫长且涉及的历史”后正确执行此操作的命令是
git repack -a -d -f --depth=250 --window=250
但是这假设您已经从存储库历史记录中removed unwanted gunk并且已经按照清单来缩小git filter-branch
documentation中找到的存储库。
git-filter-branch可用于删除文件的子集,通常使用
--index-filter
和--subdirectory-filter
的某种组合。人们期望生成的存储库小于原始存储库,但是你需要更多的步骤来实际使它变小,因为Git努力不会丢失你的对象,直到你告诉它。首先要确保:
如果blob在其生命周期内被移动,那么您确实删除了文件名的所有变体。
git log --name-only --follow --all -- filename
可以帮助您找到重命名。您真的已经过滤了所有裁判:在致电
--tag-name-filter cat -- --all
时使用git filter-branch
。然后有两种方法可以获得更小的存储库。更安全的方法是克隆,保持原始原封不动。
- 用
git clone file:///path/to/repo
克隆它。克隆将没有删除的对象。见git-clone。 (请注意,使用普通路径进行克隆只会将所有内容硬链接!)如果你真的不想克隆它,无论出于何种原因,请检查以下几点(按此顺序)。这是一种非常具有破坏性的方法,因此请进行备份或返回克隆它。你被警告了。
删除由git-filter-branch备份的原始引用:说
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
使用
git reflog expire --expire=now --all
暂停所有reflog。垃圾会使用
git gc --prune=now
收集所有未引用的对象(或者如果您的git gc
不够新,无法支持--prune
的参数,请改用git repack -ad; git prune
。< / p>
Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST) From: Linus Torvalds <torvalds at linux-foundation dot org> To: Daniel Berlin <dberlin at dberlin dot org> cc: David Miller <davem at davemloft dot net>, ismail at pardus dot org dot tr, gcc at gcc dot gnu dot org, git at vger dot kernel dot org Subject: Re: Git and GCC In-Reply-To: <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com> Message-ID: <alpine.LFD.0.9999.0712052132450.13796@woody.linux-foundation.org> References: <4aca3dc20712051947t5fbbb383ua1727c652eb25d7e@mail.gmail.com> <20071205.202047.58135920.davem@davemloft.net> <4aca3dc20712052032n521c344cla07a5df1f2c26cb8@mail.gmail.com> <20071205.204848.227521641.davem@davemloft.net> <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com>
2007年12月6日星期四,丹尼尔柏林写道:
实际上,事实证明
git-gc --aggressive
做了这个愚蠢的事情 有时打包文件,无论你是否转换过 SVN回购与否。绝对。
git --aggressive
大多是愚蠢的。它真的只对它有用 “我知道我有一个真的坏包,我想扔掉 我所做的所有糟糕的包装决定。“为了解释这一点,值得解释(你可能已经意识到了,但是 让我逐步了解基础知识)git delta-chains如何工作,以及如何工作 它们与大多数其他系统截然不同。
在其他SCM中,delta链通常是固定的。它可能是“前锋” 或者“向后”,当你使用存储库时,它可能会有所改进, 但一般来说,它是对单个文件的一系列更改 一种单一的SCM实体。在CVS中,它显然是
*,v
文件,而且很多 其他系统做的事情很相似。Git也会做三角形链,但它更“宽松”地做了它们 不是固定的实体。 Deltas是针对任何随机的其他版本生成的 那个git认为是一个很好的delta候选者(各种公平的 成功的启发式方法),绝对没有硬分组规则。
这通常是一件非常好的事情。这对各种概念都有好处 原因(即,git内部从来都不需要关心整体 修订链 - 它根本没有根据增量来考虑,但是 它也很棒,因为摆脱僵硬的delta规则意味着 通过将两个文件合并在一起,git完全没有任何问题, 例如 - 根本没有任意
*,v
“修订文件” 一些隐藏的意思。这也意味着增加的选择更加开放 题。如果将增量链限制为仅一个文件,则实际上不会 关于如何处理增量有很多选择,但是在git中,确实如此 可能是一个完全不同的问题。
这就是真正命名为
--aggressive
的地方 git通常会尝试重用delta信息(因为这是一个好主意, 并且它不会浪费CPU时间来重新找到我们发现的所有好的增量 早些时候),有时你想说“让我们从头开始,一片空白 平板,并忽略所有以前的增量信息,并尝试生成 一套新的增量。“所以
--aggressive
并不是真正的咄咄逼人,而是浪费 CPU时间重新做了我们之前做过的决定!有时这是一件好事。特别是一些导入工具可以 产生非常糟糕的三角洲。任何使用
git fast-import
的东西, 例如,可能没有太多的大三角洲布局,所以它可能 值得一提的是“我想从干净的石板开始。”但几乎总是,在其他情况下,这实际上是一件非常糟糕的事情。 这将浪费CPU时间,特别是如果你真的做了一个 早些时候做好三角形工作,最终的结果是不会重复使用全部 你已经找到的那些好的增量,所以你实际上最终会得到一个 更糟糕的最终结果!
我会向Junio发送一个补丁来删除
git gc --aggressive
文档。它可能很有用,但它通常只在您使用时才有用 真正了解它正在做什么,以及那个 文档对你没有帮助。通常,做增量
git gc
是正确的方法,而且更好 比做git gc --aggressive
。它将重新使用旧的增量,并且 当那些旧的增量无法找到时(进行增量GC的原因) 首先!)它将创造新的。另一方面,“长期的初始进口”肯定是正确的 并且涉及历史“是值得花费很多钱的一点 时间找到非常好的增量。然后,每个用户之后(如 只要他们不使用
git gc --aggressive
撤消它!)就会得到 这次一次性活动的优势。特别是对于有大量项目的大型项目 历史悠久,值得做一些额外的工作,告诉三角洲 找到疯狂的代码。所以相当于
git gc --aggressive
- 但正确 - 就是 做(过夜)像git repack -a -d --depth=250 --window=250
深度的东西只是三角洲链的深度 (让他们的历史更久 - 这是值得的空间开销),和 窗口的事情是关于我们想要每个delta的对象窗口有多大 候选人扫描。
在这里,你可能想要添加
-f
标志(这是“全部丢弃” 老三角洲,“因为你现在正在努力确保这一个 实际上找到了好的候选人。然后它将需要永远和一天(即。,“一夜之间做” 事情)。但最终的结果是每个人都在下游 存储库将获得更好的包,而不必花费任何精力 在它自己。
Linus
答案 1 :(得分:47)
我什么时候应该使用gc&amp;重新包装?
正如我在“Git Garbage collection doesn't seem to fully work”中所提到的,git gc --aggressive
本身就不够,甚至不够。
并且,I explain below通常不需要。
最有效的组合是添加git repack
,还有git prune
:
git gc
git repack -Ad # kills in-pack garbage
git prune # kills loose garbage
注意:Git 2.11(2016年第4季度)将默认gc aggressive
深度设置为50
commit 07e7dbf见Jeff King (peff
)(2016年8月11日)
(由Junio C Hamano -- gitster
--合并于commit 0952ca8,2016年9月21日)
gc
:默认积极深度为50“
git gc --aggressive
”用于将delta-chain长度限制为250, 这对于获得额外的空间节省来说太深了 对运行时性能有害。
限制已降至50。摘要是:当前默认值为250 节省大量空间,并节省CPU成本。这不是一个很好的权衡。
--aggressive
的“git-gc
”标记有三件事:
- 使用“
-f
”抛弃现有的增量并从头开始重新计算- 使用“--window = 250”来增加增量效果
- 使用“--depth = 250”来制作更长的delta链
醇>项目(1)和(2)是“积极”重新包装的良好匹配 他们要求重新包装做更多的计算工作,以期获得更好的包装。您在重新包装期间支付成本,而其他操作仅看到好处。
第(3)项不太清楚 允许更长的链意味着对增量的限制更少,这意味着可能找到更好的增量并节省一些空间 但这也意味着访问增量的操作必须遵循更长的链,这会影响它们的性能 所以这是一个权衡,并且不清楚这种权衡甚至是一个好的。
您可以看到常规操作的CPU节省随着我们的增加而提高 减少深度。
但我们也可以看到,随着深度的增加,节省的空间并不是那么大。在10到50之间节省5-10%可能值得CPU权衡。保存1%从50到100,或另外0.5%从100到250可能不是。
说到CPU保存,“git repack
”学会接受--threads=<n>
选项并将其传递给pack-objects。
commit 40bcf31见Junio C Hamano (gitster
)(2017年4月26日)
(Junio C Hamano -- gitster
--于2017年5月29日commit 31fb6f4合并)
重新包装:接受
--threads=<n>
并将其传递给pack-objects
我们已经为--window=<n>
和--depth=<n>
这样做了;这会有所帮助
当用户想要强制--threads=1
进行可重复的测试时
不受赛车多线程的影响。
答案 2 :(得分:13)
git gc --aggressive
的问题在于选项名称和文档具有误导性。
作为Linus himself explains in this mail,git gc --aggressive
基本上是这样做的:
虽然git通常会尝试重新使用delta信息(因为这是一个好主意,并且它不会浪费CPU时间重新找到我们之前发现的所有优秀增量),有时你想说“让我们从头开始,使用空白平板,并忽略所有先前的增量信息,并尝试生成一组新的增量“。
通常不需要在git中重新计算增量,因为git非常灵活地确定这些增量。只有你知道你有非常非常糟糕的增量才有意义。正如Linus所解释的那样,主要使用git fast-import
的工具属于这一类。
大多数情况下,git在确定有用的增量方面表现相当不错,而使用git gc --aggressive
会让你得到的增量可能更糟,同时浪费了大量的CPU时间。
Linus结束了他的邮件,结论git repack
大--depth
和--window
是大多数时候更好的选择;特别是在你导入一个大项目并想确保git找到好的增量之后。
所以相当于
git gc --aggressive
- 但是正确地 - 是(夜间)做的事情
git repack -a -d --depth=250 --window=250
这个深度的东西只是关于delta链的深度(让它们在旧历史中更长 - 它值得开销空间),窗口的事情是我们希望每个delta候选者扫描的对象窗口有多大
在这里,你可能想要添加
-f
标志(这是“丢弃所有旧的增量”,因为你现在实际上是在努力确保这个实际上找到了好的候选者。
答案 3 :(得分:6)
注意。如果没有备份,请不要使用与远程同步的存储库运行git gc --agressive
。
此操作从头开始重新创建增量,如果正常中断,可能会导致数据丢失。
对于我的8GB计算机,攻击性gc在1Gb存储库上的内存不足,提交了10k次小提交。当OOM杀手终止git进程时 - 它给我留下了几乎空的存储库,只有工作树和少数三角洲幸存下来。
当然,它不是存储库的唯一副本,所以我只是重新创建它并从远程拉出(fetch不能用于破坏的回购并且在解决增量问题上陷入僵局&#39;步骤几次我试图做所以),但如果你的回购是完全没有遥控器的单开发商本地回购 - 首先备份它。
答案 4 :(得分:0)
注意:正如Git 2.22(2019年第二季度)所阐明的那样,请小心使用git gc --aggressive
。
请参见commit 0044f77,commit daecbf2,commit 7384504,commit 22d4e3b,commit 080a448,commit 54d56f5,commit d257e0f,{{3} }(2019年4月7日)和commit b6a8d09之前的commit fc559fb,commit cf9cd77,commit b11e856(2019年3月22日)。
(由Ævar Arnfjörð Bjarmason (avar
)在Junio C Hamano -- gitster
--中合并,2019年4月25日)
的有用性
gc
文档:淡化--aggressive
现有的“
gc --aggressive
”文档缺少建议 用户定期运行它。
我已经亲自与许多用户进行了交谈,这些用户已经将这些文档作为使用此选项的建议,并且(通常)是在浪费时间。因此,让我们澄清一下它的真正作用,然后让用户得出自己的结论。
让我们也澄清一下“效果是持久的”,以简述commit ac70c53的形式。
侵略性
提供
--aggressive
选项时,将使用-f
标志调用git-gc documentation now includes,该标志又将--no-reuse-delta
传递给git-repack
。
这将丢弃所有现有的增量并重新计算它们,但代价是 在重新包装上花费更多的时间。此效果主要是持久的,例如当将包和松散的对象合并到另一个包中时,该包中的现有增量可能会被重复使用,但是在许多情况下,我们可能会从较新的包中选择次优的增量。
此外,提供
--aggressive
将调整传递给git-pack-objects的--depth
和--window
选项。
请参阅下面的gc.aggressiveDepth
和gc.aggressiveWindow
设置。
通过使用更大的窗口尺寸,我们更有可能找到更多的最佳增量。在给定的存储库上不运行定制的性能基准的情况下,在该存储库上使用此选项可能不值得。
这需要花费更多时间,并且最终的空间/增量优化可能值得也可能不值得。对于大多数用户及其存储库,完全不使用此功能是正确的权衡。
然后(git-repack
):
gc
文档:请注意--aggressive
对--window
和--depth
的影响由于commit 080a448(
gc
:默认进阶深度为50,2016-08-11,Git v2.10.1),我们在--aggressive
下使用与默认。正如在有意义的提交中所指出的那样,将更深的深度设置为“积极的”默认设置是错误的,因此节省磁盘空间以牺牲运行时性能为代价,这通常与“侵略性的gc”想要。