繁体   English   中英

git push --force-with-lease 与 --force

[英]git push --force-with-lease vs. --force

我试图理解两者之间的区别

git push --force

git push --force-with-lease

我的猜测是,如果远程没有本地分支没有的提交,后者只会推送到远程?

force用您的本地分支覆盖远程分支。

--force-with-lease是一个更安全的选项,如果更多的提交被添加到远程分支(由另一个团队成员或同事或你拥有的东西),它不会覆盖远程分支上的任何工作。 它确保您不会通过强制推送覆盖其他人的工作。

我认为您对命令的总体看法是正确的。 如果远程分支与本地机器上的远程分支具有相同的值 - 您将覆盖 remote。 如果它没有相同的值 - 它表示在您处理代码时其他人对远程分支所做的更改,因此不会覆盖任何代码。 显然,如果远程中有其他提交,则值将不相同。

我只是认为--force-with-lease作为我想确保不覆盖任何队友代码时使用的选项。 我公司的很多团队都使用--force-with-lease作为故障安全的默认选项。 在大多数情况下它是不必要的,但是如果您碰巧覆盖了另一个人为远程贡献的内容,则会为您省去很多麻烦。

我确定您查看了文档,但此处可能包含一些更冗长的解释:

https://git-scm.com/docs/git-push

寻找来自可靠和/或官方来源的答案。

torek评论他的其他答案中提到的“比较和交换”由Git 本身来源进一步说明。

如果远程没有本地分支没有的提交,后者只会推送到远程?

该功能在此提交中引入(2013 年 12 月,Git v1.8.5-rc0)

--force-with-lease将通过要求它们的当前值与某些合理的默认值相同来保护所有将要更新的远程引用,除非另有说明;

目前,“一些合理的默认值”被暂时定义为“我们拥有的远程跟踪分支的值,用于更新远程的引用”,如果我们没有这样的远程跟踪分支,这是一个错误。

所以“租赁”的意思是:

force-with-lease ”:您假设您在获取时对 ref 进行了租约,以决定重新定位的历史记录应该是什么,并且只有在租约没有被破坏的情况下才能推迟。

消息来源仍然提到“cas”:

  • 这个选项最初被称为“ cas ”(代表“比较和交换”),这个名字没有人喜欢,因为它太技术化了。
  • 第二次尝试将其称为“lockref”(因为它在概念上类似于在获取锁后推送)但是“锁”这个词被讨厌,因为它暗示它可能会拒绝其他人的推送,这不是此选项的工作方式。
  • 这一轮称之为“强制租赁”。
    您假设您在获取时租用了 ref 以决定重新定位的历史记录应该是什么,并且只有在租用未被破坏的情况下才能推迟。

所以:“ git push --force-with-lease vs. --force

正如我在“默认push --force-with-lease ”中提到的,正如 Git 2.13(2017 年第二季度)所提到的,选项--force-with-lease可以是忽略如果后台进程(例如您在带有 Git 插件的 IDE 中找到的那些)运行git fetch origin
在这种情况下, --force占上风。

正如Pavlus 在评论中补充的那样

它本身并没有被忽略,只是现在您对本地远程头和远程头具有相同的参考,因此--force-with-lease将正确运行 -- 比较这两者,如果在 fetch 和推,有人更新远程,它不会表现为--force ,它仍然会失败。


另一个区别:在 Git 2.29(2020 年第四季度)之前,使用“ --force-with-lease ”选项推送名称包含非 ASCII 字符的引用在智能 HTTP 协议上不起作用。
它可以与git push --force

请参阅brian m 的commit cd85b44 (2020 年 7 月 21 日) 卡尔森 ( bk2204 )
(由Junio C gitster合并-- gitster -- in commit c2796ac ,2020 年 7 月 30 日)

remote-curl : 使--force-with-lease使用非 ASCII 引用名称

报道者:Frej Bjon
签字人:brian m. 卡尔森

当我们调用远程传输助手并传递带有参数的选项时,如有必要,我们将参数引用为 C 样式字符串。
当我们传递非 ASCII 引用名称时,cas 选项就是这种情况,它实现了--force-with-lease命令行标志。

然而,远程curl助手并不是为了解析这样的参数而设计的,这意味着如果我们尝试将--force-with-lease与 HTTP 推送和非 ASCII 引用名称一起使用,我们会收到如下错误:

 error: cannot parse expected object name '0000000000000000000000000000000000000000"'

请注意双引号, get_oid提醒我们在十六进制对象 ID 中无效。

即使我们能够解析它,我们也会将错误的数据发送到服务器:我们会发送一个转义的引用,它不会像用户想要的那样运行,并且可能会意外地导致更新或删除我们没有的引用故意的。

由于我们需要在这里期待一个带引号的 C 样式字符串,只需检查第一个参数是否是双引号,如果是,则取消引用它。
请注意,如果 refname 包含双引号,那么我们已经将其双引号,因此没有歧义。

我们仅在智能协议中测试这种情况,因为基于 DAV 的协议无法处理此功能。
我们使用 UTF-8 是因为这在我们的测试中更好,对 Windows 更友好,但代码应该适用于所有非 ASCII 引用。

虽然我们在这里,因为选项的名称现在已经很好地建立并且不会改变,让我们内联它而不是使用 #define 常量。

git push --force是破坏性的,因为它无条件地用本地的任何内容覆盖远程存储库。 强烈建议不要使用 git 的push --force因为它会破坏已经推送到共享存储库的其他提交。 强制推送的最常见原因之一是当我们被迫重新设置分支时。

例如。 我们有一个带有功能分支的项目,Alice 和 Bob 都将在该项目上工作。 他们都克隆了这个存储库并开始工作。 Alice 最初完成了她的部分功能,并将其推送到主存储库。 这一切都很好。 Bob 也完成了他的工作,但在推动它之前,他注意到一些更改已合并到 master 中。 为了保持一棵干净的树,他对主分支执行了变基。 当然,当他去推送这个 rebase 的分支时,它会被拒绝。 然而没有意识到 Alice 已经推动了她的工作,他执行了 push --force。 不幸的是,这将删除 Alice 在中央存储库中的所有更改记录。

--force-with-lease所做的是拒绝更新分支,除非它是我们期望的状态; 即没有人更新上游分支。 在实践中,这是通过检查上游 ref 是否符合我们的预期来实现的,因为 ref 是散列,并将父链隐式编码为它们的值。

这是一篇关于git push --forcegit push --force-with-lease的好帖子: –force 被认为是有害的; 理解 git 的 –force-with-lease

假设服务器上的任何 pre-receive 钩子接受推送,这将始终成功:

git push --force

而这会在继续之前运行特定的客户端检查:

git push --force-with-lease

您可以自己手动运行特定检查。 这是“租约检查”算法:

  1. 找出你当前的分支。

  2. 运行git for-each-ref refs/remotes 记下您的 git 客户端认为对应于您当前分支的上游状态的 commit-id。

例如,如果您在分支“foo”上,请注意与“refs/remotes/origin/foo”相关联的提交 ID。

  1. 立即确定上游 git 服务器上远程分支的实际提交 ID。

  2. 如果您从第 2 步和第 3 步中提取的提交 ID 一致,则仅让“git push”继续。 换句话说,只有当您本地 git clone 的上游概念与实际上游一致时才继续。

这里有一个可悲的含义:由于git fetch “refs/remotes/origin/*”下的所有 refs 更新为最新版本,因此这种命令组合与git push --force基本相同:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

为了解决git push --force-with-lease这个固有弱点,我尝试从不运行git fetch 相反,每当我需要与上游同步时,我总是运行git pull --rebase ,因为git pull只更新 refs/remotes 下的单个 ref,保持--force-with-lease的“租约”有用。

强制租赁不一定安全。 它就像 Sylvie 所说的那样工作。 一个注意事项:在 git 中,分支只是提交上的一个指针。 并且提交指向零个或多个父提交。 即使您完全使用硬 git reset 和强制推送或使用 --force-with-lease 推送而完全更改了分支,这也不一定是大问题。 您可以使用本地 git reflog 来查看分支上的本地提示(当时 HEAD 在哪里?)已更改并重置并再次推送分支。 然后你只会丢失远程分支上的新提交,但即使它们也可能被团队成员恢复。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM