git gc
和git repack -ad; git prune
之间有什么区别吗
如果是,git gc
将执行哪些附加步骤(反之亦然)
在空间优化和安全方面,哪个更好?
git gc
和git repack -ad; git prune
之间有什么区别吗?
不同之处在于,默认情况下,git gc
对需要哪些内务管理任务非常保守。例如,除非存储库中松散对象的数量超过某个阈值(可通过gc.auto
变量进行配置),否则它不会运行git repack
。此外,git gc
将运行比git repack
和git prune
更多的任务。
如果是,
git gc
将执行哪些附加步骤(反之亦然)?
根据文档,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
根据包的数量(第121-126行),它可以运行带有-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
配置变量的值,然后全部松动使用CCD_ 30将对象组合成单个包。将gc.auto
的值设置为0
将禁用松散物体。如果包数超过
gc.autoPackLimit
的值,则现有包(用.keep
文件标记的包除外)通过使用CCD_ 36的CCD_。
正如您所看到的,git gc
努力根据存储库的状态做正确的事情。
在空间优化和安全方面,哪个更好?
通常,运行git gc --auto
更好,因为它将尽可能少地完成保持存储库良好状态所需的工作——安全且不浪费太多资源。
但是,请记住,垃圾收集可能已经在某些命令之后自动触发,除非通过将gc.auto
配置变量设置为0
来禁用此行为。
来自文件:
--auto
使用此选项,git gc
检查是否需要任何内务管理;否则,它将退出而不执行任何工作。一些git命令在执行以下操作后运行git gc --auto
创建许多松散的对象。
因此,对于大多数存储库,您不需要经常显式运行git gc
,因为它已经由您负责了。
1.截至2016年8月8日提交a0a1831
。
git help gc
包含一些提示。。。
可选配置变量gc.rererresolved指示您之前解决的冲突合并记录的保存时间。
可选配置变量gc.reereresolutiond指示您尚未解决的冲突合并记录的保存时间。
我相信,如果你只做git repack -ad; git prune
,这些就不会完成。
注意,git prune
由git gc
运行,前者已与Git 2.22(2019年第二季度)一起进化
"CCD_ 49";已经被教导在可能的情况下利用可达性位图。
请参阅Jeff King(peff
)的提交cc80c95、提交c2bf473、提交fde67d6、提交d55a30b(2019年2月14日)
(由Junio C Hamano合并——gitster
——于2019年3月7日提交f7213a3)
prune
:使用位图进行可达性遍历
修剪通常必须遍历整个提交图,以便查看哪些对象是可访问的
这正是可达性位图想要解决的问题,所以让我们使用它们(当然,如果它们可用的话)。
请参阅此处的可达性位图。
以下是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:上
Test HEAD^ HEAD -------------------------------------------------------------------------- 5304.6: prune with bitmaps 35.05(34.79+0.23) 3.00(2.78+0.21) -91.4%
测试显示了一个非常优化的情况,因为我们刚刚重新打包,应该可以很好地覆盖位图中的所有引用
但是这实际上是非常现实的:通常情况下,prune是通过"CCD_ 53";正确的重新包装后实现注意事项:更改实际上是在
reachable.c
中,因此它将通过";CCD_ 55";,同样
不过,这些并不是定期执行的(正常的"git gc
"不使用--stale-fix
),所以它们并不值得测量。回归调用方的可能性很低,因为从调用方的角度来看,位图的使用是完全透明的。
和:
参见Jeff King提交的fe6f2b0(2019年4月18日)(peff
)
(由Junio C Hamano合并——gitster
——于2019年5月8日提交d1311be)
修剪:延迟执行可达性遍历
;CCD_ 60";就是进行完全可达性步行,然后,对于每一个松散的物体,看看我们是否在散步中找到了它
但如果我们没有任何松散的物品,我们就不需要做昂贵的步行第一名。这个补丁将步行推迟到我们第一次需要看到它后果
注意,这实际上是更一般的优化的特定情况,也就是说,我们只能穿越足够远的距离来找到下面的物体考虑(即,当我们找到遍历时停止它,然后继续再次被问及下一个对象等)
在某些情况下,这可以使我们不必走完全程。但实际上,使用我们的遍历代码有点棘手,如果你有一个无法访问的对象,你无论如何都需要进行一次完整的遍历(如果运行git-repack后确实留下了任何对象,你通常会这样做)。因此,在实践中,这种懒散的全步行负载抓住了一个简单但常见的情况(即,您刚刚通过
git-gc
重新打包,没有什么是不可访问的)。perf脚本相当做作,但它确实展示了改进:
Test HEAD^ HEAD ------------------------------------------------------------------------- 5304.4: prune with no objects 3.66(3.60+0.05) 0.00(0.00+0.00) -100.0%
如果我们不小心回归了这个优化,就会让我们知道。
还要注意,我们需要特别注意
prune_shallow()
,它依赖于我们已经执行了遍历
因此,此优化只能用于非浅层存储库。由于这很容易出错,并且不在现有测试的范围内,所以让我们添加一个额外的测试t5304
明确涵盖了这种情况。
prune
:使用位图进行可达性遍历
修剪通常必须遍历整个提交图,以便查看哪些对象是可访问的
这正是可达性位图想要解决的问题,所以让我们使用它们(当然,如果它们可用的话)。以下是
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
:
Test HEAD^ HEAD -------------------------------------------------------------------------- 5304.6: prune with bitmaps 35.05(34.79+0.23) 3.00(2.78+0.21) -91.4%
测试显示了一个非常优化的情况,因为我们刚刚重新打包并位图应该能很好地覆盖所有引用
但这实际上是非常现实的:通常情况下,prune是通过"CCD_ 67";正确的重新包装后。关于实现的几个注意事项:
变化实际上是在
reachable.c
中,因此它将通过";CCD_ 69";,同样
不过,这些并不是定期执行的(正常的"git gc
"不使用--stale-fix
),所以它们并不值得测量
回归调用方的可能性很低,因为位图的使用从调用方的角度来看是完全透明的。位图情况实际上可以在不创建";CCD_ 72";,相反,调用方可以在位图结果中查找每个对象id。然而,这在运行时将是一个微不足道的改进,并且会使调用程序变得更加复杂
他们必须分别处理位图和非位图情况,在git-prune
的情况下,我们还必须调整prune_shallow()
,它依赖于我们的SEEN
标志。因为我们确实创建了真实的对象结构,所以我们通过一些扭曲来创建正确类型的结构
这不是严格必要的(lookup_unknown_object()
就足够了),但使用正确的类型会更节省内存,因为我们已经知道它们了。
当可达性位图生效时(自Git 2.222019以来);不要丢失最近创建的对象和从它们可到达的对象";保护我们免受比赛影响的安全被错误地禁用:Git 2.32(2021年第二季度)已经纠正了这一点。
参见Jeff King(peff
)的提交2ba582b,提交1e951c6(2021年4月28日)
(由Junio C Hamano合并——gitster
——提交6e08cbd,2021年5月7日)
prune
:保存从具有位图的最近对象可访问的内容报告人:David Emett
签字人:Jeff King
我们将修剪到期传递给
mark_reachable_objects()
,它不仅会遍历可到达的对象,还会将任何最近的对象视为可达性提示;有关详细信息,请参见d3038d2("prune
:保持对象可从最近的对象访问",2014-10-15,Git v2.2.0-rc0-merge)。然而,这与fde67d6中添加的位图代码路径交互不良("
prune
:使用位图进行可达性遍历",2019-02-13,Git v2.22.0-rc0-merge在第2批中列出)
如果我们命中位图优化路径,我们会立即返回以避免常规遍历,意外跳过"也穿过最近的";密码相反,我们应该对位图与常规遍历进行if-else,然后使用"if";最近的";无论在哪种情况下,遍历
这会将"rev_info"
重新用于位图,然后进行常规遍历,但这应该可以正常工作(位图代码以常规方式清除挂起的数组,就像常规遍历一样)。