git gc
和git repack -ad; git prune
之间有什么区别吗?
如果是,git gc
将执行哪些额外步骤(反之亦然)?
在空间优化或安全性方面哪一个更好用?
答案 0 :(得分:7)
git gc
和git repack -ad; git prune
之间有什么区别吗?
不同之处在于,默认情况下git gc
对于需要哪些内务处理任务非常保守。例如,它不会运行git repack
,除非存储库中的松散对象数量超过某个阈值(可通过gc.auto
变量配置)。此外,git gc
将执行的任务不仅仅是git repack
和git prune
。
如果是,
git gc
将执行哪些其他步骤(反之亦然)?
根据documentation,git gc
运行:
git-prune
git-reflog
git-repack
git-rerere
更具体地说,通过查看source code of gc.c
(lines 338-343)1,我们可以看到它最多调用 以下命令:
pack-refs --all --prune
reflog expire --all
repack -d -l
prune --expire
worktree prune --expire
rerere gc
根据包(lines 121-126)的数量,它可以使用repack
选项而不是(lines 203-212)运行-A
:
* 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;
请注意line 211-212 of the need_for_gc
function如果存储库中没有足够的松散对象,则gc
根本不会运行。
如果有太多松散的物体,也需要提供清洁服务 存储库中的许多包。如果松散物体的数量超过
gc.auto
配置变量的值,然后全部松散 使用git repack -d -l
将对象组合到一个包中。 将gc.auto
的值设置为0
会禁用自动打包 松散的物体。如果包的数量超过
gc.autoPackLimit
的值,那么 现有的包(标有.keep
文件的包除外)是 使用-A
的{{1}}选项合并为单个包。
如您所见,git repack
努力根据存储库的状态做正确的事情。
在空间优化或安全方面哪一个更好用?
一般来说,运行git gc
会更好,因为它可以做的工作量最少,可以保证存储库的良好状态 - 安全且不会浪费太多资源。
但是,请记住,在某些命令之后可能已经自动触发了垃圾收集,除非通过将git gc --auto
配置变量设置为gc.auto
来禁用此行为。
<强> - 自动强>
使用此选项,0
检查是否需要任何内务处理;如果没有,它退出而不执行任何工作。一些git 执行可能的操作后,命令运行git gc
创造许多松散的物体。
因此,对于大多数存储库而言,您不应该经常显式地运行git gc --auto
,因为它已经为您处理了。
<子>
1.截至2016-08-08的提交a0a1831
。
子>
答案 1 :(得分:1)
git help gc
包含一些提示......
可选配置变量gc.rerereresolved指示您保留先前解决的冲突合并记录的时间长度。
可选配置变量gc.rerereunresolved指示保留未解决的冲突合并记录的时间。
如果你只做git repack -ad; git prune
,我相信这些都没有完成。
答案 2 :(得分:0)
请注意,git prune
由git gc
经营,前者在Git 2.22(2019年第二季度)中得到了发展
“ git prune
”被教成在可能时利用可达性位图。
请参见commit cc80c95的commit c2bf473,commit fde67d6,commit d55a30b,Jeff King (peff
)(2019年2月14日)。
(由Junio C Hamano -- gitster
--在commit f7213a3中合并,2019年3月7日)
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%
测试显示了一个非常理想的情况,因为我们将重新打包,并使用位图很好地覆盖所有引用。
但是这实际上是很现实的:通常通过“gc
”来执行修剪 重新包装后。实施注意事项:更改实际上在
reachable.c
中,因此它也会通过“reflog expire --stale-fix
”改善可达性遍历。
不过,这些操作不是定期执行(正常的“git gc
”不使用--stale-fix
),因此它们实际上不值得测量。降级该调用者的可能性很小,因为从调用者的角度来看,位图的使用是完全透明的。
并且:
请参见commit fe6f2b0的Jeff King (peff
)(2019年4月18日)。
(由Junio C Hamano -- gitster
--在commit d1311be中合并,2019年5月8日)
修剪:延迟执行可达性遍历
“
git prune
”的一般策略是进行完整的可达性查询, 然后针对每个松散的物体,看看是否在步行中找到了它。
但是,如果我们没有任何松散的物体,则无需进行昂贵的步入 第一名。此修补程序将延迟步行,直到我们第一次需要查看其 结果。
请注意,这实际上是更一般的优化的特定情况, 那就是我们只能走很远才能找到下面的物体 考虑(即在找到遍历后停止遍历,然后继续 再次询问下一个对象时,等等。
在某些情况下,这可以使我们不必整日散步。但这实际上与我们的遍历代码有点棘手,并且即使您只有一个无法访问的对象,您仍然需要进行完整的遍历(如果在运行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%
测试显示了一个非常理想的情况,因为我们将重新包装并 我们的位图应该可以很好地覆盖所有参考。
但这实际上是很现实的:通常通过“gc
”来执行修剪 重新包装后。有关实现的一些注意事项:
更改实际上在
reachable.c
中进行,因此它也会通过“reflog expire --stale-fix
”来改善可达性遍历。
不过,这些操作不是定期执行(正常的“git gc
”不使用--stale-fix
),因此它们实际上不值得测量。
降级该调用者的可能性很小,因为从调用者的角度来看,位图的使用是完全透明的。位图情况实际上可以在不创建“
struct object
”的情况下逃脱,而是调用者可以只在位图结果中查找每个对象id。但是,这将在运行时方面有所改善,并使调用者更加复杂。
他们必须分别处理位图和非位图,在git-prune
的情况下,我们还必须调整prune_shallow()
,这取决于我们的SEEN
标志因为我们确实创建了真实的对象结构,所以我们会经历一些扭曲来创建正确的类型。
并非绝对必要(lookup_unknown_object()
就足够了,但是使用正确的类型会提高内存效率,因为我们已经知道它们了。