git gc
和git repack -ad; git prune
吗?如果有的话,git gc
(或相反)会执行哪些额外步骤?在空间优化或安全方面,哪一个更好使用?git gc
对需要进行的维护任务非常保守。例如,除非存储库中的松散对象数量超过某个阈值(可通过 gc.auto
变量进行配置),否则它不会运行 git repack
。此外,git gc
会运行比 git repack
和 git prune
更多的任务。git gc
运行以下操作:
git-prune
git-reflog
git-repack
git-rerere
具体来说,通过查看gc.c
的源代码(第338-343行)1,我们可以看到它最多调用以下命令:
pack-refs --all --prune
reflog expire --all
repack -d -l
prune --expire
worktree prune --expire
rerere gc
-A
选项运行repack
,而非(203-212行)。
* If there are too many loose objects, but not too many
* packs, we run "repack -d -l". If there are too many packs,
* we run "repack -A -d -l". Otherwise we tell the caller
* there is no need.
if (too_many_packs())
add_repack_all_option();
else if (!too_many_loose_objects())
return 0;
请注意 need_for_gc
函数中211-212行,如果仓库中没有足够的松散对象,则根本不会运行gc
。
这在文档中进一步说明:
如果仓库中存在太多的松散对象或包,则需要进行清理。如果松散对象的数量超过“gc.auto”配置变量的值,则使用“git repack -d -l”将所有松散对象合并为单个包。将“gc.auto”的值设置为“0”将禁用松散对象的自动打包。如果包的数量超过“gc.autoPackLimit”的值,则使用“git repack”的“-A”选项将现有包(除了那些带有“.keep”文件标记的包)合并为单个包。正如您所看到的,“git gc”会根据仓库的状态尽力做正确的事情。
一般来说,运行“git gc --auto”更好,因为它将尽可能少地执行必要的工作,以使仓库保持良好状态-安全且不浪费太多资源。
然而,请注意,垃圾回收可能已经在某些命令之后自动触发,除非将gc.auto
配置变量设置为0
禁用此行为。
来自文档:
--auto
使用此选项,git gc
会检查是否需要进行任何清理工作; 如果不需要,则不执行任何操作。一些git命令在执行可能创建许多松散对象的操作后运行git gc --auto
。
因此,对于大多数存储库,您通常不需要显式运行git gc
,因为它已经为您处理了。
截至2016年08月08日提交的a0a1831
。
git help gc
包含一些提示...
可选的配置变量
gc.rerereresolved
指示先前解决的有冲突合并记录保留的时间。可选的配置变量
gc.rerereunresolved
指示未解决的有冲突合并记录保留的时间。
我认为如果只执行 git repack -ad; git prune
,那么这些操作不会被执行。
git gc
运行时会运行 git prune
,后者已经在 Git 2.22(2019 年第二季度)中得到改进。git prune
" 已经学会了在可能的情况下利用可达性位图。
查看 commit cc80c95, commit c2bf473, commit fde67d6, commit d55a30b (2019年2月14日) 由 Jeff King (peff
) 提交。
(由 Junio C Hamano -- gitster
-- 合并于 commit f7213a3, 2019年3月7日)
修剪
: 使用位图进行可达性遍历修剪通常必须遍历整个提交图,以查看哪些对象是可达的。
这正是可达性位图要解决的问题,因此让我们使用它们(如果它们可用的话)。
在这里查看可达性位图。
Here are timings on git.git:
Test HEAD^ HEAD ------------------------------------------------------------------------ 5304.6: prune with bitmaps 3.65(3.56+0.09) 1.01(0.92+0.08) -72.3%
And on linux.git:
Test HEAD^ HEAD -------------------------------------------------------------------------- 5304.6: prune with bitmaps 35.05(34.79+0.23) 3.00(2.78+0.21) -91.4%
The tests show a pretty optimal case, as we'll have just repacked and should have pretty good coverage of all refs with our bitmaps.
But that's actually pretty realistic: normally prune is run via "gc
" right after repacking.Notes on the implementation: the change is actually in
reachable.c
, so it would improve reachability traversals by "reflog expire --stale-fix
", as well.
Those aren't performed regularly, though (a normal "git gc
" doesn't use--stale-fix
), so they're not really worth measuring. There's a low chance of regressing that caller, since the use of bitmaps is totally transparent from the caller's perspective.
并且:
参见 提交 fe6f2b0(2019年4月18日) by Jeff King (peff
)。
(由Junio C Hamano -- gitster
--合并在提交 d1311be,2019年5月8日)
修剪:惰性执行可达性遍历
The general strategy of "
git prune
" is to do a full reachability walk, then for each loose object see if we found it in our walk.
But if we don't have any loose objects, we don't need to do the expensive walk in the first place.This patch postpones that walk until the first time we need to see its results.
Note that this is really a specific case of a more general optimization, which is that we could traverse only far enough to find the object under consideration (i.e., stop the traversal when we find it, then pick up again when asked about the next object, etc).
That could save us in some instances from having to do a full walk. But it's actually a bit tricky to do with our traversal code, and you'd need to do a full walk anyway if you have even a single unreachable object (which you generally do, if any objects are actually left after running git-repack).So in practice this lazy-load of the full walk catches one easy but common case (i.e., you've just repacked via
git-gc
, and there's nothing unreachable).The perf script is fairly contrived, but it does show off the improvement:
Test HEAD^ HEAD ------------------------------------------------------------------------- 5304.4: prune with no objects 3.66(3.60+0.05) 0.00(0.00+0.00) -100.0%
and would let us know if we accidentally regress this optimization.
Note also that we need to take special care with
prune_shallow()
, which relies on us having performed the traversal.
So this optimization can only kick in for a non-shallow repository. Since this is easy to get wrong and is not covered by existing tests, let's add an extra test tot5304
that covers this case explicitly.
prune
: 使用位图进行可达性遍历Pruning generally has to traverse the whole commit graph in order to see which objects are reachable.
This is the exact problem that reachability bitmaps were meant to solve, so let's use them (if they're available, of course).Here are timings on
git.git
:Test HEAD^ HEAD ------------------------------------------------------------------------ 5304.6: prune with bitmaps 3.65(3.56+0.09) 1.01(0.92+0.08) -72.3%
而在 linux.git
上:
自 Git 2.22(2019 年)开始使用可达性位图时,“不要丢失最近创建的对象和从它们可达的对象”安全机制被错误地禁用以保护我们免受竞争条件的影响,这一问题已在 Git 2.32(2021 年第二季度发布)中得到修正。
查看提交 2ba582b,提交 1e951c6(2021年4月28日)由Jeff King (peff
)完成。
(由Junio C Hamano -- gitster
--在提交 6e08cbd中合并,2021年5月7日)
prune
:使用位图保存最近可达对象报告者:David Emett
签名者:Jeff King
mark_reachable_objects()
,它不仅遍历可达对象,还将任何最近的对象视为可达性提示;有关详细信息,请参见d3038d2(“prune
: keep objects reachable from recent objects”,2014-10-15,Git v2.2.0-rc0 -- merge)。prune
: use bitmaps for reachability traversal”,2019-02-13,Git v2.22.0-rc0 -- merge列在batch #2中)。"rev_info"
作为位图和常规遍历,但这应该可以正常工作(位图代码以通常的方式清除挂起数组,就像常规遍历一样)。