Merge conflicts… Nobody likes them. Some of us even fear them. But they are a fact of life when you’re working with Git, especially when you’re teaming up with other developers. In most cases, merge conflicts aren’t as scary as you might think. In this fourth part of our “Advanced Git” series we’ll talk about when they can happen, what they actually are, and how to solve them.
How and when merge conflicts occur
The name gives it away: a merge conflict can occur when you integrate (or “merge”) changes from a different source into your current working branch. Keep in mind that integration is not limited to just merging branches. Conflicts can also happen during a rebase or an interactive rebase, when you’re cherry picking in Git (i.e. when you choose a commit from one branch and apply it to another), when you’re running
git pull or even when reapplying a stash.
All of these actions perform some kind of integration, and that’s when merge conflicts can happen. Of course, this doesn’t mean that every one of those actions results in a merge conflict every time — thank goodness! But when exactly do conflicts occur?
Actually, Git’s merging capabilities are one of its greatest advantages: merging branches works flawlessly most of the time because Git is usually able to figure things out on its own and knows how to integrate changes.
But there are situations where contradictory changes are made — and that’s when technology simply cannot decide what’s right or wrong. These situations require a decision from a human being. For example, when the exact same line of code was changed in two commits, on two different branches, Git has no way of knowing which change you prefer. Another situation that is a bit less common: a file is modified in one branch and deleted in another one. Git will ask you what to do instead of just guessing what works best.
How to know when a merge conflict has occurred
So, how do you know a merge conflict has occurred? Don’t worry about that — Git will tell you and it will also make suggestions on how to resolve the problem. It will let you know immediately if a merge or rebase fails. For example, if you have committed changes that are in conflict with someone else’s changes, Git informs you about the problem in the terminal and tells you that the automatic merge failed:
$ git merge develop CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result.
You can see that I ran into a conflict here and that Git tells me about the problem right away. Even if I had missed that message, I am reminded about the conflict the next time I type
If you’re working with a Git desktop GUI like Tower, the app makes sure you don’t overlook any conflicts:
In any case: don’t worry about not noticing merge conflicts!
How to undo a merge conflict and start over
You can’t ignore a merge conflict — instead, you have to deal with it before you can continue your work. You basically have the following two options:
- Resolve the conflict(s)
- Abort or undo the action that caused the conflict(s)
Before we go into resolving conflicts, let’s briefly talk about how to undo and start over (it’s very reassuring to know this is possible). In many cases, this is as simple as using the
--abort parameter, e.g. in commands like
git merge --abort and
git rebase --abort. This will undo the merge/rebase and bring back the state before the conflict occurred.
This also works when you’ve already started resolving the conflicted files and, even then, when you find yourself at a dead end, you can still undo the merge. This should give you the confidence that you really can’t mess up. You can always abort, return to a clean state, and start over.
What merge conflicts really look like in Git
Let’s see what a conflict really looks like under the hood. It’s time to demystify those little buggers and get to know them better. Once you understand a merge conflict, you can stop worrying.
As an example, let’s look at the contents of an
index.html file that currently has a conflict:
Git is kind enough to mark the problematic areas in the file. They’re surrounded by
>>>>>>>. The content after the first marker originates from our current working branch (
HEAD). The line with seven equals signs (
=======) separates the two conflicting changes. Finally, the changes from the other branch are displayed (
develop in our example).
Your job is to clean up those lines and solve the conflict: in a text editor, in your preferred IDE, in a Git desktop GUI, or in a Diff & Merge Tool.
How to solve a conflict in Git
It doesn’t matter which tool or application you use to resolve a merge conflict — when you’re done, the file has to look exactly as you want it to look. If it’s just you, you can easily decide to get rid of a code change. But if the conflicting change comes from someone else, you might have to talk to them before you decide which code to keep. Maybe it’s yours, maybe it’s someone else’s, and maybe it’s a combination of those two.
The process of cleaning up the file and making sure it contains what you actually want doesn’t have to involve any magic. You can do this simply by opening your text editor or IDE and making your changes.
Sometimes, though, you’ll find that this is not the most efficient way. That’s when dedicated tools can save time and effort. For example, there are various Git desktop GUIs which can be helpful when you’re resolving merge conflicts.
Let’s take Tower as an example. It offers a dedicated “Conflict Wizard” that makes these otherwise abstract situations more visual. This helps to better understand where the changes are coming from, what type of modification occurred, and ultimately solve the situation:
Especially for more complicated conflicts, it can be great to have a dedicated Diff & Merge Tool at hand. It can help you understand diffs even better by offering advanced features like special formatting and different presentation modes (e.g. side-by-side, combined in a single column, etc.).
There are several Diff & Merge Tools on the market (here are some for Mac and for Windows). You can configure your tool of choice using the
git config command. (Consult the tool’s documentation for detailed instructions.) In case of a conflict, you can invoke it by simply typing
git mergetool. As an example, I’m using the Kaleidoscope app on my Mac:
After cleaning up the file — either manually in a text editor, in a Git desktop GUI, or with a Merge Tool — you can commit the file like any other change. By typing
git add <filename>, you inform Git that the conflict has been resolved.
When all merge conflicts have been solved and added to the Staging Area, you simply create a regular commit. And this completes the conflict resolution.
As you can see, a merge conflict is nothing to worry about and certainly no reason to panic. Once you understand what actually happened to cause the conflict, you can decide to undo the changes or resolve the conflict. Remember that you can’t break things — even if you realize you made a mistake while resolving a conflict, you can still undo it: just roll back to the commit before the great catastrophe and start over again.
If you want to dive deeper into advanced Git tools, feel free to check out my (free!) “Advanced Git Kit”: it’s a collection of short videos about topics like branching strategies, Interactive Rebase, Reflog, Submodules and much more.