`git gc`和`git repack -ad之间有什么区别吗? git prune`?

时间:2016-08-09 10:32:56

标签: git git-gc

git gcgit repack -ad; git prune之间有什么区别吗? 如果是,git gc将执行哪些额外步骤(反之亦然)? 在空间优化或安全性方面哪一个更好用?

3 个答案:

答案 0 :(得分:7)

  

git gcgit repack -ad; git prune之间有什么区别吗?

不同之处在于,默认情况下git gc对于需要哪些内务处理任务非常保守。例如,它不会运行git repack,除非存储库中的松散对象数量超过某个阈值(可通过gc.auto变量配置)。此外,git gc将执行的任务不仅仅是git repackgit prune

  

如果是,git gc将执行哪些其他步骤(反之亦然)?

根据documentationgit 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根本不会运行。

documentation

进一步阐明了这一点
  

如果有太多松散的物体,也需要提供清洁服务   存储库中的许多包。如果松散物体的数量超过   gc.auto配置变量的值,然后全部松散   使用git repack -d -l将对象组合到一个包中。   将gc.auto的值设置为0会禁用自动打包   松散的物体。

     

如果包的数量超过gc.autoPackLimit的值,那么   现有的包(标有.keep文件的包除外)是   使用-A的{​​{1}}选项合并为单个包。

如您所见,git repack努力根据存储库的状态做正确的事情。

  

在空间优化或安全方面哪一个更好用?

一般来说,运行git gc会更好,因为它可以做的工作量最少,可以保证存储库的良好状态 - 安全且不会浪费太多资源。

但是,请记住,在某些命令之后可能已经自动触发了垃圾收集,除非通过将git gc --auto配置变量设置为gc.auto来禁用此行为。

来自documentation

  

<强> - 自动
  使用此选项,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 prunegit gc经营,前者在Git 2.22(2019年第二季度)中得到了发展

git prune”被教成在可能时利用可达性位图。

请参见commit cc80c95commit c2bf473commit fde67d6commit d55a30bJeff King (peff)(2019年2月14日)。
(由Junio C Hamano -- gitster --commit f7213a3中合并,2019年3月7日)

  

prune:使用位图进行可达性遍历

     

修剪通常必须遍历整个提交图,以便   查看可访问的对象。
  这正是可到达性位图要解决的确切问题,所以让我们使用它们(当然,如果有的话)。

请参见reachability bitmap here

  

以下是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 fe6f2b0Jeff 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()就足够了,但是使用正确的类型会提高内存效率,因为我们已经知道它们了。

  •