How to Resolve Git Merge Conflicts
If you’ve ever worked with Git for a while, chances are you've run into a merge conflict. It usually happens when your code and the upstream repository (the original project you forked from) don't agree on what should happen with a file.
Let’s walk through a real-world example where I had to resolve a "modify/delete" conflict, that's when the upstream project updates a file while you’ve deleted it in your branch.
TL;DR – Quick Fix for a Modify/Delete Conflict
git fetch upstream
git rebase upstream/master
# Fix conflict (file deleted locally, modified upstream)
git rm config/app.yml
git rebase --continue
git push origin rm-config --force-with-lease
Fixing a merge conflict
Step 1: Fetch the latest changes
git fetch upstream
This grabs the latest updates from the upstream repository without touching your local work. Think of it as just checking what's new before deciding what to do with it. Why not origin? Because origin is your fork which might be outdated, and we want to sync with the main source (upstream).
Step 2: Rebase onto upstream/master
git rebase upstream/master
Rebase basically takes your commits and replays them on top of the latest upstream version. The nice thing: you get a clean, linear history without those noisy merge commits. At this point, Git noticed a problem:
- Upstream: The file config/app.yml was modified
- Your branch: That same file was deleted
Git couldn't decide which version should win. That’s where you step in.
Step 3: Tell Git what you want
git rm config/app.yml
This command says: "Yes, I want this file gone, no matter what upstream did with it." Git then stages that deletion, resolving the conflict.
Step 4: Continue the rebase
git rebase --continue
Since rebase pauses whenever there's a conflict, you need to tell it when you are done fixing things. This continues the process until your branch is fully rebased.
Step 5: Push your changes
git push origin rm-config --force-with-lease
We are now pushing our changes back into our branch rm-config. --force-with-lease
is nice to have as, safely overwrites your branch, but only if nobody else has pushed new changes in the meantime
After a rebase, your commit history has changed. A normal push will fail this is why we need to push with force.