git gc –ggressive vs git repack

我正在寻找方法来减lessgit回购大小。 大多数时候,一个好的search指向了我。 我也读过这不是首选的方法。
为什么? 如果我正在运行gc --aggressive我应该知道gc --aggressive什么?

$ git repack -a -d --depth=250 --window=250build议超过gc --aggressive 。 为什么? 如何repack减less回购大小? 另外,我不太清楚两个标志; – 深度和 – 窗口。

我应该selectgc还是repack ? 我应该什么时候使用gcrepack

现在没有什么区别: git gc --aggressive按照Linus在2007年提出的build议进行操作; 见下文。 从版本2.11(2016年第四季度)开始,git默认为50的深度。大小为250的窗口很好,因为它扫描每个对象的较大部分,但深度为250是不好的,因为它使每个链都指向非常深的旧对象,这会减慢所有将来的git操作,使磁盘使用率稍微降低。


历史背景

Linusbuild议(见下面的完整邮件列表文章)使用git gc --aggressive只有当你有,“一个非常糟糕的包”或“真正可怕的坏三angular洲”,但“几乎总是在其他情况下,这实际上是一件非常糟糕的事情。“结果甚至可能让你的存储库比你开始时更糟!

在他input“一个漫长的历史”之后,他build议这样做的命令是

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

但是这里假设你已经从你的版本库历史logging中删除了不需要的gunk ,并且你已经按照清单缩小了git filter-branch文档中find的版本库。

git-filter-branch可以用来摆脱文件的一个子集,通常使用--index-filter--subdirectory-filter 。 人们期望得到的存储库比原来的要小,但是你需要多一些步骤才能使它变小,因为Git在你告诉它之前尽量不要丢失你的对象。 首先确保:

  • 如果一个blob在其整个生命周期中移动,你真的删除了所有的文件名称。 git log --name-only --follow --all -- filename可以帮助你find重命名。

  • 你真的过滤了所有的参考:使用--tag-name-filter cat -- --all当调用git filter-branch

然后有两种方法可以获得较小的存储库。 更安全的方法是克隆,保持原来的原样。

  • git clone file:///path/to/repo克隆它git clone file:///path/to/repo 。 克隆将不会有被删除的对象。 请参阅git-clone。 (请注意,使用纯path进行克隆只是硬链接一切!)

如果你真的不想克隆它,无论出于什么原因,请检查以下几点(按此顺序)。 这是一个非常具有破坏性的方法,所以做一个备份或者回去克隆它。 你被警告了。

  • 删除由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 reflog expire --expire=now --all

  • 垃圾收集所有未被引用的对象与git gc --prune=now (或者如果你的git gc不够新来支持--prune参数,请使用git repack -ad; git prune --prune git repack -ad; git 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日星期四,丹尼尔柏林写道:

其实,事实certificate, git-gc --aggressive做文件打包的时候会做这个愚蠢的事情,无论你是否从SVN git-gc --aggressive转换而来。

绝对。 git --aggressive大多是愚蠢的。 对于“我知道我有一个非常糟糕的包装,我想扔掉我所做的所有不好的包装决定”的情况下,这真的只是有用的。

为了解释这一点,值得说明的是(你可能已经意识到了这一点,但是让我通读一下基础知识),git三angular链是如何工作的,以及它们与大多数其他系统如此不同。

在其他供应链pipe理中,三angular洲链通常是固定的。 它可能是“向前”或“向后”,并且在您使用存储库时可能会有所变化,但通常它是对单个文件(表示为某种单一的SCM实体)的一系列更改。 在CVS中,它显然是*,v文件,而其他很多系统都是非常相似的。

Git也可以做三angular链,但它更“松散”。它没有固定的实体。 Deltas是针对git认为是一个很好的三angular洲候选人的任何随机的其他版本(具有各种相当成功的启发式)而产生的,并且绝对没有严格的分组规则。

这通常是一件非常好的事情。 这对于各种概念上的原因是有好处的( 比如 ,git内部从来不需要关心整个修订链 – 它根本不用考虑delta),但是它也很好,因为摆脱不灵活的delta规则意味着这个git没有任何问题,把两个文件合并在一起,例如 – 没有任何任意的*,v “版本文件”,它们有一些隐藏的含义。

这也意味着select三angular洲是一个更开放的问题。 如果将delta链限制为只有一个文件,那么对于如何处理delta错误,你确实没有多lessselect,但是在git中,它确实可能是一个完全不同的问题。

而这正是命名的--aggressive虽然git一般会试图重复使用delta信息(因为这是一个好主意,并且不会浪费CPU时间重新find我们之前find的所有好的delta) ,有时你想说“让我们从头开始,用一个空白的石板,忽略所有以前的三angular洲信息,并尝试产生一个新的一套增量”。

所谓的--aggressive并不是真正的侵略性,而是浪费CPU时间来重新做出我们之前做过的决定!

有时候这是件好事。 一些import工具尤其可能会产生非常糟糕的三angular洲。 例如,任何使用git fast-import东西,可能都没有太多的三angular布局,所以可能值得说“我想从一个干净的石板开始”。

但是在其他情况下,几乎总是这样做实际上是一件非常糟糕的事情。 这会浪费CPU时间,特别是如果你之前在delta的时候已经做得很好,最终的结果是不会重复使用你已经find的所有好的 delta,所以你最终会得到一个很好的结果更坏的结果呢!

我会给Junio发一个补丁来删除git gc --aggressive文档。 它可能是有用的,但它通常是有用的,只有当你非常深入地了解它在做什么,并且文档不能帮助你做到这一点。

一般来说,做增量git gc是正确的方法,而且比git gc --aggressive更好。 它将重新使用旧的三angular洲,当那些旧的三angular洲不能被find(首先做增量GC的原因!)它将会创build新的。

另一方面,“长期涉入历史的最初导入”是一个值得花费大量时间寻找真正好的三angular洲的值得肯定的事实。 然后,每一个用户(只要他们不使用git gc --aggressive撤销它!)将获得这个一次性事件的优势。 特别是对于历史悠久的大项目,可能值得做一些额外的工作,告诉delta寻找代码狂放。

所以相当于git gc --aggressivegit gc --aggressive – 但是做得很好 – 就是做一夜之间的事情

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

那里深度的东西只是三angular洲链的深度(使它们延续旧的历史 – 这是值得的空间开销),而窗口的事情是多大的对象窗口,我们希望每个三angular洲候选人扫描。

在这里,你可能想添加-f标志(这是“drop all old deltas”,因为你现在确实试图确定这个标志实际上find了合适的候选者。

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

  Linus 

我应该什么时候使用gc&repack?

正如我在“ Git垃圾收集似乎并没有完全发挥作用 ”中所提到的那样, git gc --aggressive本身是不够的,甚至是不够的。

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

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

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

参见Jeff King( peff )的 commit 07e7dbf (2016年8月11日) 。
(由Junio C gitster合并- gitster -于2016年9月21日的第gitster 提交 )

gc :默认攻击深度为50

git gc --aggressive ”用于限制delta链长度为250,这对于获得额外的空间节省来说太深了,并且对于运行时性能是不利的。
限制已经减less到50。

总结是:当前的默认值250不会节省太多的空间,并且会花费CPU。 这不是一个好的折衷。

git-gc的“ --aggressive ”标志做了三件事情:

  1. 使用“ -f ”扔掉现有的增量,并从头开始重新计算
  2. 使用“–window = 250”看起来更难
  3. 使用“–depth = 250”来制造更长的三angular链

项目(1)和(2)是“积极”重新包装的良好匹配。
他们要求重新包装做更多的计算工作,希望得到更好的包装。 您在重新包装期间支付费用,其他操作只能看到收益。

第(3)项不太清楚。
允许更长的链条意味着更less的三angular洲的限制,这意味着可能find更好的,并节省一些空间。
但是这也意味着进入三angular洲的运作必须跟随更长的链条,这会影响他们的performance。
所以这是一个折衷,并不清楚权衡甚至是一个很好的。

(请参阅提交研究 )

您可以看到,随着我们减less深度,常规操作的CPU节省将会提高。
但是我们也可以看到,随着深度的增加,节省的空间并不大。 在10到50之间节省5-10%可能值得CPU折衷。 节省1%,从50到100,或另外0.5%,从100到250可能不是。


说到CPU保存,“ git repack ”学会接受--threads=<n>选项并将其传递给pack-objects。

见Junio C gitstergitster )的 提交40bcf31 (2017年4月26日) 。
(由Junio C gitster合并- gitster -在2017年5月29日的第gitster 提交 )

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

我们已经这样做了--window=<n>--depth=<n> ; 这将有助于当用户想要强制 – --threads=1进行可重复testing而不受multithreading的影响。

git gc --aggressive的问题是,选项名称和文档是误导性的。

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

虽然git通常会尝试重新使用delta信息(因为这是一个好主意,而且不会浪费CPU时间重新find我们之前find的所有好的delta),有时候你想说“让我们从头开始,空白石板,并忽略所有以前的增量信息,并尝试生成一组新的增量“。

通常不需要在git中重新计算deltas,因为git决定这些deltas非常灵活。 只有当你知道你真的很差的三angular洲时才有意义。 正如Linus解释的那样,主要使用git fast-import属于这个类别。

大多数情况下,git在确定有用的变化量方面做得相当不错,使用git gc --aggressive会给你带来潜在的更糟糕的变化,而浪费大量的CPU时间。


Linus结束他的邮件,得出的结论是git repack --depth了一个大的--depth--window在大部分时间是更好的select; 特别是在你导入了一个大型的项目,并希望确保gitfind好的增量。

所以相当于git gc --aggressivegit gc --aggressive – 但是做得很好 – 就是做一夜之间的事情

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

那里深度的东西只是三angular洲链的深度(使它们延续旧的历史 – 这是值得的空间开销),而窗口的事情是多大的对象窗口,我们希望每个三angular洲候选人扫描。

在这里,你可能想添加-f标志(这是“drop all old deltas”,因为你现在确实试图确定这个标志实际上find了合适的候选者。