Skip to main content
DevOps Insightsguides & answers

Git · troubleshooting

fatal: refusing to merge unrelated histories

The two branches share no commit at all, so Git cannot tell what changed on each side and refuses rather than guess. Usually a repository was created on the host with a README while the project was started locally; sometimes a shallow clone simply cannot see the shared history. Rebase onto the remote, or fetch the missing history. --allow-unrelated-histories is for the rare deliberate merge of two separate projects.

Reproduced on Git 2.50, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • A clean working tree, or your changes committed or stashed, before you pull, merge or rebase.
  • Read access to the remote, so git fetch can bring its history in for you to look at first.
  • Agreement from the other people on the branch before you push a history they did not start from.

Run this first

step 1 of 4
git fetch origin && git merge-base HEAD origin/<branch>

Look for No output (exit status 1)

Confirms there is no common commit on disk. If this prints a hash, the error came from a different pair of refs than you think.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Is this a shallow clone?

git rev-parse --is-shallow-repository

Cause space

4 of 4 still possible

  • The repository was created with its own first commitCommon
  • A shallow clone cannot see the history both sides shareOccasional
  • The remote points at a different repositoryOccasional
  • You really are combining two separate projectsRare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    git fetch origin && git merge-base HEAD origin/<branch>

    Confirms there is no common commit on disk. If this prints a hash, the error came from a different pair of refs than you think.

    Look for No output (exit status 1)

  2. Step 2

    git rev-parse --is-shallow-repository

    Separates missing history from unrelated history before you change anything.

    Look for true means fetch more history first; false means the histories really are separate

  3. Step 3

    git rev-list --max-parents=0 HEAD origin/<branch>

    Lists the root commit of each side, which shows where each history began.

    Look for A host-made initial commit on one side and your first commit on the other

  4. Step 4

    git remote -v && git log --oneline -5 origin/<branch>

    Rules out pulling from the wrong repository or branch.

    Look for The URL and the commits of the project you meant

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The repository was created with its own first commit

Common

You started the project locally, then created the repository on GitHub, GitLab or Bitbucket with a README, licence or .gitignore. The host made a first commit, your machine made another, and neither history contains the other. This is the usual way to meet the error, on the first pull after adding the remote.

Confirm

git fetch origin && git rev-list --max-parents=0 HEAD origin/<branch>

Two different commit hashes, one being the host's initial commit (often titled Initial commit) and the other your first local commit

Fix

  • Rebase your commits onto the remote's. Your work ends up after the host's first commit in one straight history, with no merge commit and nothing to force.
  • If both sides added the same file, usually README.md, the rebase stops on that file. Keep the content you want, git add it and git rebase --continue.
  • Push normally afterwards. The remote's commit is now an ancestor of yours, so it is a fast-forward.
git fetch origin
git log --oneline origin/<branch>
git rebase origin/<branch>
git push -u origin <branch>

Check the log first: it should show only what the host created. git pull --rebase origin <branch> does the fetch and rebase in one step. Reproduced on Git 2.50: the rebase succeeded and left a single root commit.

A shallow clone cannot see the history both sides share

Occasional

A clone or fetch with --depth keeps only recent commits. If the branch you pull moved on after your shallow fetch, the commit both sides share may be older than anything on disk, so Git sees no common ancestor even though one exists on the server. CI checkouts are the usual place, because they clone shallow by default on several platforms.

Confirm

git rev-parse --is-shallow-repository && git merge-base HEAD origin/<branch>

true, followed by no merge base. A shallow repository with no merge base points to missing history rather than unrelated projects

Fix

  • Fetch the missing history, then pull or merge again. Nothing about how you merge needs to change.
  • In CI, fetch deep enough to reach the merge base, or fetch full history for jobs that merge or compare branches.
  • Do not add --allow-unrelated-histories here. The histories are related; the shared part is just not downloaded, and forcing the merge creates a confusing parallel history.
git fetch --unshallow origin
git merge-base HEAD origin/<branch>
git pull --no-rebase origin <branch>

Reproduced on Git 2.50: after a depth-1 clone and depth-1 fetch, git merge-base found nothing and the pull refused; after --unshallow the merge base was found and the pull merged normally.

The remote points at a different repository

Occasional

The URL for origin, or the branch you named, belongs to another project: a copy-paste from the wrong repository page, a template repository, or a fork of something else. The histories really are unrelated, and merging them would combine two projects.

Confirm

git remote -v && git log --oneline -5 origin/<branch>

A URL or a set of commits you do not recognise as this project

Fix

  • Point origin at the right repository with git remote set-url origin <url>, then fetch and try again.
  • If you pulled the wrong branch name, pull the right one. Nothing has changed locally, because the refusal stopped before any merge.

You really are combining two separate projects

Rare

Bringing one repository into another while keeping both histories, for example when consolidating two repositories into one. This is the case the option exists for.

Confirm

git log --oneline origin/<branch> | tail -3

The other project's own early history, which you intend to keep

Fix

  • Merge with --allow-unrelated-histories, once, on the command line. Expect add/add conflicts on files both projects have, such as README.md and .gitignore.
  • Consider moving one project into a subdirectory first, so the two do not collide file by file.
  • Do not add the option to an alias or a script. git-merge describes this as a rare occasion, and no configuration variable exists to make it the default.
git merge --allow-unrelated-histories origin/<branch>

Reproduced on Git 2.50: with README.md on both sides this stopped with CONFLICT (add/add). Resolve, git add, then git commit.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Every Git merge starts from the last commit both sides have in common. Here there is none: the history you are pulling and the history you have began separately. Git stops instead of merging two unrelated projects into one. The usual cause is starting a project on your computer while the repository on GitHub or GitLab was created with its own first commit.

A repository created with a README, and a project started locally

Reproduced with Git 2.50.1 (Apple Git-155) on macOS: a local bare repository standing in for GitHub, given a first commit containing README.md as a host does when you tick “Add a README”, and a separate local project with its own first commit. Global and system config were switched off, so no pull setting was configured.

Command

git remote add origin <url>
git pull origin main
git pull --no-rebase origin main
git merge-base HEAD origin/main

Output

$ git pull origin main
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> origin/main
hint: You have divergent branches and need to specify how to reconcile them.
...
fatal: Need to specify how to reconcile divergent branches.

$ git pull --no-rebase origin main
 * branch            main       -> FETCH_HEAD
fatal: refusing to merge unrelated histories

$ git merge-base HEAD origin/main
$ echo $?
1

How to read it

  • With no pull.rebase setting, current Git stops first at Need to specify how to reconcile divergent branches. The unrelated-histories refusal appears once you choose a merge, with --no-rebase or git merge origin/main.
  • git merge-base printed nothing and exited 1: there is no common commit. That is the whole cause.
  • git push origin main at this point was rejected as non-fast-forward, for the same reason.
  • git pull --rebase origin main succeeded: it replayed the local commit on top of the README commit, leaving one straight history with a single root.
  • In a project that also had a README.md, git merge --allow-unrelated-histories origin/main stopped with CONFLICT (add/add): Merge conflict in README.md: both sides added the file, and with no ancestor there is no original version to compare against.

Words used on this page

Common ancestor (merge base)
The most recent commit both branches contain. A merge compares each side against it to work out what changed. git merge-base prints it.
Root commit
A commit with no parent: the first commit of a history. Unrelated histories each have their own.
Unrelated histories
Two branches with no commit in common, typically because each started from its own root commit.
Shallow clone
A clone made with --depth, which leaves out older commits. A common ancestor may be among the commits it left out.
--allow-unrelated-histories
An option to git merge (and git pull, which passes it through) that merges anyway, with nothing in common to compare against.
Rebase
Replaying your commits on top of another branch's tip. It needs no common ancestor, so it works where a merge refuses.
What is actually happening

A merge is three-way: Git finds the newest commit both sides share and compares each side against it. When git merge-base finds no such commit, there is nothing to compare against, so every file on both sides looks newly added.

Before Git 2.9 such merges went through silently. The release notes describe why that changed: a brand-new history of an existing project got pulled by an unsuspecting maintainer, merging an unnecessary parallel history into it. The refusal is that lesson made the default, and the git-merge documentation says no setting to turn it off exists or will be added.

The causes differ, and so do the fixes. Two projects that genuinely started separately, usually a host-created first commit and a local one, need to become one history, and rebasing your commits onto the remote does that without a merge commit. A shallow clone has the shared history on the server but not on disk, so fetching it is the fix and nothing needs merging differently. A remote that points at the wrong repository needs the URL corrected.

On current Git a plain git pull with no pull.rebase setting stops earlier, at Need to specify how to reconcile divergent branches. The two messages often come one after the other: you choose merge, then meet this one.

How to tell this is your problem
WhereWhat you see
git pull or git merge outputfatal: refusing to merge unrelated histories
git merge-base HEAD origin/<branch>No output, exit status 1
git rev-list --max-parents=0 HEAD origin/<branch>Two different root commits, one per history
git push output! [rejected] main -> main (non-fast-forward), before any pull has been attempted

How to know it is actually fixed

  • git merge-base HEAD origin/<branch> now prints a commit.
  • git status reports the branch up to date with, or ahead of, its upstream rather than diverged.
  • git push succeeds without --force.
  • git rev-list --max-parents=0 HEAD shows the number of root commits you expect: one after a rebase, two only after a deliberate combination.

Stopping it happening again

  • When the project already exists locally, create the repository on the host empty: no README, licence or .gitignore. Then add the remote and push.
  • Or clone the new host repository first and copy the project into it, so there is only one history from the start.
  • Set a pull policy, for example git config --global pull.rebase true, so git pull does something predictable rather than stopping to ask.
  • In CI jobs that merge or compare branches, fetch enough history to reach the merge base.

Security considerations

  • Look at what you are about to merge in with git log origin/<branch> first. An unrelated history is, by definition, code your branch has never contained.
  • Git refuses this by default precisely because a brand-new history of an existing project once got merged in unnoticed (Git 2.9 release notes). Adding --allow-unrelated-histories to a script or alias removes that check from every future merge.
  • Never fix this by force-pushing your local history over the remote. Whatever the remote held, a host-generated README or a colleague's work, is gone for everyone.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it