但是我不确定这样是否足够,是否需要在 "git gc"之前或之后运行 "git repack"。
"git repack" 和 "git gc" 的手册没有提到它们之间的任何连接,而 "git repack" 的手册实际上包含了这样一句话:
相反,下一个 git gc 调用将按照正常的到期规则修剪松散的不可访问对象。
这对我来说意味着 "git gc" 不足以完成所有的日常维护任务,还需要使用 "git repack"。那么,正确的操作是什么?应该使用哪些 git 维护命令?
git gc
确实会运行 repack
。
但不是通常的 repack。有一个新的 git repack --cruft
,生成垃圾包。
在 Git 2.37(2022年第三季度)中,引入了一种将无法访问的对象打包成 "垃圾包" 的机制,而不是将它们弹出为松散形式以便稍后回收。
使用以下命令激活该机制:
git config --global gc.cruftPacks true
ttaylorr
)完成。gitster
--合并于提交a50036d, 2022年6月3日)
文档/技术
:添加cruft-packs.txt签署者:Taylor Blau
创建一个技术文档来解释cruft包。
它包含了问题的简要概述、一些背景信息、实现细节以及几种未在此处考虑的替代方法。
technical/cruft-packs
现在已经包含在其手册页面中:
“Cruft packs”提供了一种替代Git传统机制的功能,即删除不可达对象。本文档介绍了Git修剪机制的概述,以及如何使用“Cruft packs”来完成相同的任务。
为了从仓库中删除不可达对象,Git 提供了 git repack -Ad
命令(参见git repack
)。引用文档:
[quote] [...] 先前包中的不可达对象变成未打包的松散对象,而不是留在旧包中。[...] 松散的不可达对象将根据正常到期规则在下一个 'git gc' 调用时进行修剪。
不可达对象不会立即被删除,因为这样做可能会与正在进行的推送竞争,该推送可能引用即将被删除的对象。相反,这些不可达对象被存储为松散对象,并保持这种状态,直到它们的年龄超过到期时间窗口,此时它们将被 git prune
删除。
Git 必须将这些不可达对象松散地存储,以便跟踪它们的每个对象修改时间。如果这些不可达对象被写入一个大包中,那么刷新该包(因为其中包含的对象已被重写)或创建一个新的不可达对象包将导致该包的修改时间得到更新,并且其中的对象永远不会离开到期时间窗口。
相反,为了跟踪各个对象的修改时间并避免所有杂质对象同时刷新的情况,对象被松散地存储。
当仓库包含许多未离开宽限期的不可达对象时,这可能会导致不良情况。
在 .git/objects
的碎片目录中有大量文件会导致仓库性能下降。
但是,如果不可达对象足够多,则可能会导致 inode 不足,从而降低整个系统的性能。
由于我们永远无法打包这些对象,因此这些仓库通常占用大量磁盘空间,因为我们只能对它们进行 zlib 压缩,但不能将它们存储在 delta 链中。
“Cruft packs”通过在单个包中包含所有松散对象的同时,在单独的文件中包含每个对象的修改时间,消除了存储不可达对象的松散状态的需要。
当生成新的包时,通过 git repack --cruft
或 git pack-objects
的 --cruft
选项来编写“Cruft packs”。请注意,git repack --cruft
是一个经典的全合并包,这意味着结果包中的所有内容都是可达的,而其他所有内容都是不可达的。
一旦编写完成,“--cruft” 选项指示 git repack
生成另一个包,其中只包含上一步未打包的对象(即打包所有不可达对象)。
该进程如下进行:
枚举每个对象,将任何 (a) 不包含在保留
并且:
将新的
builtin/gc.c
:有条件地避免通过松散方式修剪对象签名作者:Taylor Blau
git repack --cruft
模式从git gc
中通过一个新的选择性标志公开。当像git gc --cruft
这样调用时,git gc
将避免将不可访问的对象作为松散对象爆炸,并创建一个杂物包和.mtimes
文件。(链接1) (链接2) (链接3) (链接4) (链接5) (链接6)
git config
现在在其手册页中包含:
gc.cruftPacks
将不可访问的对象存储在一个废弃的包中(参见
git repack
),而不是作为散装对象。默认值为
false
。
git config
现在在其手册页中包含:
git gc
' 时,它将调用 'prune --expire 2.weeks.ago
'(如果使用 gc.cruftPacks
或 --cruft
进行垃圾包处理,则还会调用 'repack --cruft --cruft-expiration 2.weeks.ago
')。可以通过此配置变量覆盖优雅期。值 "now" 可以用于禁用此优雅期并立即修剪不可达对象,或者可以使用 "never" 来禁止修剪。当 'git gc
' 与另一个写入存储库的进程同时运行时,此功能有助于防止损坏;请参见 git gc
的 "NOTES" 部分。git gc
' 的 手册页 中包括:gc.cruftpacks
。nasamuffin
)。ttaylorr
--在提交记录bdd42e3中合并,于2022年11月8日)
config
: 让 feature.experimental 暗示 gc.cruftPacks=true签署者:Emily Shaffer
签署者:Taylor Blau
我们有兴趣探索是否应该将 gc.cruftPacks=true 变为默认值。
为了确定这样做是否安全,让我们鼓励更多用户尝试它。
已经设置 feature.experimental=true
的用户已经自愿尝试新的、可能会破坏配置的更改,因此让我们在这组用户中尝试这个新的默认值。
git config
现在在其手册页面中包括:
gc.cruftPacks=true
可以在垃圾回收期间减少不可达对象占用的磁盘空间,从而防止松散对象爆炸。
示例:
git reset HEAD~2
git -c gc.cruftPacks=true gc
# or
git gc --cruft
find .git/objects/pack -name "*.mtimes" >mtimes
sed -e 's/\.mtimes$/\.pack/g' mtimes >packs
while read pack
do
test_path_is_file "$pack" || return 1
done <packs
git repack
"(man) 学会将无用的对象移至存储库外的 pack 文件。(原文链接)
查看 提交 91badeb, 提交 c12cda4, 提交 eddad36, 提交 4e7b65b (2022年10月24日) 由 Taylor Blau (ttaylorr
) 提交。ttaylorr
-- 完成,日期为2022年11月18日)
builtin/repack.c
:实现--expire-to
以存储修剪后的对象。
签名:Taylor Blau
When pruning objects with
--cruft
,git repack
(man) offers some flexibility when selecting the set of which objects are pruned via the--cruft-expiration
option.This is useful for expiring objects which are older than the grace period, making races where to-be-pruned objects become reachable and then ancestors of freshly pushed objects, leaving the repository in a corrupt state after pruning substantially less likely.
But in practice, such races are impossible to avoid entirely, no matter how long the grace period is.
To prevent this race, it is often advisable to temporarily put a repository into a read-only state.
But in practice, this is not always practical, and so some middle ground would be nice.This patch introduces a new option,
--expire-to
, which teachesgit repack
to write an additional cruft pack containing just the objects which were pruned from the repository.
The caller can specify a directory outside of the current repository as the destination for this second cruft pack.This makes it possible to prune objects from a repository, while still holding onto a supplemental copy of them outside of the original repository.
Having this copy on-disk makes it substantially easier to recover objects when the aforementioned race is encountered.
--expire-to
is implemented in a somewhat convoluted manner, which is to take advantage of the fact that the first timewrite_cruft_pack()
is called, it adds the name of the cruft pack to thenames
string list.
That means the second time we callwrite_cruft_pack()
, objects in the previously-written cruft pack will be excluded.As long as the caller ensures that no objects are expired during the second pass, this is sufficient to generate a cruft pack containing all objects which don't appear in any of the new packs written by
git repack
, including the cruft pack.
In other words, all of the objects which are about to be pruned from the repository.It is important to note that the destination in
--expire-to
does not necessarily need to be a Git repository (though it can be) Notably, the expired packs do not contain all ancestors of expired objects.
So if the source repository contains something like:<unreachable> / C1 --- C2 \ ads/master
where C2 is unreachable, but has a parent (C1) which is reachable, and C2 would be pruned, then the expiry pack will contain only C2, not C1.
git repack
现在在其手册页面中包含:
--expire-to=<dir>
将包含修剪对象(如果有)的垃圾包写入目录
<dir>
。此选项可用于将任何修剪对象的副本保留在单独的目录中作为备份。仅与--cruft -d
一起使用时有用。
示例:
git repack -d \
--cruft --cruft-expiration=5.minutes.ago \
--expire-to="myRepo/objects/pack/pack
在 Git 2.43(2023 年第四季度)中,"git repack
"(man) 学会了 --max-cruft-size
,以防止废弃包无限增长。
由于 git gc
运行 git repack --cruft
,这将帮助 git gc
避免留下大型废弃物。
peff
)提交。ttaylorr
)提交。gitster
--在提交 79861ba中合并,2023年10月18日)
builtin/repack.c
:实现对--max-cruft-size
的支持
签名:Taylor Blau
Cruft packs是一种替代机制,用于存储一组无法访问的对象,其修改时间足够新,以避免被从存储库中删除。当Cruft packs首次引入时(参见b757353(“builtin/pack-objects.c
: --cruft
without expiration”,2022-05-20,Git v2.37.0-rc0 -- merge listed in batch #7)和a7d4938(“builtin/pack-objects.c
: --cruft
with expiration”,2022-05-20,Git v2.37.0-rc0 -- merge listed in batch #7),推荐的工作流程包括:
git repack -d
(man))或生成一系列几何级数的packs(通过git repack --geometric=<d> -d
(man))来实现。--cruft-expiration=<approxidate>
的包来实现。Documentation/technical
: add cruft-packs.txt”,2022-05-20,Git v2.37.0-rc0 -- merge listed in batch #7))。--max-cruft-size
,允许存储库累积垃圾包,直到达到给定的大小,此后可以累积新一代的垃圾包,直到达到最大大小,依此类推。--max-cruft-size
指定的大小,该包就被冻结。--max-cruft-size
选项指定的值的二次函数,而不是与总不可达对象数量的二次函数相同。--max-pack-size
传递给pack-objects
,让它负责保持生成的垃圾包集的正确大小。git config
现在在其man page中包含以下内容:
gc.maxCruftSize
限制重新打包时新垃圾包的大小。当与
--max-cruft-size
一起指定时,命令行选项优先。请参阅git repack
的--max-cruft-size
选项。
git gc
现在在其man page中包含以下内容:
--max-cruft-size=<n>
当将无法访问的对象打包到垃圾包时,限制新垃圾包的大小最多为<n>
字节。覆盖任何通过gc.maxCruftSize
配置指定的值。有关更多信息,请参见git repack
的--max-cruft-size
选项。
git repack
现在在其手册页中包含了这个功能。
--max-cruft-size=<n>
在创建新的包之前,将无用对象重新打包成大小为<n>
字节的包。只要存在足够小于<n>
的无用包,重新打包将会创建一个新的无用包,其中包含来自任何组合无用包以及任何新的无法访问的对象。大于<n>
字节的无用包将不会被修改。当新的无用包大于<n>
字节时,它将被拆分为多个包,所有这些包的大小都保证不超过<n>
字节。仅与--cruft -d
一起使用。
git gc
也会运行git repack
”;) 因此,是的,git gc
就足够了。 - michas