这是个好问题;文档有点模棱两可,来源也很混乱(force flags的实际应用非常分散)。
一个答案就足够清楚了。 the git push documentation 是这样说的,加了我的粗体字:
--[no-]force-with-lease
--force-with-lease=<refname>
--force-with-lease=<refname>:<expect>
通常,“git push”拒绝更新不是用于覆盖它的本地引用的祖先的远程引用。
如果远程引用的当前值是预期值,则此选项会覆盖此限制。否则“git push”会失败。
想象一下,您必须对已发布的内容进行变基。您必须绕过“必须快进”规则才能将您最初发布的历史记录替换为重新设置的历史记录。如果在你变基时其他人在你的原始历史之上构建,远程分支的尖端可能会随着她的提交而前进,而盲目地使用 --force 推送将失去她的工作。
此选项允许您说您希望您正在更新的历史记录是您重新定位并想要替换的内容。如果远程 ref 仍然指向您指定的提交,您可以确定没有其他人对 ref 做任何事情。这就像在没有显式锁定它的情况下对 ref 进行“租用”,并且只有在“租用”仍然有效时才会更新远程 ref。
--force-with-lease 单独,不指定详细信息,将通过要求其当前值与远程跟踪分支相同来保护将要更新的所有远程引用我们为他们准备了。
--force-with-lease=,如果不指定预期值,将保护 命名的 ref(单独),如果它要被更新,通过要求它的当前值与我们拥有的远程跟踪分支相同。
--force-with-lease=: 将保护 命名的 ref(单独),如果要更新,要求其当前值为与指定值相同(允许与我们为 refname 拥有的远程跟踪分支不同,或者使用这种形式时我们甚至不必有这样的远程跟踪分支)。
请注意,除了 --force-with-lease=: 之外的所有明确指定 ref 预期当前值的形式仍处于试验阶段,随着我们获得此功能的经验,它们的语义可能会发生变化。
"--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 的 compare-and-swap 指令,它原子地测试是否有一些variable2 设置为预测值,如果是,则将其替换为新值,并以某种形式返回在变量中找到的实际值。
如果 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),我们可以使用“加载链接”或“加载锁定”指令,然后使用“存储条件”指令。仅当高速缓存行仍由当前 CPU 独占时,条件存储才会成功。在这种情况下,我们必须重新执行变量的初始锁定加载,我们的循环看起来更像:label: ll r1,(r0); add 1,r1; sc (r0),r1; bne label。这用于 PowerPC 和 MIPS 架构。
2通常,所讨论的变量是一个内存位置,通常具有对齐约束,即使在名义上支持未对齐内存的 CPU 上也是如此。例如,在 Intel Haswell 上,比较和交换 8 字节指令将在 4 字节边界上运行完成,但它实际上并不是原子的。当同事的内存分配器仅提供 4 字节对齐时,我发现了这一点很困难。 :-)