git gc --aggressive vs git repack


88

我正在寻找减少git存储库大小的方法。搜索将我带入git gc --aggressive大多数时间。我还读到这不是首选方法。

为什么?我在跑步时应该注意些什么gc --aggressive

git repack -a -d --depth=250 --window=250建议超过gc --aggressive。为什么?如何repack减少存储库的大小?另外,我对标志--depth和还不太清楚--window

我应该在gc和之间选择什么repack?什么时候应该使用gcrepack

Answers:


76

如今,两者之间没有任何区别:git gc --aggressive按照Linus在2007年提出的建议进行操作;见下文。从2.11版(2016年第四季度)开始,git默认深度为50。大小为250的窗口是好的,因为它扫描每个对象的较大部分,但是深度为250的窗口是不好的,因为它使每个链都引用很深的旧的对象,这会降低以后所有git操作的速度,从而略微降低磁盘使用率。


历史背景

Linus建议(请参阅下面的完整邮件列表帖子)git gc --aggressive仅当您用他的话说“一个非常糟糕的背包”或“确实非常糟糕的三角洲”时使用,但是“几乎总是,在其他情况下,它实际上是一个非常糟糕的背包”要做的事。” 结果甚至可能使您的存储库比开始时的情况更糟!

他建议在导入“漫长而复杂的历史”之后正确执行此操作的命令是

git repack -a -d -f --depth=250 --window=250

但这是假设您已经从存储库历史记录中删除了不需要的内容,并且已经遵循了清单中的缩小git filter-branch文档中找到的存储库的操作。

git的过滤分支可以用来摆脱文件的一个子集,通常用的一些组合--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

  • 垃圾收集时使用所有未引用的对象git gc --prune=now(如果您git gc还不够陌生,无法支持的参数--prune,请git repack -ad; git prune改用)。


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日星期四,丹尼尔·柏林(Daniel Berlin)写道:

实际上,事实证明,git-gc --aggressive有时不管您是否从SVN存储库转换而来,这种愚蠢的事情都会打包文件。

绝对。git --aggressive大部分都是哑巴 它仅对以下情况才有用:“我知道我有一个非常糟糕的包装,我想放弃我所做的所有糟糕的包装决定。”

为了解释这一点,值得解释(您可能已经意识到了,但无论如何我还是要看一下基础知识)git delta-chains的工作原理以及它们与大多数其他系统的区别。

在其他SCM中,增量链通常是固定的。它可能是“向前”或“向后”,并且在使用存储库时可能会有所发展,但是通常它是对表示为某种单一SCM实体的单个文件的更改链。在CVS中,显然是*,v文件,许多其他系统也做类似的事情。

Git也可以做三角链,但是可以做得“松散”得多。没有固定的实体。相对于git认为是很好的delta候选者(具有各种相当成功的启发式方法)的任何其他随机版本生成Delta,并且绝对没有硬分组规则。

这通常是一件非常好的事情。这是很好的各种观念上的原因(,git的内部从来没有真正甚至需要关心整个修订链-它并没有真正想在所有的增量而言),但它也是伟大的,因为摆脱僵化三角洲规则手段例如,git将两个文件合并在一起根本没有任何问题-根本就没有任何*,v具有某些隐藏含义的“修订文件”。

这也意味着增量的选择是一个更加开放的问题。如果仅将增量链限制为一个文件,那么关于增量的选择确实没有太多选择,但是在git中,这实际上可能是一个完全不同的问题。

这就是真正的名字不好的地方--aggressive。虽然git通常会尝试重用增量信息(因为这是个好主意,并且不会浪费CPU时间重新查找我们之前发现的所有好增量)。想说“让我们从头开始,一头空白,忽略所有以前的增量信息,并尝试生成一组新的增量。”

因此,--aggressive这并不是真正具有侵略性,而是关于浪费CPU时间来重新做我们之前已经做过的决定!

有时候那是一件好事。特别是某些导入工具可能会产生非常糟糕的差值。git fast-import例如,任何使用的东西都可能没有太多的delta布局,因此可能值得一说:“我想从一个干净的开始。”

但是在其他情况下,几乎总是这样,这实际上是一件非常糟糕的事情。这将浪费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

深度是关于增量链有多深(在较长的历史中使它们变长,这是值得的空间开销),而窗口则是关于我们希望每个增量候选对象扫描多大的对象窗口。

在这里,您可能要添加-f标志(即“删除所有旧的增量”,因为您现在实际上正在尝试确保该标志确实找到了合适的人选)。

然后这将需要一整天和一天的时间(“一夜之间做”的事情)。但是最终结果是,该存储库下游的每个人都可以得到更好的数据包,而不必自己花费任何精力。

          Linus

2
您对深度的评论有点令人困惑。刚开始我会抱怨您错了,因为积极进取可以大大加快git存储库的速度。在进行了积极的垃圾收集之后,一个巨大的仓库花了五分钟的时间才将git状态减少到几秒钟。但是后来我意识到您并不是说侵略性的gc放慢了回购速度,而是很大的深度。
user6856

57

我什么时候应该使用gc和重新包装?

正如我在“ Git垃圾回收似乎无法充分发挥作用”中所提到的那样,agit gc --aggressive本身不足或什至不足。
并且,正如我在下面解释的,通常不需要。

最有效的组合是增加git repack,而且git prune

git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage

注意:Git 2.11(2016年第四季度)会将默认gc aggressive深度设置为50

参见Jeff King()的commit 07e7dbf(2016年8月11日(通过合并JUNIOÇ滨野- -提交0952ca8 9月21日2016)peff
gitster

gc:默认进阶深度为50

git gc --aggressive”通常用于将增量链长度限制为250,这对于获得额外的空间节省而言太深了,并且不利于运行时性能。
限制已减少到50。

摘要是:当前的默认值250不会节省太多空间,并且会占用CPU。这不是一个很好的权衡。

--aggressive”标志git-gc可做三件事:

  1. 使用“ -f”丢弃现有的增量并从头开始重新计算
  2. 使用“ --window = 250”来查看增量变化
  3. 使用“ --depth = 250”制作更长的增量链

项目(1)和(2)非常适合“激进”的重新包装。
他们要求重新包装进行更多的计算工作,以期获得更好的包装。您需要在重新打包期间支付费用,其他操作只能看到收益。

项目(3)不清楚。
允许更长的链意味着对增量的限制更少,这意味着有可能找到更好的链并节省一些空间。
但这也意味着访问增量的操作必须遵循较长的链,这会影响其性能。
因此,这是一个折衷方案,尚不清楚该折衷方案是否是一个好的方案。

(请参阅提交学习

您会看到,随着深度的减少,用于常规操作的CPU节省量会提高。
但是我们还可以看到,随着深度的增加,节省的空间并不是很大。在10到50之间节省5-10%可能值得CPU权衡。节省1%从50减少到100,或者再节省0.5%从100减少到250。


说到节省CPU,“ git repack”学会了接受该--threads=<n>选项并将其传递给包装对象。

参见Junio C Hamano()的commit 40bcf31(2017年4月26日(通过合并JUNIOÇ滨野- -提交31fb6f4 5月29日2017)gitster
gitster

重新包装:接受--threads=<n>并将其传递给pack-objects

我们已经这样做了--window=<n>--depth=<n>; 当用户想要强制--threads=1进行可重复的测试而不会受到争用多个线程的影响时,这将有所帮助。


3
我在“ Git垃圾回收似乎无法正常工作”链接中提到Linus线程
VonC 2015年

1
感谢您的最新更新!这里的所有其他答案都是旧的。现在我们可以看到git gc --aggressive已经修复了两次:首先,执行Linus在2007年建议的“更好的打包方法”。然后在Git 2.11中避免了Linus所建议的过大的对象深度,但事实证明这是有害的(减慢了所有将来的Git操作,并且没有节省任何值得一提的空间)。
gw0

git gc,然后是git repack -Ad和git prune增加了我的存储库的大小...为什么?
devops

@devops不确定:您使用的是哪个版本的Git?您可以为此提出一个新问题(具有更多详细信息,例如操作系统,仓库的一般大小,...)
VonC

man git-repack表示-d:`还可以运行git prune-packed删除多余的松散对象文件。`还是这样git prune做?man git-pruneIn most cases, users should run git gc, which calls git prune.,那么以后有什么用git gc?仅使用它会更好还是足够git repack -Ad && git gc
雅各布

14

问题git gc --aggressive在于选项名称和文档具有误导性。

正如Linus自己在这封邮件中解释的那样git gc --aggressive基本上是这样的:

虽然git通常会尝试重用增量信息(因为这是个好主意,并且不会浪费CPU时间重新查找我们之前发现的所有良好的增量),但有时您还是想说“让我们重新开始,空白板,并忽略所有先前的增量信息,并尝试生成一组新的增量”。

通常,无需重新计算git中的增量,因为git可以非常灵活地确定这些增量。仅当您知道自己有非常非常差的增量时才有意义。正如Linus解释的那样,主要利用这些工具的工具就git fast-import属于此类。

大多数时候,git在确定有用的增量方面做得非常好,使用Deltagit gc --aggressive将使您产生可能浪费更长时间的CPU的增量。


莱纳斯结束了他的邮件与结论,即git repack用大--depth--window在大多数时间是更好的选择; 尤其是在导入大型项目并希望确保git找到良好的增量之后。

因此,相当于(git gc --aggressive正确完成)的事情是(隔夜)做类似的事情

git repack -a -d --depth=250 --window=250

深度是关于增量链有多深(在较长的历史记录中使它们更长-这是值得的空间开销),而窗口是关于我们希望每个增量候选对象扫描多大的对象窗口。

在这里,您可能要添加-f标记(即“删除所有旧的增量”),因为您现在实际上正在尝试确保该标记确实找到了合适的候选者。


8

警告。git gc --agressive如果没有备份,请不要使用与远程数据库不同步的存储库运行。

此操作会从头开始重新创建增量,如果正常中断可能会导致数据丢失。

对于我的8GB计算机,积极的gc用1万次小提交就耗尽了1Gb存储库中的内存。当OOM杀手终止git进程时-它给我留下了几乎空的存储库,只有工作树和很少的delta幸存下来。

当然,它不是存储库的唯一副本,所以我只是重新创建了它并从远程拉出(获取在无效的回购上不起作用,而在我尝试这样做的“解决增量”步骤上却死锁了几次),但是如果您的回购是完全没有遥控器的单一开发人员本地存储库-首先备份它。


5

注意:谨防使用git gc --aggressive,正如Git 2.22(Q2 2019)阐明的那样。

请参见提交0044f77提交daecbf2提交7384504提交22d4e3b提交080a448提交54d56f5提交d257e0f提交b6a8d09(2019年4月7日)和fc559fb提交提交cf9cd77提交b11e856由(2019年3月22日)ÆvarArnfjörðBjarmason( avar
(通过合并JUNIOÇ滨野- gitster-提交ac70c53,2019年4月25日)

gc docs:淡化的用处 --aggressive

现有的“ gc --aggressive”文档无法向用户推荐他们定期运行该文档。
我已经亲自与许多用户进行了交谈,这些用户已经将这些文档作为使用此选项的建议,通常,这(通常)是浪费时间

因此,让我们澄清一下它的真正作用,并让用户得出自己的结论。

让我们还澄清一下“影响是持久的”,以解释杰夫·金的简短解释

这意味着git-gc文档现在包括

积极的

--aggressive选项被提供时,git-repack将与被调用-f的标志,这反过来将传递--no-reuse-deltaGIT中包对象
这将丢弃所有现有的增量并重新计算它们,但要花费更多的时间进行重新包装。

这样的影响通常是持久的,例如,当包装和松散的物体合并到另一个包装中时,该包装中的现有增量可能会被重复使用,但是在很多情况下,我们可能会从较新的包装中选择次优的增量打包。

此外,供应--aggressive会捏捏--depth--window传递给的选项git-repack
请参阅下面的gc.aggressiveDepthgc.aggressiveWindow设置。
通过使用更大的窗口尺寸,我们更有可能找到更多的最佳增量。

在给定的存储库上不运行定制的性能基准的情况下,使用此选项可能不值得
这需要花费更多时间,并且由此产生的空间/增量优化可能不值得。对于大多数用户及其存储库,完全不使用此功能是正确的权衡。

并且(提交080a448):

gcdocs:注意--aggressive影响--window--depth

07e7dbfgc:默认深度为50,2016-08-11,Git v2.10.1)以来,我们有点混淆--aggressive了默认使用的深度。

正如在有意义的提交中指出的那样,将“ aggressive”的默认深度设置为更大是错误的,从而以牺牲运行时性能为代价来节省磁盘空间,这通常与“ aggressive gc”的使用相反。想要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.