58

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.

vefthym
  • 7,422
  • 6
  • 32
  • 58
Chang
  • 3,953
  • 2
  • 30
  • 43
  • 6
    The big point here is that it's impossible for two people to push completely simultaneously. One of them "gets there first", as Mark says, and a split-second is as good as an hour. The real question is: "what if one person pushes, then another pushes something different?" Mark has answered this for you as well. – Cascabel Jan 10 '11 at 15:58
  • Related question, specifically about using a network drive for the repo: [Concurrency in a GIT repo on a network shared folder](https://stackoverflow.com/questions/750765/concurrency-in-a-git-repo-on-a-network-shared-folder) – sleske Mar 01 '22 at 08:41

1 Answers1

90

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.

Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • I don't understand it clearly since there are some terms that I don't know about git.I need more time to learn git for understand your answers. 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 the mark's answer, I think the push should be rejected. – Chang Jan 13 '11 at 05:26
  • 1
    @Chang, all the conflicts should be resolved at local site. If server detects a conflict when someone pushes data (and if two users are doing this "simultaneously" one of the pushes will be conflicting, because it will be applied only after the other one completes), the server will reject it, and the unlucky user shall then resolve conflicts and try to push again. – P Shved Jan 13 '11 at 05:38
  • 1
    @Chang: I'm afraid git really isn't like a key/value store, and it'll just be confusing to think of it in those terms. Perhaps the central idea is what a "commit" is (e.g. P, Q, etc. in my answer): a commit records the exact content of the source code at that point in time with the date, author's name, and references to parent commits. Those parent commits let you construct the history of the project up to that point. The later push won't be rejected because of conflicts - it'll be rejected because the history of the commit you're pushing doesn't include the commit in the earlier one. – Mark Longair Jan 13 '11 at 08:55
  • This. Seriously, git isn't anything like a key-value store and, as Mark said, thinking of it in those terms will only bring you further confusion. – James Gregory Jan 13 '11 at 09:34
  • @Mark, James Thank your answers! I get that from http://progit.org/book/ch9-2.html. – Chang Jan 14 '11 at 02:34
  • I think this answer is really incomplete. First, "Git is a content-addressable filesystem. Great. What does that mean? It means that at the core of Git is a simple key-value data store." That's from the Git book 10.2. Sure, thinking of git as key-value store is not helpful for most use cases. However, saying git is *not* a key-value store *internally* is misleading. Second, the answer does not explain how git handles *simultaneous* updates. It simply says - yes git handles them, you will get a conflict, but why is not answered. – user316606 Jan 07 '17 at 04:23
  • @user316606 You're quite right, I said something incorrect in trying to guide the questioner away from a way of thinking about the issue that I thought would be unhelpful. (Maybe this is just bad luck, but I've come across a few people learning git who'd read something like the statement you quoted from the Git book, and then made really strange assumptions as a result.) I've corrected that, and made it much less prominent in the answer. I've also added a paragraph pointing out that updates to a ref are atomic, which I hope addresses to some extent the question about "simultaneous" pushes. – Mark Longair Jan 22 '17 at 19:16
  • And what happens if the two pushes come exactly at the same time? It is at least theoretically possible. Does Git do some sort of locking? – Soong Feb 16 '17 at 07:59
  • 1
    @Soong I'm not an expert on this by any means but a quick look at the code and release notes suggests to me that the atomicity of updates used to be assured with a lockfile, but now there's a system of transactions so that multiple refs can be updated atomically together. You can start looking here if you're interested in the details: https://github.com/git/git/blob/6e3a7b3398559305c7a239a42e447c21a8f39ff8/refs.c#L898-L938 or ask a new question. – Mark Longair Feb 16 '17 at 09:24
  • Is it whichever push *starts* first that wins, or whichever push *finishes* first? – David Moles Apr 06 '18 at 16:22