这是一个好问题;文档有点模糊,源代码也很混乱(实际的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字节对齐时,我通过艰难的方式发现了这一点。:-)