我注意到 gitcore.repositoryFormatVersion
中的默认选项默认为 0,但是什么是“存储库格式版本”以及它们有什么功能差异?
2 回答
这是为了未来的兼容性——如果 git 开发人员发现有必要更改存储在磁盘上的方式以启用某些新功能,那么他们可以使升级后的存储库core.repositoryformatversion
具有1
. 然后,知道新格式的新版本 git 将触发代码来处理它,而旧版本的 git 不会优雅地使用"Expected git repo version <= 0, found 1. Please upgrade Git"
.
到目前为止,唯一定义或认可的 repo 格式版本是0
,它表示每个公开版本的 git 都使用的格式。
git 2.7(2015 年 11 月)在新的Documentation/technical/repository-version.txt
.
请参阅Jeff King ( )的提交 067fbd4和提交 00a09d5(2015 年 6 月 23 日) 。(由Junio C Hamano 合并 -- --在提交 fa46579中,2015 年 10 月 26 日)peff
gitster
您现在可以定义“扩展”,并将core.repositoryformatversion
其用作“标记”来表示所述扩展的存在,而不必增加 Git 版本号本身:
如果我们要针对每一个这样的变化增加存储库版本,那么任何理解实现的版本
X
也必须理解X-1
,X-2
等等,即使不兼容可能在系统的正交部分中,否则我们没有理由不能实现一个而没有另一个(或者更重要的是,用户不能选择使用一个功能而不使用另一个功能,仅权衡该特定功能的兼容性)。该补丁记录了现有
repositoryformatversion
策略并引入了一种新格式“1”,它允许存储库指定它必须使用任意扩展集运行。
从文档中提取:
每个 git 存储库都在其文件的
core.repositoryformatversion
键中标有数字版本 。config
此版本指定了对磁盘存储库数据进行操作的规则。请注意,这仅适用于直接访问存储库的磁盘内容。只要服务器进程理解 format ,一个
只理解 format 的旧客户端0
仍然可以使用 format 连接git://
到存储库。1
1
版本
0
这是git初始版本定义的格式,包括但不限于repository目录、repository配置文件、object和ref存储的格式。
版本
1
此格式与 version 相同
0
,但有以下例外:
读取
core.repositoryformatversion
变量时,支持版本 1 的 git 实现还必须读取extensions
配置文件部分中的任何配置键。如果版本 1 存储库指定
extensions.*
了正在运行的 git 尚未实现的任何键,则操作不得继续。
类似地,如果实现不理解任何已知键的值,则操作不得继续。这可以使用,例如:
通知 git 不应仅根据 ref 提示的可达性来修剪对象(例如,因为它具有“克隆 --shared”子级)
除了通常的“refs”和“packed-refs”目录之外,refs 的存储格式
现在这确实是所有发布版本号策略及其semver 策略的原始方法。
因为我们碰到了格式“1”,并且因为格式“1”要求运行的 git 知道提到的任何扩展,所以我们知道旧版本的代码在遇到这些新格式时不会做任何危险的事情。
例如,如果用户选择为 refs 使用数据库存储,他们可以将“extensions.refbackend”配置设置为“db”。
旧版本的 git 将无法理解格式“1”和保释。
理解“1”但不知道“refbackend”或知道“refbackend”但不知道“db”后端的 git 版本将拒绝运行。
当然,这很烦人,但比声称存储库中没有引用或写入其他实现不会读取的位置的替代方法要好得多。请注意,我们在这里只定义格式 1 的规则。
我们自己从来不写格式 1;它是一种工具,旨在供用户和未来的扩展使用,以提供旧实现的安全性。
作为第一个扩展,您将拥有 git 2.7 preciousObjects
:
如果在存储库中使用此扩展,则不应运行可能从对象存储中删除对象的操作。如果您与其他无法看到其引用的存储库共享该存储,这将很有用。
该文档提到:
当配置键
extensions.preciousObjects
设置为 时true
,不得删除存储库中的对象(例如,通过git-prune
或git repack -d
)。
那是:
例如,如果你这样做:
$ git clone -s parent child $ git -C parent config extensions.preciousObjects true $ git -C parent config core.repositoryformatversion 1
在父存储库中运行 git 时,您现在有了额外的安全性。
修剪和重新打包将因错误而退出,git gc
并将跳过这些操作(它将继续打包 refs 并执行其他非对象操作)。
旧版本的 Git 在存储库中运行时,每次操作都会失败。
preciousObjects
请注意,我们在执行“”时默认不设置扩展名clone -s
,因为这样做会破坏向后兼容性。这是用户应该明确做出的决定。
请注意,此core.repositoryformatversion
业务是旧的。真的老了。提交 ab9cb76,2005 年 11 月,Git 0.99.9l。
最初是为 db 版本完成的:
这使
init-db
存储库版本感知。它检查现有配置文件是否表明正在重新初始化的存储库版本错误,并在造成进一步伤害之前中止。
Git 2.22(2019 年第二季度)将避免
repository_format
结构周围的泄漏。
请参阅提交 e8805af(2019 年 2 月 28 日)和提交 1301997(2019 年 1 月 22 日)由Martin Ågren (``)。
(由Junio C Hamano 合并gitster
——在提交 6b5688b中,2019 年 3 月 20 日)
setup
:修复内存泄漏struct repository_format
在我们设置 a 之后
struct repository_format
,它拥有各种分配的内存。然后我们要么使用这些成员,因为我们决定要使用“候选”存储库格式,要么我们丢弃候选/暂存空间。
在第一种情况下,我们将内存的所有权转移给几个全局变量。在后一种情况下,我们只是默默地删除结构并最终泄漏内存。引入一个初始化宏
REPOSITORY_FORMAT_INIT
和一个函数clear_repository_format()
,用于read_repository_format()
. 为了拥有清晰而简单的内存所有权,让所有用户struct repository_format
复制他们从中获取的字符串,而不是窃取指针。
clear_...()
在开始时调用read_...()
而不是仅仅将结构清零,因为我们有时会多次输入函数。
因此,在调用之前初始化结构很重要read_...()
,所以要记录下来。
这也很重要,因为我们甚至可能不会在调用read_...()
之前调用clear_...()
,例如,看到builtin/init-db.c
。教导
read_...()
在错误时清除结构,以便将其重置为安全状态,并记录下来。(在中,即使是 -1,我们也会setup_git_directory_gently()
查看,我们实际上不应该按照 API 执行此操作。在此提交之后,没关系。)repo_fmt.hash_algo
repo_fmt.version
使用 Git 2.28(2020 年第三季度),运行时本身可以自动升级存储库格式版本,例如在非浅层提取上。
参见Xin Li ( ) 的commit 14c7fa2、commit 98564d8、commit 01bbbbd、commit 16af5f1(2020 年 6 月 5 日)。(由Junio C Hamano 合并 -- --在提交 1033b98中,2020 年 6 月 29 日)livid
gitster
fetch
:允许在初始克隆后添加过滤器签字人:李鑫
追溯添加过滤器对于现有的浅克隆很有用,因为它们允许用户查看早期的更改历史记录,而无需在常规
--unshallow
提取中下载所有 git 对象。如果没有此补丁,用户可以通过编辑存储库配置来将远程克隆转换为承诺者,例如:
git config core.repositoryFormatVersion 1 git config extensions.partialClone origin git fetch --unshallow --filter=blob:none origin
由于完成这项工作的困难部分已经到位,并且此类编辑可能容易出错,因此请教 Git 自动执行所需的配置更改。
请注意,此更改不会修改现有的 Git 行为,即
extensions.partialClone
无需更改即可识别设置repositoryFormatVersion
。
警告:在 2.28-rc0 中,我们更正了一个错误,即即使在版本 0 的存储库中,某些存储库扩展也会被错误地接受(extensions.*
命名空间中的这些配置变量应该在版本号为 1 或更高版本的存储库中具有特殊含义),但这有点太大的变化。
请参阅Jonathan Nieder ( ) 的提交 62f2eca和提交 1166419(2020 年 7 月 15 日)。(由Junio C Hamano 合并 -- --在d13b7f2 提交中,2020 年 7 月 16 日)artagnon
gitster
Revert "check_repository_format_gently()
:拒绝旧存储库的扩展”报告人:Johannes Schindelin
签字人:Jonathan Nieder
这将恢复提交 14c7fa269e42df4133edd9ae7763b678ed6594cd。
该
core.repositoryFormatVersion
字段是在ab9cb76f661(“存储库格式版本检查”,2005-11-25,Git v0.99.9l -- merge)中引入的,由于 Martin Atukunda 的一些受欢迎的分析,提供了受欢迎的前向兼容性。语义很简单:
core.repositoryFormatVersion
设置为 0 的存储库应该可以被所有活跃使用的 Git 实现所理解;并且 Git 实现应该尽早出错,而不是尝试对具有更高core.repositoryFormatVersion
值的 Git 存储库采取行动,这些值代表他们不理解的新格式。直到00a09d57eb8才需要定义新的存储库格式(引入
core.repositoryformatversion
2015-06-23 的“扩展”形式)。这为 Git 存储库提供了更细粒度的扩展机制。
在
core.repositoryFormatVersion
设置为 1 的存储库中,Git 实现可以对extensions.*
修改存储库解释方式的“”设置进行操作。在存储库格式版本 1 中,无法识别的扩展设置会导致 Git 出错。
如果用户设置了扩展设置但忘记将存储库格式版本增加到 1,会发生什么情况?
在这种情况下,扩展设置仍然可以识别;更糟糕的是,无法识别的扩展设置不会导致 Git 出错。因此,将存储库格式版本 0 与扩展设置相结合在某种意义上会产生两全其美的结果。
为了改善这种情况,从14c7fa269e4
(check_repository_format_gently()
: 拒绝旧存储库的扩展,2020-06-05) Git 改为忽略 v0 模式下的扩展。通过这种方式,v0 存储库获取历史(2015 年之前)行为并保持与不了解 v1 格式的 Git 实现的兼容性。不幸的是,用户一直在使用这种配置,这种行为变化让很多人感到惊讶:
git config --worktree
遵循其建议启用(未增加存储库格式版本)的“”用户extensions.worktreeConfig
会发现他们的工作树配置不再生效- 已在现有存储库中设置的工具(例如copybara
extensions.partialClone
)(未同时增加存储库格式版本)会发现该设置不再生效如果我们及时回到 2015 年, 14c7fa269e4中引入的行为可能是一个很好的行为,但我们为时已晚。
出于某种原因,我认为这是最初实施的,并且已经倒退了。
抱歉,在开发14c7fa269e4时没有做我的研究。
让我们回到自 2015 年以来的行为:始终根据
extensions.*
设置进行操作,无论存储库格式版本如何。当我们在这里时,包括一些测试来描述对“升级存储库版本”代码路径的影响。