如今,两者之间没有任何区别: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会尽力不丢失对象,除非您告知它。首先确保:
然后有两种方法来获得较小的存储库。一种比较安全的方法是克隆,这样可以使原始文件保持原样。
- 用克隆它
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