git: fatal: refusing to merge unrelated histories
Hi, it's BlueByte. If a pull just stopped with "refusing to merge unrelated histories", nothing is broken — Git is protecting you from accidentally stitching two unrelated projects together. Let's confirm the two sides really are the same project, then flip the one flag that allows it.
What the message means
A pull or merge stops with:
fatal: refusing to merge unrelated historiesThe two sides share no common ancestor. Git refuses because combining unrelated histories is usually a mistake — but when it is genuinely what you want, one flag allows it. This is a guardrail, not corruption.
Why the two histories have no common commit
Since Git 2.9, git merge and git pull refuse to combine histories with no commit in common. You hit it in a few recognizable situations:
- You ran
git initlocally, committed, then added a remote that already had its own initial commit. The two initial commits are unrelated. - You are merging two separate repositories into one.
- You force-created a branch with
--orphanand later tried to merge it back. - You re-created a repo from scratch (deleted
.git, rangit initagain) and then pulled the old remote, which now looks unrelated.
First, confirm both sides are the same project
Do not allow the merge blind — look at both logs and make sure they are the project you mean to combine:
git log --oneline -5 HEAD
git log --oneline -5 origin/mainIf the two logs are clearly the same project that simply started twice, the merge is safe to allow. If origin/main is a completely different project, stop — you are about to merge the wrong remote. You can also confirm there is genuinely no shared commit with git merge-base HEAD origin/main, which prints nothing when the histories are unrelated.
Allow the merge, once you're sure
Once you have confirmed the histories belong together, allow it explicitly:
git pull origin main --allow-unrelated-historiesor, if you already fetched:
git merge origin/main --allow-unrelated-historiesResolve any conflicts as usual, then commit. The two histories are now joined at a single merge commit.
A real case: a README on the remote
You created a project locally with git init, made three commits, then created an empty repo on the host — except the host added a README on creation, giving it its own initial commit. git pull origin main fails with "refusing to merge unrelated histories". git log on both sides shows the same project, just started twice, and git merge-base prints nothing, confirming no shared commit. You run git pull origin main --allow-unrelated-histories, resolve a trivial README conflict, and commit. The graph now shows one merge commit tying your three commits to the host's README commit.
Check the histories actually joined
Confirm the two lines came together and your files are all present:
git log --oneline --graph -8You should see one merge commit where the two histories meet, with both sides' commits reachable below it.
Keep it from coming up again
When you want a local folder to track an existing remote, clone the remote first and copy your files in, rather than git init + add-remote — that way there is one shared history from the start. When creating a remote you will push existing local history into, create it empty (no README).
How this differs from a merge conflict
This is not a merge conflict — conflicts happen after a merge starts, over specific lines. refusing to merge unrelated histories stops the merge from starting at all, because there is no common base to diff against. Once you have allowed it, ordinary conflict resolution takes over.
Related questions
Is --allow-unrelated-histories dangerous?
No, but it removes a guardrail. Use it only after you have checked that both sides are the project you mean to combine.
Why did this start happening in a new repo?
You committed locally after git init, then added a remote that already had its own initial commit. The two initial commits are unrelated.
I only want the remote's history, not my local commits.
Clone the remote fresh and copy your working files into it. That is cleaner than an unrelated-history merge you will later have to untangle.
Can I avoid the merge commit?
Not when joining unrelated histories — a merge commit is how the two roots are tied together. A rebase cannot replay onto a base that does not exist in your history.
How do I confirm the histories really are unrelated?
Run git merge-base HEAD origin/main. It prints a commit hash when there is a shared ancestor and nothing when the histories are truly unrelated.
References
Haneul Seo
Infrastructure engineer · 10+ years running Linux fleets
More in this category
Git: fatal: detected dubious ownership in repository
Since the CVE-2022-24765 fix in Git 2.35.2, Git refuses to read a repository whose working tree or .git directory is owned by a different user than the one running the command. It shows up in containers, CI jobs, sudo sessions and shared drives. Fix the ownership if the repo should be yours, or add the exact path to safe.directory in your global config — never in the repo's own config, which Git ignores for this.
Kubernetes: Internal error occurred: failed calling webhook
An admission webhook sits in front of your write, the API server could not get an answer out of it, and failurePolicy: Fail turned that silence into a rejection. The tail of the message is the whole diagnosis: context deadline exceeded means the call went nowhere, no endpoints available means nothing is running, and an x509 line means the API server does not trust the webhook's certificate. Each has a different fix, and none of them is your manifest.
MySQL: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
A statement waited the full innodb_lock_wait_timeout for a row lock another transaction is still holding, and gave up. sys.innodb_lock_waits names the blocking session and hands you the KILL statement, and a blocking_query of NULL means the blocker is idle on an open transaction. The detail most retry loops get wrong: by default only the timed-out statement is rolled back, so your transaction is still open and still holds every lock it took earlier.
Redis: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk
Reads keep working and every write is rejected, because the last background save failed and stop-writes-on-bgsave-error defaults to yes. The log names the real cause — no space, a dir the redis user can't write, a read-only mount at rename time, or fork failing with Cannot allocate memory. Fix the cause, run one BGSAVE, and writes come back on their own with no restart: rdb_last_bgsave_status flips from err to ok. Setting stop-writes-on-bgsave-error no restores writes instantly but leaves the snapshot broken, so treat it as a deliberate trade, not the fix.
Node.js: FATAL ERROR: Reached heap limit — JavaScript heap out of memory (exit 134)
The V8 heap has its own ceiling, derived from system memory and the Node release, and it is often far below the RAM you have; when a build or server reaches it, V8 aborts with FATAL ERROR: Reached heap limit and exit code 134. Read the real limit with v8.getHeapStatistics().heap_size_limit, then raise it with --max-old-space-size (in MiB) or NODE_OPTIONS for a large workload, size it below the cgroup limit inside containers, and use --heapsnapshot-near-heap-limit to catch a leak in a long-running process. Exit 137 with no FATAL ERROR line is a container kill, not this.
Docker: "exec format error" when the container starts — wrong-platform image, no emulator, or a script with no shebang
The container exits on its first instruction with exec format error — the kernel's ENOEXEC, meaning the file exists but cannot be executed here. In practice that is an image built on one CPU architecture (an Apple-silicon Mac produces linux/arm64) and run on another (an x86_64 server) with no QEMU handler registered in binfmt_misc, or an entrypoint script whose first line is not a shebang. uname -m, docker image inspect and ls /proc/sys/fs/binfmt_misc tell the causes apart; the fix is an explicit docker buildx build --platform (or a manifest list for both), QEMU registration or --platform when you mean to emulate, and a #!/bin/sh line for the script.