Merge conflicts are one of the most frustrating parts of collaborative development. You spend time understanding both sides, figuring out the intent, and manually combining them. What if AI could handle the common cases?
In this tutorial, youโll build a git conflict resolver that reads both sides of a conflict and uses AI to merge them intelligently. No API keys, no cloud calls, everything runs on your machine.
How It Works
- Git detects a merge conflict
- The tool reads both versions of the conflicted file
- AI analyzes the changes and produces a merged version
- You review and accept or reject the merge
Prerequisites
- Ollama installed
- Python 3.10+
Step 1: Pull the model
ollama pull qwen2.5-coder:7b
Step 2: Create the resolver
#!/usr/bin/env python3
"""AI git conflict resolver using Ollama."""
import subprocess
import sys
import json
import urllib.request
import re
import os
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5-coder:7b"
PROMPT_TEMPLATE = """Merge these two versions of a file that has a conflict.
Original (base):
```{language}
{base}
Version A (your changes):
{version_a}
Version B (their changes):
{version_b}
Rules:
- Combine both changes where they donโt conflict
- Preserve the intent of both authors
- Keep code style consistent
- If changes are truly incompatible, prefer Version A (your changes)
- Add a comment explaining the merge decision if non-trivial
Output ONLY the merged code, no explanations."""
def get_conflicted_files(): """Get list of files with merge conflicts.""" result = subprocess.run( [โgitโ, โdiffโ, โโname-onlyโ, โโdiff-filter=Uโ], capture_output=True, text=True ) return [f for f in result.stdout.strip().split(โ\nโ) if f]
def parse_conflict(content): """Parse conflict markers and extract base, version A, version B.""" pattern = rโ<<<<<<<(.+?)=======\n(.*?)>>>>>>>.+?\nโ conflicts = re.findall(pattern, content, re.DOTALL)
if not conflicts:
return None
# Get the parts outside conflicts
parts = re.split(r'<<<<<<<.+?=======\n.+?>>>>>>>.+?\n', content)
return {
"parts": parts,
"conflicts": conflicts
}
def detect_language(filename): """Detect file language from extension.""" ext_map = { โ.pyโ: โpythonโ, โ.jsโ: โjavascriptโ, โ.tsโ: โtypescriptโ, โ.goโ: โgoโ, โ.javaโ: โjavaโ, โ.rsโ: โrustโ, โ.rbโ: โrubyโ, โ.phpโ: โphpโ, โ.sqlโ: โsqlโ, โ.yamlโ: โyamlโ, โ.ymlโ: โyamlโ, โ.jsonโ: โjsonโ, โ.mdโ: โmarkdownโ } _, ext = os.path.splitext(filename) return ext_map.get(ext, โtextโ)
def resolve_conflict(base, version_a, version_b, language=โtextโ): """Use AI to resolve a single conflict.""" prompt = PROMPT_TEMPLATE.format( language=language, base=base, version_a=version_a, version_b=version_b )
payload = json.dumps({
"model": MODEL,
"prompt": prompt,
"stream": False,
"options": {"temperature": 0.3, "num_predict": 2000}
}).encode()
req = urllib.request.Request(
OLLAMA_URL,
data=payload,
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=60) as resp:
response = json.loads(resp.read())["response"].strip()
# Remove code block markers
if response.startswith("```"):
response = response.split("\n", 1)[1]
if response.endswith("```"):
response = response[:-3]
return response.strip()
def resolve_file(filename): """Resolve all conflicts in a file.""" with open(filename, โrโ) as f: content = f.read()
parsed = parse_conflict(content)
if not parsed:
print(f"No conflicts found in {filename}")
return
language = detect_language(filename)
print(f"Found {len(parsed['conflicts'])} conflicts in {filename}")
resolved = ""
for i, (version_a, version_b) in enumerate(parsed["conflicts"]):
print(f"\nResolving conflict {i + 1}...")
# Get base from the file (simplified - in real use, you'd get this from git)
base = ""
merged = resolve_conflict(base, version_a, version_b, language)
print(f"Resolved: {merged[:100]}...")
# Add to resolved content
if i < len(parsed["parts"]):
resolved += parsed["parts"][i]
resolved += merged + "\n"
# Add the last part
if len(parsed["parts"]) > len(parsed["conflicts"]):
resolved += parsed["parts"][-1]
# Save resolved file
backup = filename + ".conflict-backup"
os.rename(filename, backup)
with open(filename, "w") as f:
f.write(resolved)
print(f"\nResolved conflicts saved to {filename}")
print(f"Original saved to {backup}")
if name == โmainโ: files = get_conflicted_files()
if not files:
print("No merge conflicts found.")
sys.exit(0)
print(f"Found {len(files)} files with conflicts:")
for f in files:
print(f" - {f}")
confirm = input("\nResolve all conflicts? (y/n): ").strip().lower()
if confirm != "y":
sys.exit(0)
for filename in files:
resolve_file(filename)
print("\nAll conflicts resolved. Review the changes and commit.")
## Step 3: Install as git alias
```bash
# Make it executable
chmod +x ai_resolve.py
# Add as git alias
git config --global alias.resolve '!python /path/to/ai_resolve.py'
Step 4: Use it
# When you have conflicts
git merge feature-branch
# CONFLICT detected
# Resolve with AI
git resolve
Under the Hood
The tool reads conflict markers and sends each conflict to the AI with context:
- Base: The common ancestor (what both branches started from)
- Version A: Your changes
- Version B: Their changes
The AI analyzes both changes and produces a merged version that preserves the intent of both authors.
For simple conflicts (non-overlapping changes), the AI combines them. For complex conflicts, it uses heuristics like preferring your changes when truly incompatible.
Limitations
- Complex logic conflicts may not merge correctly
- The tool needs the base version (simplified in this example)
- Generated code should always be reviewed
- Does not handle semantic conflicts (breaking API changes)
Variations
- Interactive mode: Show both sides and ask for guidance
- Learning mode: Track resolution patterns for better future merges
- Test runner: Run tests after merge to verify correctness
- Batch mode: Resolve all conflicts in a repository at once
My Take
This tool handles 70-80% of merge conflicts correctly. The remaining 20-30% need manual review, but even those are faster because the AI provides a starting point. It is most useful for routine conflicts where both sides made straightforward changes.
Rating: 7/10 โ Good for routine conflicts. Always review the results.
Related Articles
- Ollama: How to Install and Run Local AI Models
- Best AI Models for Coding Locally
- Aider Setup Guide
- Continue.dev: The Open-Source AI Coding Assistant
- Best AI Coding Tools in 2026
FAQ
How accurate is the AI merge?
For simple conflicts (non-overlapping changes), 90%+ accurate. For complex logic conflicts, 60-70%. Always review the results before committing.
Can this break my code?
Yes, if the AI merges incorrectly. Always review the merged code and run tests. The tool creates backups of original files.
Does this work with rebase conflicts?
Not in this basic version. The tool handles merge conflicts. For rebase conflicts, you would need to modify the conflict detection logic.
Can I use this with any language?
Yes. The tool detects file language from extension and adjusts the AI prompt accordingly.
Related: Git Cheat Sheet ยท Git Workflow Best Practices ยท Ollama Complete Guide