当两个对等方同时将更改推送到同一个远程时,git 如何工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4643998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:48:48  来源:igfitidea点击:

How git works when two peers push changes to same remote simultaneously

git

提问by Chang

I am new to git, I usually use P4 which has center repository, while git is distributed VCS.

我是 git 新手,我通常使用具有中心存储库的 P4,而 git 是分布式 VCS。

I am interested in how git works when two peers push changes to same remote simultaneously. Assume each peer resolved all conflicts before push. I guess the later one will be rejected if git reports conflicts!

我对当两个对等方同时将更改推送到同一个远程时 git 的工作方式感兴趣。假设每个对等点在推送之前解决了所有冲突。我猜如果 git 报告冲突,后面的会被拒绝!

However, from what I understand, git is internally a key/value store, much like the current popular NOSQL database especially Couch-DB which supports p2p replication.

然而,据我所知,git 在内部是一个键/值存储,很像当前流行的 NOSQL 数据库,尤其是支持 p2p 复制的 Couch-DB。

Actually I want to ask, how does git process conflicts in the case that clients push changes to remote git repository? Is the push rejected?

其实我想问一下,在客户端推送变更到远程git仓库的情况下,git如何处理冲突?推送被拒绝了吗?

From Mark's answer, I think the push should be rejected.

从马克的回答来看,我认为应该拒绝推送。

回答by Mark Longair

Short answer

简答

Yes, one of the pushes will be rejected - whichever one is later, even if it's just by a microsecond, as Jefromi mentions in his comment. However, it will be rejected because the remote repository sees that the history of the later push doesn't include the history of the earlier one, rather than because it sees any conflict in the content that's being pushed.

是的,其中一个推送将被拒绝 - 无论哪个推送晚一点,即使只是一微秒,正如 Jefromi 在他的评论中提到的那样。但是,它会被拒绝,因为远程存储库看到后来推送的历史记录不包括前一个推送的历史记录,而不是因为它看到正在推送的内容中存在任何冲突。

More detailed answer

更详细的回答

Usually a push will be rejected if it wouldn't "fast-forward" the branch, in Git terminology. This means that if your master is at A and the remote repository's is at B, then the push will only succeed if B is an ancestor of A. (I say "usually" because you can add options to "force" the push if the remote repository allows that, but that's not the typical case.)

在 Git 术语中,如果推送不会“快进”分支,通常会被拒绝。这意味着,如果您的 master 位于 A 而远程存储库的位于 B,那么只有当 B 是 A 的祖先时,推送才会成功。(我说“通常”是因为您可以添加选项来“强制”推送,如果远程存储库允许这样做,但这不是典型情况。)

In the case you describe, supposing all three repositories initially have the same history:

在您描述的情况下,假设所有三个存储库最初都具有相同的历史记录:

P -- Q -- R

And you have added a commit S:

并且您添加了一个提交 S:

P -- Q -- R -- S

... while someone else has added a commit T:

...而其他人添加了一个提交T:

P -- Q -- R -- T

If that other person gets there first when pushing (that is, Git on the server handles their push first), then their push will be accepted because Ris an ancestor of T, so the remote repository will then also have the history P -- Q -- R -- T. If you subsequently try to push, you will get an error because Tis not an ancestor of S. Typically, on seeing that ! [rejected]error you will either run git pullor git pull --rebaseto make sure that you are ahead of master in the remote repository.

如果其他人在推送时先到达那里(即,服务器上的 Git 先处理他们的推送),那么他们的推送将被接受,因为R是 的祖先T,因此远程存储库也将具有历史记录P -- Q -- R -- T。如果您随后尝试推送,您将收到一个错误,因为T它不是S. 通常,在看到该! [rejected]错误时,您将运行git pullgit pull --rebase确保您在远程存储库中领先于 master。

git pullwill create a merge commit Mto make your history look like:

git pull将创建一个合并提交M,使您的历史记录看起来像:

P -- Q -- R -- T -- M
           \       /
            -- S -

... while git pull --rebasewill reapply the changes that you introduced on top of Tto create a new commit, S':

... whilegit pull --rebase将重新应用您在其上引入的更改T以创建新提交,S'

P -- Q -- R -- T -- S'

In either of those cases, you should be able to push again, because Tis an ancestor of both Mand S'. (That is assuming no one else has pushed again in the mean time!)

在其中的任意一种情况下,你应该能够再次推,因为T是双方的祖先MS'。(这是假设在此期间没有其他人再次推动!)

By only allowing fast-forwards there never has to be resolution of conflicts on the remote side - if there are any conflicts, you'll be prompted to resolve them locally when you run git pull.

通过只允许快进,永远不必在远程端解决冲突——如果有任何冲突,当你运行git pull.

It might be worth noting that the update applied to the remote repository in response to a push is atomic, so in the example situation we've described above where Sand Tare being pushed at the same time, it will alwaysbe the case that one of them is completely applied while the other one will fail, having not effect.

可能值得注意的是,响应推送而应用于远程存储库的更新是原子的,因此在我们上面描述的示例情况中,其中ST被同时推送,总是出现以下情况之一它们完全应用,而另一个将失败,没有效果。

A note about your key/value store point

关于您的键/值存储点的说明

While Git's object database is implemented as a key/value store, which maps object names (also referred to as hashes or SHA1sums) to the content of objects, in my experience it's easy for people learning Git to make confusing assumptions about how Git behaves when they hear "it's like a key value store" - it sounds as if this might be happening in your case, so I'd suggest that thinking about Git at that level isn't the most helpful approach for understanding this issue.

虽然 Git 的对象数据库是作为键/值存储实现的,它将对象名称(也称为哈希或 SHA1sum)映射到对象的内容,但根据我的经验,学习 Git 的人很容易对 Git 在以下情况下的行为做出令人困惑的假设他们听到“它就像一个键值存储”——听起来好像在你的情况下可能会发生这种情况,所以我建议在那个级别考虑 Git 并不是理解这个问题的最有帮助的方法。