DEV Community

Cover image for How to resolve merge conflicts in Git without guessing: markers, --ours/--theirs and the rebase flip

How to resolve merge conflicts in Git without guessing: markers, --ours/--theirs and the rebase flip

DevOps Daily on October 08, 2026

You are rebasing your branch onto main. Git stops on a conflict in limits.py. You want to keep your version, so you type git checkout --ours limits...
Collapse
 
systemcraftdev profile image
SystemCraftDev •

The three-versions framing is the key idea, and the rebase flip is the one that bites people in practice.

A related tip for the "which increase wins" question from lesson 1: during a merge, git log --merge -- config.yaml lists just the commits from each side that touched the conflicted file, so you can read why main went to 45 and why the feature branch went to 60 before choosing. Without it, people often resolve from the markers alone, without knowing what either side intended.

It only works for merges (it errors with "--merge without MERGE_HEAD?" mid-rebase). In a rebase, git show REBASE_HEAD shows the commit currently being replayed, which is the "theirs" side.

On newer Git, git restore --theirs <file> does the same job as git checkout --theirs <file> with a clearer name.

Collapse
 
devopsdaily profile image
DevOps Daily •

great additions! checking the commit history before resolving is such an underrated habit 👌

Collapse
 
alexcodebytes profile image
Oleksandr •

Merge conflicts in config.yaml are the ultimate test of developer patience. Most people just blindly click 'Accept Ours' or 'Accept Theirs' and hope the CI/CD pipeline doesn't catch fire, so learning about :1:config.yaml is a lifesaver.

Collapse
 
devopsdaily profile image
DevOps Daily •

haha exactly! accepting ours/theirs blindly is basically gambling with your config 😄

Collapse
 
alexcodebytes profile image
Oleksandr •

100%. Blindly hitting --ours on a config file is the fastest way to corporate roulette. You think you just saved a couple of minutes, but then three hours later the staging environment completely implodes because a single environment variable dropped out of existence. Manually auditing line-by-line is painful, but it's the only way to sleep peacefully at night.

Collapse
 
marcusykim profile image
Marcus Kim •

I'd extend lesson 6 with a test that asserts the worker's timeout value, not just that get_request_timeout() exists. Renames are an easy failure to spot; a clean merge that leaves the worker using the old default can pass a smoke test. That gives learners two distinct checks: does the merged code run, and does it still enforce the behavior both branches intended?

Collapse
 
devopsdaily profile image
DevOps Daily •

great point! a clean merge doesn't always mean correct behavior. testing the actual value is a nice addition!

Collapse
 
mrsaynothing profile image
Mr Say Nothing •

The flip deserves the emphasis you gave it: a resolve script that says --ours breaks silently the day someone runs it mid-rebase, because ours is now the other branch. We added a guard that reads the rebase state before any scripted resolution runs — cheap insurance against a keyword that changes sides.

Collapse
 
devopsdaily profile image
DevOps Daily •

that's a smart guard to have! especially when resolution scripts are automated 👌

Collapse
 
bobbyiliev profile image
Bobby •

one thing that helped me a lot was using git diff --check after resolving conflicts. it's surprisingly easy to leave something broken even when all the conflict markers are gone 😅

Collapse
 
devopsdaily profile image
DevOps Daily •

good tip!

Collapse
 
nark3d profile image
Adam Lewis •

Which rule applies when the conflict is real, as in both sides changed the same function and neither is a superset of the other? Taking --ours or --theirs there commits a silent regression. The only way out is reading both edits and rebuilding the intent by hand. Does the post treat that as a separate case, or does it fold it in with the mechanical ones?