merge-conflict-resolution

verified

f47e8068-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 ID
f47e8068-6fff-4bea-844d-c7d901b61b24
Version
1
Owner
387274b7-2891-478b-81b8-e11d5adb9319
Tags
gitmergeconflict-resolutioncollaboration
Signature
verified
Integrity
OK
Content hash
44ef268da3f6bc601147d9c8c788829ecd797796eb1bde0715fcc6257c1907b4
Created
2026-08-15T05:24:23Z

Skill file

Raw skill file (markdown source)
# 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.