Blog cover

Git Merge Conflicts

Harsh Seksaria
Version Control System, Git and GitHub

--

Hey there! Hope you’re doing well.

In the last blog, we saw more about branches, how to merge two or more branches and how they change files when we see them in file explorer. In this blog, we are going to learn about merge conflicts, what they mean, when they arise, and how to manage those conflicts.

Suppose there's a file in two branches. There have been changes in the file at the same location in both branches. So when you try to merge these two branches, you will get something called a merge conflict.

In a general situation, like the last example we saw, Git will automatically merge the branches (say we have edits to the same files, but at different locations, even that's fine) when there is no conflict. But when a merge conflict arises, i.e., there are edits at the same location of the same file in both the branches, Git will need a little help from us to know what to do.

A conflict won't occur unless you try to merge, and these are compared with files in the latest commit. So, maybe a lot of developers work on the same file in different branches, share with others, and after finishing the work, while merging, BOOOM💥, conflict arises.

Let's create a conflict situation and see how Git lets us deal with it.

Step 1: Let's see if we have any existing branches and if there are any, you can delete them. (Recall commands to list and delete branches from previous blogs) Make sure you are in the main branch.

Main branch label
Make sure you are in the main branch. Ensure “main” is there.

Step 2: Create a file in the folder as sort.py and enter some code.

file
Notice the file “sort.py”
Contents of the file
Contents of the file

Step 3: Create a new branch experiment_sort and move into that branch.

git branch experiment_sortgit checkout experiment_sort

Now, if you would have deleted any files from the main branch and not made a commit, those deleted files will be included in the new branch, and not the file we made right now.

See that old files are included, but not the new file.

Git takes the last commit instance from the parent branch and makes that new branch. So if you didn't get the new file sort.py, move to main, delete the branch made right now, commit in the main, and then again create this new branch.

git checkout maingit branch -d experiment_sortgit commit -a -m "Sort files added"git branch experiment_sort

Now, you are prepared to create a conflict situation.

Step 4: Right now, we have created a branch from a commit instance of main. So we make changes in both branches, commit at both places, and then try to merge.

Edit file in the main branch and commit. (Make sure you are in the main branch)

Edited sort.py
Edited file. Notice that I have replaced both the pass statements in the main branch.

Now, commit it and checkout to the experiment_sort branch.

git add .git commit -m "Changed pass statements"git checkout experiment_sort

Now edit the pass statement in main( ) and commit the changes.

making changes in new branch
See I have only replaced the first pass statement in the experiment_sort branch.
git add .git commit -m "Changes made in another branch"

Step 5: Now if you recall, to merge two branches, we need to checkout to the branch in which we want to bring in the changes from another branch. Here, we move to the main.

git checkout main

Step 6: Finally, comes the merge command.🎈

git merge experiment_sort

But, what just happened?😲😮😯🙀😵🥴😱😰😢

Read the above lines.

Git was trying to automatically merge the two editions of files (from two branches) but it got confused between the two changes we made at the same place (the pass statement under main was replaced) as to which one should be kept in the main.

Run the command to see the status of the repo.

git status
Ah! Well, that's a lot of information.

From the above output, Git tells us that we have unmerged paths and we can either fix conflicts and try again or abort the merge.

Merging process
Notice the branch indicator. It shows merging with main. That's why we have the option to abort the merge.

Step 7: Open the sort.py file.

Notice that Git has added some information in the file to indicate which line has conflict. In the green color, it shows current change, which means the changes whatever had been made in this branch (main, here) and in blue color, it says incoming change, which means changes being taken in from experiment_sort branch.

Remember we changed the pass statement in sort( ) too. There’s no conflict in that because we didn't make any change to that part in the experiment_sort branch.

We have all the freedom here to choose which version of the change to keep or to change the file entirely or to accept both the changes.

Say if we want to keep both the changes, you can simply remove the conflict markers and save the file. Or if you're using VS Code, like me, you can click on the options above markers. (Accept Current Change | Accept Inco…..)

Step 8: Close the file after saving and run the following command.

git add sort.pygit status
status after fixing conflicts
Now it says that conflicts have been fixed but we are still in the process of merging.

Fiiiiiiiiinalyyyyy, something good.😅

Step 9: Now we need to commit to wrap up the merge process.

Do you remember the steps to commit I told you before? Where we can either pass the commit message in command using the -m option or write a message in the editor. Let's go with the second option. Just type git commit.

Commit message editor

Notice that there is already a commit message which is written in yellow. This has been given by default by Git. Also, see it tells which file had a conflict. You can obviously add more to this commits message if you like. So the final message will look like this:

Adding to commit message
After adding to the commit message

Save and exit. (If it opened in VI editor, use :wq to write and exit)

Dooooooooooooone. 👍

Step 10: Let's see the graph type log of commits.

git log --graph --oneline
Graph log
I have created this in a new repo. So older commits are not listed here.

Try to go through the flow of the commits and understand what’s happening where.

Here we had a simple conflict in a single line in a single file. But in reality, the scenario could be bad. There may be a number of conflicts at different places, in multiple files across multiple branches. If you want to just leave everything and go back, you can use the abort command as a shield.

git merge --abort

Summary

We have created a conflict scenario to see how Git deals with it with our help. We created a new branch, made changes at the same location in the same file in both the branches, and tried to merge. Git also inserted conflict markers in the file where there was a conflict. Finally, we kept both the changes, saved the file & committed it, and wrapped up our merging process.

In the next blog, you will find a cheat sheet for all the commands related to branches. Till then, happy learning!

My name is Harsh Seksaria. I like to write about the topics simplifying them as much as possible for you to understand without unnecessary effort. Still, sometimes something may not be very clear. If you find any mistake, error, or you have a suggestion, just mail me. I’ll try to improve it asap.

My email: harsh20.freelance@gmail.com

My LinkedIn: www.linkedin.com/in/harshseksaria

--

--

Harsh Seksaria
Version Control System, Git and GitHub

MSc Data Science @ Christ (Deemed to be University), Bangalore, INDIA