Merge Conflicts arise when multiple agents modify the same part of a file and push their changes to a remote branch. When you attempt to merge, pull from or push to these branches - there's a conflict, and Git isn't sure which set of changes to accept and which to reject, since there's no objective measure of which change is right.
Merge Conflicts only arise when it's impossible to discern upfront which changes to keep, and in this case, you have to step in and make a decision.
There are three ways you can deal with a Merge Conflict - you can <em>continue</em> with the merge, by updating your local file to match what already exists in a remote repository, you can <em>abort</em> a merge, which is typically done if there's a <em>major</em> conflict that isn't easily remedied or you can keep the local changes from the working directory and force them upon the remote repository.
In this guide, we'll take a look at the three ways you can resolve a Merge Conflict with Git.
How do Merge Conflicts Happen?
Let's quickly create a repository and a merge conflict so we can observe which changes caused it and how the files look like when we resolve it. We'll emulate a remote-work environment by creating two folders and two Git repositories within them:
$ cd Jane $ git init $ git remote add origin https://github.com/DavidLandup0/solving-merge-conflicts.git $ cd.. $ cd John $ git init $ git remote add origin https://github.com/DavidLandup0/solving-merge-conflicts.git
Jane and John are working on a project together, and share the same file -
README.md. John wrote the file, accidentally leaving in a typo, and pushed it to the remote origin. Jane caught this, fixed the typo and pushed the file to the remote origin again.
Once John wanted to add a new line to the file, and merge his branch to the
main branch - his
README.md (which has the typo) was in conflict with the
README.md, which had the typo fixed.
On John's feature branch, he added a
$ git branch feature_john $ git checkout feature_john Switched to branch 'feature_john' $ echo 'Welcome to our READMW.md!' >> README.md $ git add README.md $ git commit -m "Added README.md" [feature_john c44d65f] Added README.md 1 file changed, 1 insertion(+) create mode 100644 README.md $ git push origin feature_john git push origin feature_john Enumerating objects: 4, done. Counting objects: 100% (4/4), done. ... To https://github.com/DavidLandup0/solving-merge-conflicts.git * [new branch] feature_john -> feature_john $ git checkout main Switched to branch 'main' $ git merge feature_john Updating 48f09c2..c44d65f Fast-forward README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md $ git push origin main Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/DavidLandup0/solving-merge-conflicts.git 48f09c2..c44d65f main -> main
John added a new file to his branch and pushed it to his remote branch and then merged into
main - no issues, there weren't any files there before that.
Now, Jane wants to get up to date with the
main branch by pulling the changes made there, notices the typo - fixes it, and pushes back to main to prevent others from pulling the erroneous piece:
$ cd Jane $ git pull origin main remote: Enumerating objects: 4, done. remote: Counting objects: 100% (4/4), done. ... Updating 48f09c2..c44d65f Fast-forward README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md $ git branch feature_jane $ git checkout feature_jane $ echo 'Welcome to our README.md!' > README.md $ git add README.md $ git commit -m "Fixed typo in README.md file" [feature_jane 60f64fc] Fixed typo in README.md file 1 file changed, 1 insertion(+), 1 deletion(-) $ git push origin feature_jane Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 292 bytes | 292.00 KiB/s, done. ... To https://github.com/DavidLandup0/solving-merge-conflicts.git * [new branch] feature_jane -> feature_jane $ git checkout main Switched to branch 'main' $ git merge feature_jane Updating c44d65f..60f64fc Fast-forward README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git push origin main Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/DavidLandup0/solving-merge-conflicts.git c44d65f..60f64fc main -> main
main is clean - no typo in the
README.md. Though, John's file is now out of sync.
- If he tries pulling the origin's
main- a Merge Conflict will occur.
- If he tries to push a change with a conflicting change on the remote branch - a Merge Conflict will occur.
- If he tries to run
$ git mergeon two branches that have conflicting changes - a Merge Conflict will occur.
Say John added a new line to the file, pulled from the
main branch and then tried merging his new addition into
main before pushing his :
$ echo 'New line!' >> README.md $ git add README.md $ git commit -m "Added new line to README.md" [feature_john ba27684] Added new line to README.md 1 file changed, 1 insertion(+) $ git checkout main Switched to branch 'main' $ git pull origin main From https://github.com/DavidLandup0/solving-merge-conflicts * branch main -> FETCH_HEAD Updating c44d65f..60f64fc Fast-forward README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git merge feature_john Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result.
There it is -
Merge conflict in README.md. There are three things John can do to solve this conflict, as he is now in the MERGING phase. When Git encounters a conflict, it doesn't abandon the merge - it allows you to attempt fixing the issue on the spot or abandon it if you'd like to.
Find Merge Conflict Source
The first step you need to take is find out why there's a Merge Conflict in the first place. When in the MERGING phase, as we are, Git will annotate the file that's causing the conflict. If we open the
README.md file on John's local machine, we'll see:
<<<<<<< HEAD Welcome to our README.md! ======= 'Welcome to our READMW.md!' New line! >>>>>>> feature_john
<<<<<<< denotes the cause of the conflict and the current reference follows it (
HEAD). This is the change from
main. Then, we've got the
======= line (just a separator) before John's set of changes.
>>>>>>> denotes that that's the end of the conflict, with the branch name we're trying to merge into the top side of
Note: If we were merging by pulling
feature_john- the order of changes would be the opposite, since the current reference would be on
feature_johnand the changes on
mainwould be beneath the
=======line. Though, keep in mind that this isn't good practice as the feature branch is meant to contain separate changes from the main branch.
<h3 id="solvemergeconflictwithgitmergeabort">Solve Merge Conflict with <em>git merge --abort</em></h3>
A valid way to solve the conflict is to abort from it - and stop the MERGING phase. This is typically done when the solution isn't to fix a single line - and when large changes need to be made. This usually necessitates a plan with a team member as well.
If we abort the merge, the added conflict lines will be removed and we'll have John's
README.mdfile once again.
While we're still in the merging phase, let's abort the merge altogether:
$ git merge --abort
This simply aborts the merge and your file is returned to its state before you've encountered the conflict:
'Welcome to our READMW.md!' New line!
If you're using Git's Command-Line Editor (or other shells that support the feature), you'll also be able to see which phase you're in:
(main) $ git merge feature_john Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result. (main|MERGING) $ git merge --abort (main) $
Now, with your file out of harm's way - phone your colleague and discuss your next steps. Alternatively, if you accept their changes, you can continue with the merge.
Solve Merge Conflict with git merge --continue
You can continue the merge with a conflict, but Git won't overwrite the files automatically. If you try merging, encounter a conflict, and try to
$ git merge --continue, you'll face another error:
$ git merge feature_john Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result. $ git merge --continue error: Committing is not possible because you have unmerged files. hint: Fix them up in the work tree, and then use 'git add/rm <file>' hint: as appropriate to mark resolution and make a commit. fatal: Exiting because of an unresolved conflict. U README.md </file>
If it were possible to continue, Git would've continued already. You're still in the MERGING phase, so you can change your
README.md to conform to
main's version of it, mark the resolution by adding or removing the file again, and then run the
$ git merge --continue command.
Let's fix the file first. In our case, since the "Welcome…" line was causing an issue, but the "New line!" wasn't - we can leave the new line in - John's new feature - and fix the typo that's in conflict:
Welcome to our README.md! New line!
add the file once again and run the
$ git merge --continue command:
Fix the file... $ git add README.md $ git merge --continue [main fea8fbb] Merge branch 'feature_john'
You've accepted the changes from
main and adapted your local file to reflect it, and adding it back.
Note: In newer versions of Git, when you run the
$ git merge --continuecommand, it'll commit that merge automatically, so you don't have to, though, you do have to add the changed file again. When you run the command, a text editor will open up with the default commit message of
Merge branch 'branch_name'. You can just exit it, saving the message, to commit the change and merge the branches.
<h3 id="solvemergeconflictbyforcinglocalchangestoremote">Solve Merge Conflict By Forcing Local Changes to Remote</h3>
Instead of aborting, or yielding to changes - if you're certain that the changes made in your working directory are certainly the ones to keep, you can keep the local changes instead of adapting to the remote ones.
When a Merge Conflict occurs, you can
$ git checkout the file from
feature_john, and then add it to the
Note: Remember that
$ git checkoutupdates the files in the working tree to match the version in the index.
When updating - you can <em>keep</em> the changes made on a different branch and apply it to this branch. On the
mainbranch, into which we wish to merge
feature_john, let's update the
README.mdfile to contain the changes from the
In the context of
main, these changes are referred to as theirs, while the changes on
main are referred to as ours. If you wish to keep changes from
main, switch the
--theirs flag with
$ git checkout --theirs README.md Updated 1 path from the index $ git add README.md $ git commit -m "Accepting changes from feature_john" [main 5541f29] Accepting changes from feature_john
Now, you can merge the rest of the changes that are not in conflict cleanly, since we've only created a roundabout merge for the one file that caused a conflict this way.
In this guide, we've taken a look at how to resolve Merge Conflicts in Git. We've explored the three ways you can bump into this common error, and how they arise. Then, we've explored three solutions to the issue, with the dummy two local repositories and a remote repository we've created in the examples.Reference: stackabuse.com