git conflicts are annoying. Your code can be working seamlessly and then when you go to merge it with another teammate’s code, it all falls apart.
Sometimes, you get a massive, multi-line error for a single edit. Sometimes, no matter what you do, you just end up bouncing your git conflicts back and forth between the same person.
It happens a lot more in production and commercial based projects than you’d expect.
Over the years, I’ve seen enough git conflicts to understand that it’s more than just the code. It’s also to do with your team’s processes, in addition to how work and the code are divided.
The bigger the team, the higher the chances of a git conflict. The same goes for your code repo.
So what can you do? First, you need to drill down to the root cause. These problems often crop up as persistent patterns. Here are some of the patterns I’ve encountered in a team space and how we fixed them.
When you’re working in a team, having clear domains of work can prevent you from getting git conflicts in general.
If you’re getting the same git conflicts, especially for the same files over and over again, it usually means that your work is overlapping. As a result, any edit you make has a direct impact on the other person’s work.
So how do you prevent or stamp out this issue?
The first thing to do is to observe the scope of your work and decide how you and your teammate should abstract out each other’s portion of the work.
The point of this exercise is not for one person to take over another person’s feature, but to modularize the code in a particular way to prevent it from the constant overlap.
git conflicts can often arise due to under abstraction, with not enough or clear boundaries on the suite of functions, modules, classes, and libraries.
You’re all working on the same project, and no matter what you do, everyone on the team keeps getting git conflicts.
This may be due to how the branches are structured, and your team’s pushing workflow.
If your team is larger than the ‘two-pizza’ rule (if you need to order more than 2 pizzas your team is to big), coordination can be hard, especially if you’re all working on the same git branch. This is not recommended but for some workplaces, that’s simply how it’s done.
When these kinds of conflicts happen, the first thing you need to do as a team is de-tangle your workflow. How do you do this?
First, start by having your own personal branch to work on.
The second step is clearly separate out domains of code. This prevents your work from overlapping another person’s code, and therefore start of a series of neverending git conflicts.
The third thing you need to do is decide on a commit workflow. For example, this can be done through the ordering of features commit. Alternatively, it can be provisioned through a commit pipeline. This means that code needs to be reviewed before merging and committed to the main project branch.
Yes. This can happen and does happen quite a bit.
The problem with getting git conflicts with yourself is often caused by the repo on your machine not being up to date with the current branch. Alternatively, it can be caused by someone else working in your branch — hence the reason why your repo may be outdated.
Changes may have been committed in places you weren’t expecting, resulting in a git conflict with the files you’re working on.
Alternatively, you’re getting git conflicts with yourself maybe because you’re switching between too many branches and not merging them into a central branch.
This central branch is necessary to keep everything pipelined correctly and ensure that the repo you’re working on contains the most recent updates.
Often, the root cause of git conflicts is because your code pushes are not streamlined and single tasked.
Why?
Because git is very linear in nature.
At the end of the day, the point of git is to let you work on multiple repos at the time but ultimately bring it all together into a single and final branch — which, in many cases, is the master branch.
The master branch acts as your single source of truth and anything that deviates from this is either an update or a conflict.
Your main aim is to make it an update, rather than conflict.
So to do this, you need to sequence your commits to accommodate for changes within dependencies — but sometimes, conflicts happen regardless, especially when you’re merging back several forks from multiple developers.
Here are some recipes to help you solve merge conflicts.
This happens when changes have been made on the same set of code. This can be through deletion or modifications. To resolve this issue, you’ll need to decide on which changes to keep in the new commit.
This issue often arises when more than one developer is working on the same file — hence why it’s necessary to keep your code domains separated to prevent such issues from happening again in the future.
To resolve this kind of merge conflict, use git status to get a list of all the conflicted files.
For this, you’ll need to manually go through the file and delete what you don’t want to keep. Search for the conflict marker <<<<<<<
Changes on the base branch are marked with <<<<<<< HEAD , followed by ======= . This divider acts as the divide between your changes and the changes made by others, marked by >>>>>>> BRANCH-NAME
Decide on what the final code will look like and delete all the conflict marker: <<<<<<<, =======, >>>>>>>
Once done, add your changes to the stage using git add .
Then officially commit your code using git commit -m “your commit note here”
It happens sometimes where one person adds a file while another deletes it.
The issue pop up as an unmerged paths issue, with a list of files of who deleted the file. The issue may look something like this:
$ git status
> # On branch master
> # Your branch and ‘origin/master’ have diverged,
> # and have 1 and 2 different commits each, respectively.
> # (use “git pull” to merge the remote branch into yours)
> # You have unmerged paths.
> # (fix conflicts and run “git commit”)
> #
> # Unmerged paths:
> # (use “git add/rm …” as appropriate to mark resolution)
> #
> # deleted by us: filenamehere.js
> #
> # no changes added to commit (use “git add” and/or “git commit -a”)
To solve this issue, you need to decide if you want to keep or discard the file. If you want to permanently remove the file from the repo, use git rm filenamehere.js
If you want to keep the file, use git add filenamehere.js and this will override the delete and keep your file as part of the commit.
Why do we do this?
Because this file may be a dependency for your commit and it prevents accidental deletion by another developer.
After you’ve added or removed permanently the file or files listed in question, commit your code using git commit -m “your message here”
Sometimes your code can be in a bit of a spaghetti state and you need to reset it to a known safe point.
To do this, you can use git reset to roll back the repo you’re currently in.
First, you need to figure out which commit you want to roll back. To do this, use git log
Take note of the commit hash.
Then use git reset [yourhashcommithere]
Once you hit enter, your code will have reverted back to how it was originally before commits. Changes made will be pushed to the unstaged space.
If you want a clean reset with no changes in the repo, use git clean –all
This will give you a clean reset with no changes. If you want to commit this roll back in your branch, you can push it to the origin — but do this with caution and only if you want to make the change permanent in your repo.
git merge conflicts are never fun. They can be downright annoying — but it is often part and parcel with the job.
Regardless of where you go, you’re going to get git conflicts of some sort. Sometimes, they emerge in innocence, other times, it’s an indication of team workflows that are not optimized for modular code development.
Whatever the case, I hope this article has helped shed some light on why git merge conflicts happen and how you can potentially fix them.