You ran git pull origin main expecting a nice fast-forward. Instead Git spit out fatal: refusing to merge unrelated histories and stopped cold. This happens because your local repo and the remote repo each have their own root commit — Git sees two completely separate trees with no common ancestor and refuses to stitch them together automatically. Since Git 2.9 (released mid-2016), this check is on by default. Before that, Git would happily merge anything and create a mess you'd regret.
The single most common trigger I see: someone creates a repo on GitHub with a README and .gitignore, then on their laptop runs git init, commits locally, and tries to push or pull. Two histories, zero overlap. Another common one: you copied a project folder from an old machine, initialized a fresh repo, and now you're trying to sync with the team's remote.
Cause 1: Local git init and remote repo were created independently
This is the one you're hitting 80% of the time. You did git init in a folder that already had files, made a commit, then pointed origin at a repo that already had its own first commit. The two root commits don't share a parent, so Git bails.
The real fix — and yes, it's a single flag — is --allow-unrelated-histories. Run this from your local branch:
git pull origin main --allow-unrelated-histories
After pressing Enter, Git will attempt a merge. If there are no file conflicts, you'll see something like Merge made by the 'recursive' strategy. and a new merge commit appears. Run git log --oneline --graph and you should see your local commits joined to the remote commits by a merge node at the top.
If files overlap (README, .gitignore, package.json — these collide constantly), Git will pause with conflict markers. Open each conflicted file, pick what you want to keep between the <<<<<<< and >>>>>>> markers, save, then:
git add .
git commit -m "Merge unrelated histories"
Then git push origin main. Done.
One thing people get wrong: they run the flag on git merge without first fetching. The remote ref has to exist locally before you can merge it. If git pull complains, do git fetch origin first, then git merge origin/main --allow-unrelated-histories.
Cause 2: You switched remotes or cloned the wrong repo into an existing directory
I've watched this one burn two engineers in a single afternoon. They had a working project, then a manager said "use the new corporate repo" and they ran git remote set-url origin git@github.com:neworg/project.git without thinking. The next git pull blew up because the new remote has a totally different history — new root commit, new everything.
Before you slap the flag on, stop and ask: do I actually want these histories combined? If the new repo is a fresh start, you probably don't. The cleaner move is to keep them separate:
git fetch origin
git checkout -b new-repo-main origin/main
You'll be on a branch tracking the new repo's main. From there, cherry-pick the commits you want from your old branch:
git cherry-pick <commit-sha>
After each cherry-pick, run git log --oneline -5 to confirm the commit landed. When you're happy, push the branch and open a PR. This keeps the new repo's history clean and avoids that ugly merge commit with seventeen parents.
If you do want them combined — say the new remote is just a continuation with a squashed initial import — then use the flag same as Cause 1. Just be honest about which situation you're in, because a bad merge is painful to unwind.
Cause 3: Orphan branch, template repo, or a squashed re-import
Orphan branches (git checkout --orphan) have no parent commit. So do repos created from GitHub template repos and projects that got rebuilt by a contractor who did git init and force-pushed. When you try to merge those with your existing branch, you get the same error for the same reason: no common ancestor.
If you're merging an orphan branch that lives in the same repo — a classic gh-pages setup — the fix is identical:
git checkout main
git merge gh-pages --allow-unrelated-histories
Expect a merge commit to appear. Verify with git log --oneline --graph --all. You'll see the orphan branch snap in via a new merge node.
If the histories are genuinely unrelated (a template repo you don't care about keeping history from), say so out loud before running the flag. In that case you're better off resetting to the remote:
git fetch origin
git reset --hard origin/main
Warning: git reset --hard throws away every uncommitted change in your working tree and moves your branch pointer. If you have anything unsaved, stash it first with git stash push -u or copy the folder to a backup location. I've seen this command eat a half-day of work because someone assumed it was reversible. It isn't, unless you remembered the SHA.
Quick-reference: which fix for which situation
| Situation | Command | Notes |
|---|---|---|
Local git init + remote with own commits |
git pull origin main --allow-unrelated-histories |
Resolve conflicts, then commit and push |
| Just switched to a new remote repo | git fetch origin && git checkout -b new-main origin/main |
Cherry-pick old commits instead of merging |
Orphan branch in same repo (e.g. gh-pages) |
git merge gh-pages --allow-unrelated-histories |
Merge commit is expected |
| Old history isn't worth keeping | git reset --hard origin/main |
Destroys uncommitted work — stash first |
| Remote ref not fetched yet | git fetch origin |
Do this before any merge command |
One more thing worth mentioning: a lot of GUI clients — GitHub Desktop, Sourcetree, older GitKraken versions — hide the --allow-unrelated-histories flag behind a checkbox or just don't expose it at all. If you're stuck in a GUI and the pull keeps failing with this error, drop to the terminal. It's not worth fighting the tool. Run the command, get your merge, go back to the GUI when it's done.
And before you run any of these on a branch you actually care about, tag the current state: git tag before-merge-$(date +%s). It costs one second and gives you a way back if the merge goes sideways. Every experienced engineer does this. Do it too.