从Git 2.42(2023年第三季度)开始,"
git pack-objects
"
(man) 学会了调用一个新的钩子程序,该程序枚举额外的对象,以作为锚定点,以保留杂乱包中本来无法访问的对象。
换句话说,在
git gc
之后,您可以记录您不希望消失的对象。
cat refs/pull/137/head > ./precious-objects
pr137=$(cat refs/pull/137/head)
rm -Rf refs/pull/137
git config gc.recentObjectsHook ./precious-objects
git prune --expire=now
git show -p ${pr137}
查看
提交 4dc16e2,
提交 01e9ca4(2023年6月7日)由
Taylor Blau (ttaylorr
)。
(由Junio C Hamano -- gitster
--在提交 58ecb2e中合并,2023年6月23日)
gc
:介绍
gc.recentObjectsHook
帮助者:Jeff King
签署者:Taylor Blau
这个补丁引入了一个新的多值配置选项
gc.recentObjectsHook
,作为一种标记某些对象为最近的方式(因此不受垃圾回收的影响),而不考虑它们的年龄。
在对包含无法访问的对象的存储库执行垃圾回收操作时,Git根据对象的最近程度来决定如何处理这些对象。一般来说,无法访问但是最近的对象会保留在存储库中,而较旧的对象则会被丢弃。
然而,我们目前没有方便的方法来保留存储库中的某些宝贵的、无法访问的对象,即使它们已经过时并且将被修剪掉。我们目前的选择包括:
- 将指针引用指向您认为宝贵的任何对象的可达性提示,如果存在许多这样的对象,则可能不可取或不可行。
- 通过reflog跟踪它们,但这可能不可取,因为reflog的生命周期仅限于其跟踪的引用的生命周期(调用者可能希望将这些无法访问的对象保留更长时间)。
- 延长优雅期,这可能会保留调用者希望丢弃的其他对象。
- 手动修改要保留的对象的修改时间。如果这些对象已经是loose状态,这很容易做到(您只需枚举并对每个对象使用
touch -m
命令)。但如果它们是packed状态,您要么会修改该pack中所有对象的修改时间,要么被迫写出一个loose副本,这两种情况都可能不可取。更糟糕的是,如果它们在一个垃圾pack中,那就需要手动修改其
*.mtimes
文件,因为没有公开的接口可以进行此操作。
- 强制调用者自己构建他们想要保留的对象的pack,然后通过添加一个“
.keep
”文件来标记该pack为保留。这种方法有效,但对于调用者来说很麻烦,并且在滚动垃圾pack时拥有额外的pack会很尴尬。
这个补丁通过
gc.recentObjectsHook
配置引入了上述列表中的一个新选项,允许调用者指定一个程序(或一组程序),其输出被视为一组要作为最近对象处理的对象,而不考虑它们的真实年龄。
实现很简单。Git通过
add_unseen_recent_objects_to_traversal()
枚举最近的对象,该函数枚举loose和packed对象,并最终对满足
want_recent_object()
条件的任何对象调用
add_recent_object()
。
这个补丁将最近性条件从简单的“此对象的修改时间是否比截止时间更近?”修改为“[...] 或者,此对象是否被至少一个
gc.recentObjectsHook
提及?”。
根据是否正在生成垃圾pack,这允许调用者执行以下两种操作之一:
- 如果正在生成垃圾pack,则调用者可以通过垃圾pack保留其他对象,即使由于它们的年龄而本应该被修剪掉。
- 如果不生成垃圾pack,则调用者同样可以将其他对象保留为loose状态。
一个潜在的替代方案是引入一种新模式来改
git config
现在在其man page中包含以下内容:
gc.recentObjectsHook
在考虑是否删除对象(无论是在生成垃圾包还是存储不可达对象时)时,使用shell执行指定的命令。
将其输出解释为Git将视为“最近”的对象ID,而不考虑它们的年龄。通过将它们的修改时间视为“现在”,无论这些对象(及其后代)的真实年龄如何,都将保留在输出中提到的对象。
输出必须每行恰好包含一个十六进制对象ID,且不能包含其他内容。无法在存储库中找到的对象将被忽略。支持多个钩子,但所有钩子都必须成功退出,否则操作(无论是生成垃圾包还是解压不可达对象)将停止。