Merge conflicts are inevitable — or are they?
After 2 years of working on solo and team projects, I've learned that most merge conflicts aren't random accidents. They follow predictable patterns, and most can be prevented with the right workflow.
Here are 7 workflows I use that have reduced my merge conflicts by ~90%.
1. Trunk-Based Development with Short-Lived Branches
The longer a branch lives, the more likely it drifts from main. My rule: no branch survives more than 2 days.
# Create and switch to a short-lived branch
git checkout -b feature/user-auth
# Do your work, commit, push, merge — all within hours
Short branches mean less divergence. Less divergence = fewer conflicts.
2. Feature Flags Instead of Long-Running Branches
Instead of branching for weeks while a feature is half-built, use feature flags:
// In your app
if (featureFlags.isEnabled('new-dashboard')) {
return <NewDashboard />
}
return <LegacyDashboard />
This lets you merge incomplete features to main safely. No one sees the work-in-progress, but your branch stays current with main.
3. Commit Early, Commit Often
Large, infrequent commits are the #1 cause of painful merge conflicts. Break work into atomic commits:
# Bad: One massive commit after hours of work
git add .
git commit -m "implemented user auth"
# Good: Small, focused commits
git commit -m "add User model with email validation"
git commit -m "add login endpoint with JWT"
git commit -m "add auth middleware to protected routes"
When conflicts DO happen with small commits, they're trivially resolvable.
4. Pull (Rebase) Before Pushing
This is the single most impactful habit:
# Always rebase before pushing
git fetch origin
git rebase origin/main
# Now resolve any conflicts locally (clean state)
# Then push
git push origin feature/user-auth
Rebasing keeps a linear history and makes conflict resolution happen in YOUR branch, not in the merge commit.
5. Use .gitattributes for File-Specific Merge Strategies
Some files should NEVER be auto-merged:
# .gitattributes
package-lock.json merge=ours
*.min.js merge=ours
*.generated.css merge=ours
yarn.lock merge=ours
With merge=ours, Git always keeps your version during conflicts. Perfect for lock files and generated assets.
6. The "Squash and Merge" Team Convention
For team projects, agree on squash-and-merge for feature branches:
# On the feature branch
git rebase -i origin/main
# Squash all commits into one
# Then merge with --no-ff for a clean history
git merge --no-ff --squash feature/user-auth
This keeps main's history clean and prevents "octopus merge" conflicts.
7. Pre-Merge Conflict Check Script
I automated conflict detection with a pre-push hook:
#!/bin/bash
# .git/hooks/pre-push
# Check for conflicts before pushing
git fetch origin
CONFLICTS=$(git diff --name-only --diff-filter=U origin/main HEAD 2>/dev/null)
if [ -n "$CONFLICTS" ]; then
echo "⚠️ Potential conflicts in:"
echo "$CONFLICTS"
echo "Consider rebasing before pushing."
exit 1
fi
exit 0
This catches potential conflicts BEFORE they reach the remote.
The Bigger Picture
These workflows aren't just about avoiding merge conflicts — they're about building a disciplined development practice. The same discipline applies to everything: CI/CD pipelines, deployment strategies, and even how you organize your project structure.
If you're serious about leveling up your Git skills, I put together a comprehensive toolkit with 200+ commands, workflows, and real-world scenarios. It covers everything from basic branching to advanced rebasing strategies: The Complete Git & GitHub Power User Toolkit.
And if you're looking to automate more of your dev workflow, I maintain a collection of 68 free browser tools — JSON formatters, regex testers, color pickers, and more. All client-side, no signup required.
What Git workflows have saved you from merge conflict hell? I'd love to hear your strategies.
If you found this useful, follow me for more practical dev content. I write about tools, workflows, and productivity for solo developers and small teams.
Top comments (0)