Fix Git 'fatal: refusing to merge unrelated histories'
The Error
You run git pull or git merge and Git refuses:
fatal: refusing to merge unrelated histories
This typically happens when pulling from a remote into a local repository that was initialized independently, or when merging two branches that have no shared commit history.
Root Cause
Git tracks history as a directed acyclic graph (DAG) of commits. When two branches share a common ancestor commit, Git can compute a merge base and perform a three-way merge. When there is no common ancestor, Git considers the histories "unrelated" and refuses to merge by default.
This safety check was added in Git 2.9 to prevent accidental merges of completely separate projects. Common scenarios that trigger it:
- You created a local repo with
git init, added commits, then tried to pull from a remote that also has its own initial commit (e.g., GitHub created the repo with a README). - You are combining two separate repositories into one.
- A shallow clone lost the common history due to
--depthlimiting. - You re-initialized a repository (deleted
.gitand rangit initagain) and are now trying to pull the old remote.
Step-by-Step Fix
1. Understand what you are merging
Before forcing the merge, verify you are merging the right things:
git log --oneline -5
git log --oneline -5 origin/main
Confirm that these are genuinely related codebases you intend to combine, not completely unrelated projects.
2. Allow unrelated histories
Add the --allow-unrelated-histories flag:
# For pull
git pull origin main --allow-unrelated-histories
# For merge
git merge origin/main --allow-unrelated-histories
This tells Git to proceed with the merge even without a common ancestor. Git will treat each side's entire history as new changes.
3. Resolve merge conflicts
Since the histories are unrelated, you will likely have conflicts, especially in common files like README.md, .gitignore, or package.json:
# See which files conflict
git status
# Open and resolve each conflict
# Look for <<<<<<< HEAD markers
# After resolving
git add .
git commit -m "Merge remote history into local repository"
4. If you want the remote to completely replace local history
When your local commits are throwaway and you just want the remote content:
git fetch origin
git reset --hard origin/main
Warning: This discards all local commits and working directory changes.
5. For shallow clone issues
If a shallow clone caused the problem, deepen the history:
git fetch --unshallow origin
git pull origin main
Or if that is not possible, fetch with more depth:
git fetch --depth=1000 origin
git merge origin/main
6. The clean start approach
If the repository is in a messy state and you just want to start fresh from the remote:
cd ..
mv my-project my-project-backup
git clone [email protected]:user/my-project.git
# Copy over any local changes you need from the backup
Prevention Tips
- Do not initialize with a README on GitHub if you already have local commits. When creating a new repo on GitHub, leave it empty (no README, no .gitignore, no license) if you plan to push an existing local repo.
- Clone instead of init when a remote exists. If the repo already has history on a remote, use
git clonerather thangit initfollowed bygit remote add. - Avoid re-initializing repositories. If you need to fix a repo issue, almost everything can be resolved without deleting the
.gitdirectory. - Use
--depthcarefully. Shallow clones are useful for CI/CD but can cause merge issues. Use--unshallowwhen you need full history for merges.
Was this article helpful?
DevSecOps Lead
Security-first mindset in everything I ship. From zero-trust architectures to supply chain security, I make sure your pipeline doesn't become your weakest link.
Related Articles
Git Push Rejected: How To Fix "Updates Were Rejected Because The Remote Contains Work You Do Not Have"
You've seen this error. Everyone has. You try to push your changes and Git stops you cold: Here's your fast-track reference to diagnose and fix it. --- The...
Git Worktrees For Managing Multiple Feature Branches Simultaneously
Stop stashing. Stop context-switching. Git worktrees let you check out multiple branches simultaneously in separate directories — each with its own working...
Git Bisect: Find the Exact Commit That Broke Production
Use git bisect to binary-search through commit history and pinpoint the exact change that introduced a bug — manually or fully automated.
Git Commands: Cheat Sheet
Git commands cheat sheet for DevOps engineers — branching, rebasing, stashing, bisecting, cherry-picking, and recovery workflows with examples.
Helm Error: Release Has No Deployed Revisions - How To Recover Failed Installations
If you've been working with Helm for any length of time, you've probably encountered this frustrating error: "Error: release has no deployed revisions." It...
GCP Cloud Function "Function Execution Took Too Long" Error: Memory And Timeout Configuration Fix Guide
Getting the dreaded "Function execution took too long" error in your Cloud Functions? You're not alone. This error happens when your function exceeds the c...
More in Git
View all →Pre-Commit Hooks Framework for Automated Code Quality
Set up the pre-commit hooks framework to automatically enforce linting, formatting, and security checks before every Git commit.