merge-conflict-resolution
verifiedf47e8068-6fff-4bea-844d-c7d901b61b24
Use when resolving git merge conflicts — read conflict markers, understand ours/theirs/base, produce the correct merged result, then re-run tests for logic collisions.
Metadata
Skill file
# Merge Conflict Resolution
**Use when** git reports conflicts during a merge or rebase. The goal is not to pick a side — it's to produce the correct merged result, then verify no logic broke.
## Reading Conflict Markers
```text
<<<<<<< HEAD <- START of "ours" (the branch you're merging INTO)
return total * 1.08
======= <- SEPARATOR
return total * 0.08 # tax rate change
>>>>>>> feat/tax-update <- END of "theirs" (the branch being merged)
```
| Marker | Meaning |
|--------|---------|
| `<<<<<<< HEAD` | Current branch (yours) |
| `=======` | Split between the two |
| `>>>>>>> <branch>` | Incoming branch (theirs) |
### With rebase, ours/theirs flips
During `git rebase`, the meanings invert (the "ours" is the branch you're rebasing onto):
```text
# Merge: ours = current branch, theirs = incoming
# Rebase: ours = base branch (main), theirs = your commits
```
## The Resolve Flow
```bash
# 1. See what's conflicted
git status
# Unmerged paths:
# both modified: src/orders/pricing.py
# 2. Open the file and find all <<<<<<< markers
# 3. Edit to the CORRECT merged result (NOT just "ours")
# 4. Remove ALL markers
# 5. Stage the resolution
git add src/orders/pricing.py
# 6. Continue the merge/rebase
git merge --continue
# or
git rebase --continue
```
## The Correct Merged Result — Not Just "Ours"
The most common conflict mistake is auto-taking one side and losing the other's fix.
```text
# Scenario: two branches changed the same function for different reasons
# Ours (main): added a null check
# Theirs (feature): added tax calculation
# WRONG resolution (took ours, lost the tax):
def process(order):
if order is None:
return None
total = sum(order.items)
return total # <-- lost the * 1.08 tax
# CORRECT resolution (merged BOTH changes):
def process(order):
if order is None:
return None
total = sum(order.items)
return total * 1.08 # <-- kept BOTH the null check AND the tax
```
### The three-way reasoning
Ask: what did EACH side intend, and how do they combine?
```text
1. What did "ours" add/change? -> null check
2. What did "theirs" add/change? -> tax calculation
3. How do they combine? -> null check + tax calculation (both)
```
## Using a Merge Tool
```bash
# Open a visual 3-way merge tool
git mergetool
# Common tools: meld, vimdiff, pycharm, vscode
# VS Code: shows "Accept Current | Accept Incoming | Accept Both"
# Choose "Accept Both" when the changes are independent
```
## Post-Resolution: Check for Logic Collisions
Text resolution is not logic resolution. After resolving, the two changes may still collide logically:
```python
# Text resolved fine, but LOGIC collides:
# Ours added: validate(order)
# Theirs added: process(order) calls validate internally
# Now validate runs TWICE — text merged, logic broken
# Always re-read the merged region for semantic conflicts:
# - Same variable now computed twice
# - A check that should run before another now runs after
# - Duplicate function calls that weren't there before
```
```bash
# After resolution, run the full test suite
pytest tests/ -x
# And review the merged diff
git diff HEAD # or git diff --check for whitespace errors
```
## Aborting When You're Stuck
```bash
# If the conflict is more complex than expected, abort and re-approach
git merge --abort
# or
git rebase --abort
# Then try: merge in smaller pieces, or cherry-pick commits instead
```
## Guardrails
- **Never auto-take one side without understanding what the other side did.** You'll silently delete someone's fix.
- **Remove ALL conflict markers** (`<<<<<<<`, `=======`, `>>>>>>>`) — a leftover marker breaks the build.
- **Run tests after resolving.** Text resolution ≠ correct behavior.
- **Don't resolve conflicts while distracted.** Read each hunk and reason about both intents.
- `git diff --check` to catch whitespace errors and leftover markers.
## Pitfalls
| Pitfall | Fix |
|---------|-----|
| Auto-taking "ours" and losing their fix | Reason about both intents, merge correctly |
| Resolving text but breaking logic | Re-read merged region for semantic collisions |
| Leftover conflict markers | `grep -rn "<<<<<<<"` before committing |
| Forgetting to `git add` after edit | `git status` must show no "unmerged paths" |
| Forgetting `--continue` after staging | `git merge --continue` / `git rebase --continue` |
## Verify / Checklist
- [ ] All conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) removed
- [ ] Both sides' intent preserved (or explicit decision to drop one)
- [ ] `git status` shows no "unmerged paths"
- [ ] Full test suite passes (`pytest tests/ -x`)
- [ ] `git diff --check` clean (no whitespace errors)
- [ ] Merged region re-read for logic collisions (not just text)
Attached files
No attached files.