How to avoid git conflicts in a team?

Before you dig deep into your workflow, before you spend a moment of time or a dollar of money rebuilding your communication processes, ask your team three questions:

  1. Do we enforce whitespace conventions?
  2. If we use IDEs, do they all use the same formatting and keyword settings? For example, Eclipse can automatically finalize parameters.
  3. Do we generate textual build artifacts? For example, do we minify js, generate css rules from .sass or .scss files, or build xml configurations on the fly? Do we check them in?

After years of generating conflicts and helping others solve them in centralized workflows, I submit these three things cause the vast majority of our collective conflict pain:

The causes of merge conflicts

In the above image, the '!' slice represents legitimate merge conflicts. The vast majority of awful merges come from lazy whitespace conventions or overly aggressive IDEs (or occasionally, overly-refactory developers). Before you do anything else, standardize your IDE settings and whitespace conventions. Then have everyone issue this command in their local repositories:

# Enable the repository's stock pre-commit hook
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit

That pre-commit hook will conduct a series of checks every time you issue git commit, including a version of git diff --check, a command that checks if your committed changes introduce whitespace errors. The commit will be rejected if it does. If you really need to get around it, you can issue git commit --no-verify, but don't: Whitespace errors are like the unexploded ordinance of version control. They're merge conflicts waiting to happen.

If you want to clean up whitespace, refactor a file to improve its indentation, or otherwise make a large series of purely formatting changes, do it in isolated commits, and warn the team to check in their conflicting work in progress first.

If you conduct code reviews, make these the first questions every reviewer asks: "Did this change set touch anything it wasn't supposed to? Did it clean up any formatting? Did it unnecessarily refactor a method?" If it did, fail the review. Or if you can't, make sure those changes are sufficiently isolated from the logical changes (i.e. in different commits) to make your history useful.

Stylesheet languages, RequireJS, and js minifiers also cause conflicts, if their generated targets are checked in. The files created by these technologies are build artifacts. You wouldn't check in a WAR archive; don't check in a SASS-compiled CSS file. Or, if you feel you must, use a .gitattributes file to let git treat them as binaries.

If after doing all of these things, you still have merge conflicts, institute workflow improvements. Gary Fixler's answer is absolutely right: Legitimate merge conflicts arise because teams cannot or do not communicate well about the scope of their projects. Just make sure its not poorly enforced formatting rules first.


Well, to be really honest, the proper workflow involves good communication and management. Team members shouldn't often be working on the same thing and causing conflicts. Things like daily standups, and an attentive manager who knows what each member of the team is up to - at least in general - will go a long way in many cases to limit this.

It depends on the exact nature of the product, of course, but this is more of an organizational issue than a git issue. In fact, conflicts are often seen as "good" things, because they get people to get up from their desks, or call each other up to talk about why there was a conflict, and what should be done about it going forward. This is a chance to figure out that one person should own one area, or a set of files, or at least be the point of contact for discussing changes to that section.

Outside of making an up-front plan, there is no way to avoid git conflicts, but this would be the same issue in any versioning system. Any time two people change the same section of code, you have to figure out who wins. This is why it's not really appropriate to look toward the versioner for the solution, but to look to your team's methods and practices. Two cars can't go through an intersection at the same time, but it's extremely hard to invent cars that can pass through each other, so instead we invented the control systems of stop signs and traffic signals. This is a similar issue. We can't really make two changes to the same thing not conflict, so we must control how we work with the files.

You could consider one of the front-ends that allows locking in git, but I don't really agree with the concept, outside of non-mergeable filetypes. I think it's better to figure out a better team workflow, and meanwhile, use this as an opportunity to get really good at merging files. I did that, and now after months of doing it, conflicts are not an upsetting thing to me.


There is only one way to avoid conflicts: don't have different people edit the same file at the same time. Essentially each file has an owner who is responsible for all edits and who can pass ownership to another. Ownership for a file can be passed around based on a particular feature/branch or day-to-day as long as the ownership is clear.

If you find that you can't give one owner to each file then:

  • you need to split your files into smaller files that can be assigned to one owner
  • absolutely require that GIT conflicts get resolved (with all editors sitting together to resolve the individual conflicts).
  • Use a good multi-merge tool to visualize and then resolve the conflicts.

Ordering.

There are a few other things you can do that might help too. It will be clearer if I post them separately.

Where you insert new things will help determine whether you create conflicts.

Imagine a list of names of employees

Andy, 
Oliver, 
Ivan,

Then Brad and Patrick join and their names are added to the list. You add Brad and I add Patrick. We both add the names to the bottom of the list, and then use git to merge our lists. The result will be familiar to git users :-

Merge branch 'Patrick' into Brad

Conflicts:
    names.txt

@@@ -1,4 -1,4 +1,8 @@@
  Andy, 
  Oliver, 
  Ivan,
  <<<<<<< HEAD
 +Brad,
  =======
+ Patrick,
  >>>>>>> Patrick

Now suppose we had done the same thing but imposed a simple alphabetical ordering rule on our list. Now when we come to merge the two branches the results are a little more pleasing :-

Andy,
Ivan,
Oliver,

Add one name yourself and then merge the other person's change with git, to add the other name.

Auto-merging names.txt
Merge made by the 'recursive' strategy.
 names.txt | 1 +
 1 file changed, 1 insertion(+)

And we get

Andy,
Brad,
Ivan,
Oliver,
Patrick,

Since we don't know who is going to join the company next we are effectively adding to the list randomly, and by inserting in random places, conflicts of location in the files are less likely.