How will Git merge this?
John and Tom clone the same remote repo.
The content of remote repo is like this:
John make a local commit like this, ie, it moves the FileA.c into a folder named John and commit it locally.
Tom also make a local commit like this, ie, it moves the FileA.c into a folder named Tom and commit it locally.
If Tom and John both push their local repos to the remote repo, say GitHub, how will Git merge this?
I hope I made myself clear.
6 Solutions collect form web for “How will Git merge this?”
When you do
git commit but don’t do
git push, the changes are added in your local repository and are not committed to the global repo. So, whosoever pushes his changes first, he won’t get any conflicts since the remote server doesn’t know about the changes made by other user that are not yet
pushed. Later when the next user tries to push the changes, git will give error that the global repo has been changed and you must pull the changes first. Since, the changes are in the same file and the location has been changed, There will be a conflict, which would not be resolved by git itself.
The next user will have to make the changes again and push it so as to update the global repo.
Git/SVN/etc, do a merge as best as possible: if they see that separate, non interfering lines of code have been added/deleted/modified, then it will simply combine those changes made by John/FileA.c and Karen/FileA.c (its become practice to make someone in your example a girl =P). If the merge script see’s that the same lines of code have been edited then it will mark it as conflict in the file.
I think this point has been made, but this process occurs locally; either by Karen or John, depending on who was the person to try and push last. The person who pushed last will be notified to pull from the remote repo and resolve any conflicts before pushing their own changes.
Git will never merge during
push. One of the two devs (the poor one who tries to push last) has to resolve the conflict locally and tell git where to move the file. Git cannot know where the file should end up without human intervention.
# dev1 git clone … mkdir John && git mv FileA.c John/FileA.c git commit -m 'move file to john subdir' git push origin master # dev2 git clone … mkdir Tom && git mv FileA.c Tom/FileA.c git commit -m 'move file to tom subdir' git push origin master # git errors out: non-fast-forward, pull first to resolve potential conflicts git pull origin master # merge conflict in FileA.c # tell git which file to delete and which file to keep: git rm Tom/FileA.c && git add John.FileA.c git commit # creates a merge commit git push origin master
A second push operation will fail; merge has to be done locally. In this case there will be a conflict that must be resolved manually.
The nice thing about git is that it’s easy to try these things out for yourself without affecting any servers. The result for the last guy to push is:
02:32:54 ~/desktop/tom $ git push To /cygdrive/h/desktop/test ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to '/cygdrive/h/desktop/test' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details. 02:32:54 ~/desktop/tom $ git pull remote: Counting objects: 3, done. remote: Total 2 (delta 0), reused 0 (delta 0) Unpacking objects: 50% (1/2) Unpacking objects: 100% (2/2) Unpacking objects: 100% (2/2), done. From /cygdrive/h/desktop/test 307f68a..2539f44 master -> origin/master error: refusing to lose untracked file at 'John/FileA.c' error: refusing to lose untracked file at 'John/FileA.c' CONFLICT (rename/rename): Rename "FileA.c"->"Tom/FileA.c" in branch "HEAD" rename "FileA.c"->"John/FileA.c" in "2539f448bb15d10f14bef74688dc3470975c2dbf" CONFLICT (rename/rename): Rename "FileA.c"->"Tom/FileA.c" in branch "HEAD" rename "FileA.c"->"John/FileA.c" in "2539f448bb15d10f14bef74688dc3470975c2dbf" Automatic merge failed; fix conflicts and then commit the result
Git is nice and asks which rename is the correct one. Note that not all version control systems are capable of detecting this kind of rename/rename conflict.
The key point from the other answers is that git doesn’t guess what should happen [using some pre-coded presumption], rather it will warn the user of the difficulty because it can’t mind read the various user intentions.
Most other systems which claim the ability to do such merges fail the clairvoyance test – they don’t know what you really wanted. Let the intelligent folk (that’s you and me 😉 make the decisions.