EGit 中出现 "Push only if remote refs don't change in the mean time" 复选框的原因是什么?

What is the reason for the "Push only if remote refs don't change in the mean time" check box in EGit?

eclipse EGit 插件提供了一个推送向导,用于将更改推送到 Git 存储库。在向导的末尾,有一个带有复选框 "Push only if remote refs don't change in the mean time" 的确认对话框,如 EGit 文档页面“http://wiki.eclipse.org/EGit/User_Guide#Push_Confirmation”中所述。

根据 Git 书第 2.5 章 (https://book.git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes),如果另一个人同时推送了一些更改,Git 将拒绝推送到远程存储库 (自上次 synchronization/fetch).

所以我的问题是:如果远程存储库自上次获取后发生更改,无论如何都会拒绝推送,那么描述的复选框有什么用?

要使用描述的选项打开对话框,您需要执行以下步骤:

我不使用 EGit所以我不得不猜测一点,但是从你链接的他们的页面上看,似乎是他们的推送对话在幕后使用了几个 Git 功能。

背景

According to the Git book, chapter 2.5 (https://book.git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes), Git will reject a push to the remote repository if another person has pushed some changes in the mean time (since the last synchronization/fetch).

这没有错,但也不是全貌。

当你 运行:

git push <remote> <refspec>

你的Git通过互联网呼叫另一个Git-phone和你的Git和他们的Git——"foreign"Git,正如 the githooks documentation 所说的那样——进行对话。您的 Git 向外国 Git 发送您的新提交,然后发送以下形式的请求或命令:

Please, if you like, set your master to point to commit 1234567

或:

I command you: set your master to 1234567 now!

这次谈话分为三个部分:一个确定您的 Git 和外国 Git 将要谈论的内容;一个用于传输提交(以及任何其他适当的 Git 对象);最后一个指导外国 Git 进行哪些参考更新,即您的分支更新是礼貌请求("do this if you like it")还是命令("take this now dammit")。 (我们还应该注意,这不仅仅是 branch 名称;同样的东西适用于标签和任何其他引用。尽管它们的工作方式都非常相似。)

但是这次对话中也有两个Git:你的,和外国的Git。这很好,但是世界中有两个以上的Git。如果 third Git 正在与外国 Git 交谈怎么办?有可能你的 Git 和另一个 Git 正在与外国人交谈 Git 同时.

Pro Git 这本书关注的是这里的一个大问题,即外国 Git 可能会在您发送礼貌 "please set" 之前的某个时间在其分支上获得新的提交要求。那样的话,你发出礼貌的"please set"请求时,外国Git说:"no, if I do that, I will forget commits that I have that you don't."那样的话,就像书上说的,他们拒绝推送,您可以获取 他们的 新提交,将他们对您的所有新提交与您的提交集成,然后重试。

但这就是更强大的、类似于命令的选项的用武之地:您可以坚持让他们忘记这些提交。他们仍然可以拒绝,但如果他们不拒绝,您可以让他们忘记一些承诺。这一步有点危险:即使你先获取他们的提交(看看你要他们忘记什么),也可能会有第三次 Git 积极与外国 Git 交谈,这样当你验证那些 你希望他们忘记的提交时,他们的分支名称提交哈希映射可能已更改。

因此在 Git 的现代版本中还有另一个选项,原子地 设置引用 当且仅当 它们匹配您认为它们匹配的内容。也就是说,你让你的 Git 发送一个命令:"set master to 1234567!" 加上“...但前提是它当前是 fedcba9!”这使您有机会从国外 Git 获取数据,决定要做什么,然后向他们发送在国外 Git 上 有条件 的命令] 尚未更改这些分支(或其他引用),以确保您不会干扰第三个 Git.

Git 调用这些原子比较和交换更新 --force-with-lease.

回到EGit

EGit 似乎想对你特别有帮助(在你结束这次谈话时),弄清楚 将来 会发生什么,在本次对话的一半 还没有开始!在这里,您正在查看带有可点击框和按钮的 GUI,并且您的 Git 甚至还没有通过 Internet 呼叫外国 Git-phone 尚未开始传输,并且您的EGit GUI 正在尝试猜测将来 发生什么,即使可能还有其他 Git现在在外面和外国人聊天 Git。

所以你的 EGit GUI 有点诡计:它有一个与外国 Git 的早期对话。它现在调用 Git,并询问它: "hey, what commits do your branches name?" 如果你的 EGit 有这些提交,你的 EGit 可以 计算出 你将发送给他们什么承诺。如果你的 EGit not 有那些提交,你的 EGit 可以 get 它们,然后找出什么提交你将发送给他们。1 所以现在你的 EGit 非常清楚它将向他们发送什么 它是什么将在 他们的 分支名称(和其他引用)中看到散列 ID 映射。

因此,您的 EGit GUI 可以向您显示这些内容。但是当你点击最后的 "go" 按钮时,你的 EGit 会再次Git 并开始两部分的对话——也许第三个 Git 先到达那里,并且对话不会像您的 EGit GUI 认为的那样进行。这就是这些额外的确认点击框的用武之地。

尚不完全清楚 EGit 是否使用了 "conditional command" 选项。在通过 Internet-phone-wire 发送提交和其他对象的可能冗长的对话期间,接收外国 Git 不会完全锁定 "third Git" 更新。他们 得到一组初始的名称到 ID 映射,如果不符合他们的预期,他们可以立即中止对话;那么他们必须在对话的中间部分实际 发送 对象;然后他们有最后的,更新外国-Git 的对话参考部分。 clicky 框是否仅在第一部分起作用,或者它们是否也影响任何最终命令与礼貌请求?我不清楚。

但是,这个问题的答案:

So my question is: What is the use for the described check box if the push would be rejected anyway in case the remote repository has changed since the last fetch?

可能使用条件(仅当事情没有改变时强制推送)功能,或者它可能是"abort the conversation if things don't even start as planned",或者它甚至可能两者兼而有之。您链接的文档中的图像有一个单独的点击框 "force push",因此 EGit GUI 可能不会将其最终请求作为命令发送,除非该框是 also 检查。检查第二个确认框是否将这些变成原子交换命令,我不知道;但是如果 没有, 初始检查 就足够了,因为 "third Gits" 可能会更新外部 Git 引用在对话的对象传输部分。

因此我会说:这要么给你一个感觉良好的东西,但实际上没有任何效果;要么,开启--force-with-lease


1我不知道 EGit 是否真的这样做了——运行是一个 git fetch 无形的——但如果它 不会它无法正确计算将在未来发送的提交集。