Resolving Common Git Merge Conflicts: A Step-by-Step Troubleshooting Guide
Master Git merge conflicts with this essential troubleshooting guide. Learn how to identify conflict markers (`<<<<<<<`, `>>>>>>>`), apply manual resolution strategies (keep local, keep remote, or combine), and safely complete merges or rebases. Turn frustration into productivity by following these clear, step-by-step instructions for conflict resolution.
Resolving Common Git Merge Conflicts: A Step-by-Step Troubleshooting Guide
A Git merge conflict means Git found overlapping changes and needs you to choose the final version. You will usually see this when two branches changed the same lines, renamed the same file differently, or both edited a file Git cannot merge automatically.
The goal is simple: inspect the conflict, edit the file to the version you actually want, stage it, then continue the merge or rebase.
Understanding What a Git Merge Conflict Is
A merge conflict occurs when Git attempts to integrate changes from one branch into another (e.g., using git merge or git rebase), but finds that both branches have modified the same lines of the same file independently. Git is excellent at combining non-overlapping changes, but requires human intervention when the changes overlap directly.
How Git Signals a Conflict
When a conflict arises during a merge, Git stops the operation immediately and notifies you that the merge failed. The affected files will be marked as conflicted in your working directory. You can check the status using:
git status
The output will list files "Unmerged paths," indicating they need manual resolution before the merge can proceed.
Step 1: Identify the Conflict Markers
Once Git halts the merge, the conflicted files contain special markers inserted by Git to delineate the conflicting sections. These markers help you see exactly which changes came from which branch.
The conflict markers
In a normal text conflict, you will see three marker lines surrounding two versions of the content:
<<<<<<< HEAD:- Marks the beginning of the changes from the current branch (the branch you are merging into).
=======:- Acts as a separator between the two sets of conflicting changes.
>>>>>>> branch-name:- Marks the end of the changes from the incoming branch (the branch you are merging from).
Example of a Conflict Block:
Suppose you are merging feature/A into main, and both branches edited line 10 of config.js:
// config.js
function getTimeout() {
<<<<<<< HEAD
return 5000; // Main branch default
=======
return 10000; // Feature A override
>>>>>>> feature/A
}
Step 2: Resolve the Conflict by Editing the File
Resolving the conflict involves editing the file to remove the Git markers and select the desired code combination. You have three primary resolution strategies:
A. Keep Changes from HEAD (Current Branch)
If you decide the version on your current branch (HEAD) is correct, you remove the incoming changes and all markers.
Resolution Action:
// config.js
function getTimeout() {
return 5000; // Main branch default
}
B. Keep Changes from the Incoming Branch
If you decide the changes from the branch being merged in are correct, you remove the current branch's changes and all markers.
Resolution Action:
// config.js
function getTimeout() {
return 10000; // Feature A override
}
C. Combine or Rewrite Changes (The Hybrid Approach)
Often, the best solution is to manually construct a new version that incorporates logic from both sides, or to rewrite the code entirely to satisfy requirements from both original modifications.
Resolution Action (Example Hybrid):
// config.js
function getTimeout() {
// Set timeout based on environment variable, combining logic
if (process.env.NODE_ENV === 'production') {
return 10000;
}
return 5000;
}
Best Practice: Always verify that the resulting code compiles and functions correctly after resolving a conflict block. Running unit tests is highly recommended at this stage.
Step 3: Stage the Resolved Files
After you have manually edited every conflicted file, removing all <<<<<<<, =======, and >>>>>>> markers, you must stage these changes to inform Git that the conflict has been handled.
Use the standard git add command for each file you resolved:
git add config.js
git add src/utils/helper.py
# ... repeat for all conflicted files
To verify that Git recognizes the resolution, run git status again. All previously unmerged paths should now appear under "Changes to be committed."
Step 4: Finish the Merge or Rebase
Once all conflicts are staged, you finalize the operation based on the original command initiated:
Finishing a git merge
If you were performing a standard merge, you finalize it with a commit:
git commit
Git will typically open your configured text editor with a pre-populated merge commit message. Review it, save, and close the editor. The merge is now complete.
Finishing a git rebase
If you were rebasing, you continue the process, which applies subsequent commits on top of the resolved state:
git rebase --continue
If subsequent commits in the rebase sequence also cause conflicts, you repeat Steps 2 through 4 for each conflict encountered.
Troubleshooting Tips for Difficult Conflicts
While the steps above cover standard resolution, complex scenarios might require alternative approaches:
Abort the operation
If you start a merge or rebase and realize the situation is too complex or you need to consult with a teammate, you can always revert to the state before the command was issued:
git merge --abort # If you started with 'git merge'
git rebase --abort # If you started with 'git rebase'
Use a visual diff tool
For complex files with many overlapping changes, using a dedicated three-way merge tool (like VS Code's built-in merge editor, KDiff3, or Meld) is highly recommended. You can launch your configured tool directly:
git mergetool
This interface often shows the local version, the remote version, and the base common ancestor, making manual selection much clearer.
Deal with binary files
Git cannot automatically merge binary files (like images or compiled assets). If two branches modify the same binary file, Git will report a conflict. In this case, you must manually choose which version to keep by copying the preferred file into the working directory, staging it, and committing/continuing.
# During a merge, keep the version from your current branch
git checkout --ours image.png
# Or keep the version from the branch being merged in
git checkout --theirs image.png
git add image.png
git commit
During a rebase, --ours and --theirs can feel reversed because Git is replaying commits onto a new base. Run git status, inspect the file, and confirm the chosen version before you stage it.
Takeaway
Do not try to "remove the conflict" by deleting markers blindly. Read both sides, decide what the final code should be, run the relevant tests, then stage the resolved files. After that, use git commit for a merge or git rebase --continue for a rebase.