Git --force-with-lease与+在分支(refspec)中的使用

4
在当前的 Git 中,git push --force-with-lease origin +somebranchgit push --force-with-lease origin somebranchgit push origin +somebranch(没有加号)之间是否存在实质性差异?这三个命令似乎都是做同样的事情。
我试图查找相关文档。我看了一下文档中的 refspec,但我不知道它们是否有区别,如果有的话,在像git pull --rebase origin master这样的情况下,应该默认选择哪个。
2个回答

5
这是一个好问题;文档有点模糊,源代码也很混乱(实际的force标志应用广泛分散)。其中一个答案已经足够清楚了。以下是git push文档所说的,我加粗了关键部分:

--[no-]force-with-lease
--force-with-lease=<refname>
--force-with-lease=<refname>:<expect>

通常情况下,“git push”会拒绝更新不是用本地引用覆盖的远程引用的祖先的引用。

如果当前的远程引用的值是预期的值,则此选项将覆盖此限制。否则,“git push”会失败。

假设您必须重新发布已发布的内容。为了使用重新基础化的历史记录替换最初发布的历史记录,您必须越过“必须快进”的规则。如果在您重新基础化时有其他人建立在您的原始历史记录之上,则远程分支的末端可能随她的提交而推进,并且盲目使用--force进行推送将失去她的工作。

此选项允许您说出您正在更新的历史记录是您重新基础化并希望替换的历史记录。如果远程引用仍然指向您指定的提交,则可以确定没有其他人对引用进行任何操作。这就像在不显式锁定它的情况下“租用”引用,并且只有在“租赁”有效时才会更新远程引用。

--force-with-lease单独使用,而不指定详细信息,将通过要求其当前值与我们拥有的远程跟踪分支相同来保护所有要更新的远程引用

--force-with-lease=<refname>,而不指定预期值,将通过要求其当前值与我们拥有的远程跟踪分支相同来保护命名引用(仅限),如果它将被更新。

--force-with-lease=<refname>:<expect>,如果它将被更新,则将通过要求其当前值与指定值相同(允许与我们对refname拥有的远程跟踪分支不同,或者在使用此形式时甚至不必拥有这样的远程跟踪分支)来保护命名引用(仅限)

请注意,除了显式指定引用的当前预期值的--force-with-lease=<refname>:<expect>之外的所有形式仍处于实验阶段,它们的语义可能随着我们使用此功能而发生变化。

"--no-force-with-lease"将取消命令行上先前的所有--force-with-lease

因此,如果传输支持比较并交换选项1,而您已经写了--force-with-lease而不是--no-force-with-lease,则所有更新(强制或非强制)都使用租赁模式。
但是,--no-force-with-lease会清除已存储的push_cas_option结构,并且我不确定这些存储的值何时应用于每个refspec。
使用明确的<refname>也可以明确保护一个引用,无论是否为其设置任何强制标志。
对于底层传输缺乏比较和交换支持的情况,发生了什么也不太清楚。 幸运的是,GitHub的Git服务器支持它,如果您特别指的是GitHub,则这只是一个干扰。
1在Git源代码中,内部使用宏CAS_OPT_NAME:force-with-lease的功能受现代CPU的比较和交换指令的启发,该指令原子地测试某些变量2是否设置为预测值,如果是,则用新值替换它,并以某种形式返回实际找到的变量的值。
如果CPU体系结构使用条件码,这可能会设置条件码,但在大多数情况下,如果合适,您将获得旧值,以便可以重试比较和交换。例如,要实现原子加一,可以使用以下循环:load r1,(r0); label: add r1,1,r2; cas r1,r2,(r0); bne label; 要实现位2的原子测试和设置: load r1,(r0); label: or r1,4,r2; cas r1,r2,(r0); bne label ; 等等。例如在Intel Pentium和SPARC系统上使用此方法。
某些CPU使用缓存机制。 如果最接近CPU的缓存具有共享与独占模式(例如MESI或MOESI),则可以使用"load linked"或"load locked"指令,后跟"store conditional"指令。 仅当缓存行仍然被当前CPU以独占方式拥有时,条件存储才成功。在这种情况下,我们必须重新执行变量的初始锁定加载,并且我们的循环看起来更像:label: ll r1,(r0); add 1,r1; sc (r0),r1; bne label。例如,在PowerPC和MIPS架构上使用此方法。

2通常,所涉及的变量是一个内存位置,即使在名义上支持不对齐内存的CPU上也有对齐约束。例如,在英特尔Haswell上,一个比较和交换8字节指令将在4字节边界上运行完成,但实际上它并不是原子性的。当我的同事的内存分配器只提供4字节对齐时,我通过艰难的方式发现了这一点。:-)


哥们,这真的是深入研究问题了。不仅仅是问题本身,还有一些潜在的问题,而且还要为搜索引擎提供一些内容。 - Veksi

4
当我想通过“git pull --rebase origin master”拉取工作分支时,默认情况下应该选择哪个?
我在2013年Git 1.8.5和2016年3月Git 2.8中介绍了“force-with-lease”。
我会说……两者都不需要。pull --rebase是为了避免强制推送(无论是否使用lease)而进行的。
我只需设置(自Git 2.6以来
git config pull.rebase true
git config rebase.autoStash true

这使我能够进行一些简单的git pull,然后是简单的git push(不涉及强制推送)


好的,我忘了解决工作流问题。使用 --force-with-lease 可以防止强制推送后故意删除的提交被“复活”,但如果你的合作者一开始就没有同意这样的删除,那么它就不是必需的。因此,只有在做一些不寻常的事情时才需要这种高级选项。 - torek
额外信息的投票。对我来说,实际上有一个分心的地方,就是我不总是藏起来,而是提交,然后将其与先前的提交压缩在一起(假设我正在处理“相同的逻辑集”),这导致了第一个问题。我没有想那么多关于自动隐藏,但也许我应该。 - Veksi
@Veksi 是的,我甚至不再考虑隐藏或变基:如果需要,git会为我完成这些操作。 - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接