两个对等人同时将更改推送到同一个远程时,git如何工作 [英] How git works when two peers push changes to same remote simultaneously

查看:104
本文介绍了两个对等人同时将更改推送到同一个远程时,git如何工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

然而,据我所知,git在内部是一个键/值存储,与当前流行的NOSQL非常相似数据库尤其是支持p2p复制的Couch-DB。实际上,我想问一下,在客户端将更改推送到远程git存储库的情况下,git进程如何冲突?是否推送被拒绝?



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

解决方案

简短回答



是的,其中一个推送将被拒绝 - 无论哪个稍后,即使只有微秒,Jeulatingi提到在他的评论中。但是,它会被拒绝,因为远程存储库认为后面的推送历史不包含较早推送的历史记录,而不是因为它看到推送的内容中存在任何冲突。



更详细的答案



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



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

  P  -  Q  -  R 

你已经添加了一个提交S:

  P  -  Q  -  R  -  S 

...其他人添加了提交T:

  P  -  Q  -  R  -  T 

如果其他人在推送时首先到达那里(也就是说,服务器上的Git首先处理他们的推送),那么他们的推送将被接受,因为 R 是<$的祖先c $ c> T ,所以远程仓库也会有历史记录 P - Q - R - T 。如果您随后尝试推送,您将得到一个错误,因为 T 不是 S 的祖先。通常,在看到! [拒绝] 错误,您将运行 git pull git pull --rebase 确保你在远程仓库的master之前。



git pull 会创建一个合并提交 M 使您的历史记录如下所示:

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

... git pull --rebase 会重新应用您在 T 之上引入的更改以创建新的commit, S'

  P  -  Q  -  R  -  -  T  -  S'

在这两种情况下,您应该可以再次推送,因为 T M S'的祖先。 (假设没有其他人在同一时间再次推送!)



只要允许快进,就不需要解决远程端的冲突 - 如果有任何冲突,当您运行 git pull 时,系统会提示您在本地解析它们。



它可能值得注意的是,响应推送应用于远程仓库的更新是原子的,所以在上面描述的示例情况中, S T 同时被推送,它会始终是其中一个完全应用,而另一个将失败,不起作用。 / p>

有关您的键/值存储点的注释



Git的对象数据库作为一个键/值存储实现,它将对象名称(也称为散列或SHA1sums)映射到对象的内容,以我的经验,人们很容易学习Git做出令人困惑的假设ns关于Git如何听到它就像是一个关键值存储时的行为 - 听起来好像这种情况可能发生在您的案例中,所以我建议在该级别考虑Git并不是理解最有用的方法这个问题。


I am new to git, I usually use P4 which has center repository, while git is distributed 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!

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.

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?

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

解决方案

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.

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.)

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

P -- Q -- R

And you have added a commit S:

P -- Q -- R -- S

... while someone else has added a commit 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 R is 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 T is not an ancestor of S. Typically, on seeing that ! [rejected] error you will either run git pull or git pull --rebase to make sure that you are ahead of master in the remote repository.

git pull will create a merge commit M to make your history look like:

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

... while git pull --rebase will reapply the changes that you introduced on top of T to create a new commit, S':

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

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

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.

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 S and T are being pushed at the same time, it will always be the case that one of them is completely applied while the other one will fail, having not effect.

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如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆