Git 是否以原子方式拉取写入文件



我在文档中找不到任何内容。 如果我执行 git 拉取,我是否可以保证合并产生的底层文件是以原子方式写入的?

关于我想要实现的目标的更多背景: 我有一些脚本会定期执行 git 拉取,我需要知道我是否可以依赖文件的状态在拉取期间有效。

我们基本上使用 git 作为部署工具。我们从不通过设计合并冲突。在远程端,作业每 x 秒不断拉取一次,其他作业读取文件。可能发生的情况是,我们在 git 拉取文件时打开文件,而文件的内容不是我们所期望的。 除非 git 足够聪明,可以在底层操作系统上使用一些原子交换(在这种情况下为 RedHat)

简短的回答是否定的

值得考虑的是,git pull根本不是关于文件,而是关于提交。 文件只是一个副作用。:-) 拉取操作只是git fetch(获取提交),后跟第二个 Git 命令,通常git merge. 合并步骤合并提交。 如果操作不是快进而不是合并,这也会产生合并文件的副作用;然后,当合并或快进完成后,Git 会对生成的提交进行git checkout

所以这实际上归结为:git checkout操作系统级别的原子吗?答案是一个非常响亮的否定:它在任何方面都不是原子的。 在工作树中写入的各个文件使用操作系统级别的write调用一次写入一个,这些调用不是原子的。 需要创建或删除的文件一次完成一个。 Git确实使用索引,索引索引(即保持选项卡)工作树,以最大限度地减少删除、创建或就地重写的文件数量。 Git 还会针对其他 Git 操作进行锁定,并使 Git 级别的事务看起来是原子的——但是任何在 Git 之外工作的东西,如果不与Git的锁定系统合作,将能够在更改发生时看到它们。

git pullgit checkout部分,参见托雷克的回答。

git pullgit fetch部分,有一个 --atomic标志,Git 2.36(2022 年第 2 季度)澄清了它。

"git fetch

"(man) 可以进行两次单独的获取,但来自它们的 ref 更新是在"--atomic"下的两个单独的 ref 事务中,这已在 Git 2.36(2022 年第二季度)中得到纠正。

请参阅提交 583bc41、提交 b3a8046、提交 4f2ba2d、提交 62091b4、提交 2983cec、提交 efbade0、提交 2a0cafd (2022 年 2 月 17 日),作者:Patrick Steinhardt (pks-t).
(由 Junio C Hamano --gitster-- 合并于 提交 851d2f0,2022 年 3 月 13 日)

fetch:提高获取的测试覆盖率

签名者:帕特里克·斯坦哈特

git fetch--atomic标志一起使用时,期望要么更新所有引用,要么在获取失败的情况下不更新任何引用。

虽然我们已经对此进行了测试,但我们没有任何测试在修剪已删除的引用或回填标签时行使原子性.
测试覆盖率的差距掩盖了我们确实没有正确处理这两种情况的原子性。

添加覆盖这些测试差距的测试用例,以演示损坏的行为。

>警告:

在 Git 2.36(2022 年第 2 季度)中,恢复"删除 ref 不应单独触发松散和打包的 ref 后端的事务事件",当 ref 自打包以来未被修改时,它会回归行为。

请参阅提交 4315986,提交 347cc1b,提交 c6da34a(2022 年 4 月 13 日),作者:Junio C Hamano (gitster).
(由 Junio C Hamano --gitster-- 合并于 提交 4027e30,2022 年 4 月 14 日)

4027e30c53:合并分支 'jc/revert-ref-transaction-hook-changes'

还原"fetch:增加fetches的测试覆盖率">
Revert "Merge branch 'ps/avoid-nonneed-hook-invocation-with-packed-refs'">

最新更新