Home › DevOps › Git Unrelated Histories: Fix Refused Merge
Intermediate 5 min · September 23, 2026

Git Unrelated Histories: Fix Refused Merge

Merge with git pull --allow-unrelated-histories, then resolve everything once.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
✓ Production
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
Before you start⏱ 11 min
  • ✓Git installed with init, clone, and remote basics down
  • ✓A test repo plus an empty remote you can seed and delete freely
  • ✓Comfort reading git log --graph and resolving a text conflict
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • 'Refusing to merge unrelated histories' means your local repo and the remote share no common ancestor commit, so Git won't guess how to join them
  • The classic trigger is git init locally plus a remote created with a README, license, or .gitignore that seeded its own first commit
  • Fix it deliberately with git pull origin main --allow-unrelated-histories, then resolve every conflicted file and commit the join
  • Don't use the flag blindly: if one side is nearly empty, recloning or pushing your history is cleaner than a confusing forever-merge
✦ Definition~90s read
What is Git Unrelated Histories Merge Fix?

The unrelated-histories refusal is Git's merge-base guard: a merge needs the newest commit both sides descend from, and independent roots have none. Every commit except a root has parents, so ancestry-walking from both tips normally converges. With two roots the walks terminate separately, and since Git 2.9 the merge machinery declines to proceed rather than diff two full trees against nothing.

★
Imagine two families who both happen to be named Smith and someone suggests merging their family trees.

The refusal text names the flag that overrides it, which many engineers read as instructions rather than as a gated override.

The flag's mechanism is an empty-tree synthetic base. Both trees diff as pure additions, so the merge result is their union and every same-path file becomes an add/add conflict. This is honest behavior for genuinely parallel histories — two teams scaffolding one service — and hazardous behavior for accidents like wrong-URL merges, where it happily unions strangers.

Nothing about the flag validates intent; it only changes the base.

What this is NOT: it isn't an auth error, a corrupt clone, or a wrong URL by itself (though a wrong URL can cause it). It also isn't fixed by fetching harder — no amount of object transfer creates a shared ancestor. And it isn't a rebase problem; rebasing onto an unrelated tip hits the same missing-base wall.

Think of it as a genealogy complaint: Git won't file two family trees under one cover until a human confirms they're one family, and even then it staples rather than grafts.

Plain-English First

Imagine two families who both happen to be named Smith and someone suggests merging their family trees. The software refuses, because neither tree shares a grandparent — grafting them together would invent a shared past that never existed. Git does the same with two repos that started life separately. You can still staple the trees together with a special flag, but you should first check whether one tree is nearly empty and simpler to regrow from the other.

You initialized a repo, added the remote, ran git pull — and Git slapped your hand: 'refusing to merge unrelated histories'. Your URL is right. Your credentials work. The problem is ancestry: your local history and the remote's history start from different root commits with no shared past, and since Git 2.9 the default is to refuse joining them rather than invent a merge base that doesn't exist.

The standard setup that produces this is painfully ordinary. You ran git init, committed your project, and connected a GitHub repo you created with 'Add a README' checked. That checkbox created a first commit on the server. Now both sides have a root commit, neither descends from the other, and pull has nothing to stand on. The same thing happens when you merge two long-separate projects, vendor a library's repo into yours, or point an old checkout at a freshly re-created remote.

The fix is a deliberate override: --allow-unrelated-histories tells Git to use an empty tree as the fake common ancestor and merge everything. That works, but it merges every file both sides ever created, so you must decide when the flag is right and when a reclone or a fresh push is cleaner. This guide shows you how to diagnose independent roots, apply the flag safely, resolve the resulting join, and choose the alternative that keeps history honest.

What 'Unrelated Histories' Means Under the Hood

Every Git merge needs a merge base: the newest commit both sides descend from, used as the reference for deciding what changed. Normal merges walk both histories back until the lines meet. With unrelated histories the walk never converges — each side reaches its own root commit, a commit with no parents, without ever meeting the other line. Since Git 2.9 the default response is refusal, because diffing two trees against nothing produces an 'everything is new on both sides' result that no algorithm should apply unsupervised.

The --allow-unrelated-histories flag supplies a synthetic base: the empty tree. Both sides' full contents then count as additions against nothing, which is why the merge touches every file and overlapping paths become add/add conflicts. Understanding this predicts the blast radius before you run it. Two roots with ten shared filenames means ten conflicts minimum, and a template-seeded remote against a mature project means conflicts across the entire skeleton.

Check roots directly with git rev-list --max-parents=0 HEAD for your side and the same against origin/main for theirs. Different hashes confirm independence. This thirty-second check separates 'I need the flag' from 'I need a different strategy' and is the cheapest diagnosis in the whole article.

📊 Production Insight
A platform team once aliased pull to always include the flag to 'stop the annoying error'. Three months later a misconfigured remote URL merged a completely different service's repo into a payments repo, and the alias made it succeed silently. The alias was deleted that day. Overrides that bypass safety checks should be typed deliberately, never defaulted.
🎯 Key Takeaway
No shared root means no merge base, so Git refuses rather than guessing. The flag substitutes an empty tree, turning the merge into a full union of both sides. Inspect roots first.

The Classic Collision: Local Init Meets Seeded Remote

The number-one factory for this error is the GitHub 'Add a README file' checkbox. You build a project locally, init, commit, then create the remote with seed files checked. The server mints its own root commit containing README, LICENSE, and .gitignore. Your git remote add plus git pull then faces two roots, and the refusal follows instantly. The same happens with GitLab's 'Initialize with README' and any template-based repo creation.

You have three exits, and the right one depends on what the remote holds. If the remote is only seeds, the cleanest path is cloning fresh and copying your project files over the seed skeleton — two minutes, no merge, history starts from the remote root honestly. If your local history matters (existing commits, branches, tags), push it to a truly empty remote instead: create the remote with no seeds, or delete the seed commit's branch content first.

Reach for the flag only when both sides hold real work you must union. That happens with genuinely parallel starts — two engineers scaffolding the same service over a weekend — or when policy forbids rewriting either side. In that case the merge is real work: resolve every add/add conflict thoughtfully, write a merge message explaining the two roots, and review the union before pushing.

fix-seeded-remote.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Diagnose: list the root commits on each side (different hashes = unrelated)
git rev-list --max-parents=0 HEAD
git fetch origin
git rev-list --max-parents=0 origin/main

# Option A (cleanest when remote holds only seeds): start from the remote
# (copy your project files over a fresh clone, commit, push)
git clone <remote-url> fresh-start
cp -r my-project/* fresh-start/

# Option B: keep local history, push to a truly empty remote
# (create the remote with NO readme/license seeds, then)
git remote set-url origin <empty-remote-url>
git push -u origin main

# Option C: both sides hold real work — deliberate union merge
# (resolve every conflict, review the full diff, then push)
git pull origin main --allow-unrelated-histories
📊 Production Insight
Onboarding data from one consultancy showed this exact collision hitting roughly a third of new hires pushing their first exercise repo. The fix that stuck was a one-line runbook change: 'create remotes empty, uncheck every seed box.' First-week support tickets about Git dropped by half the next cohort.
🎯 Key Takeaway
Seed checkboxes manufacture the second root. Reclone when the remote is only seeds, push to an empty remote to keep local history, and save the flag for genuine two-sided work.

Using the Flag Without Regretting It

When the union is genuinely wanted, run the merge with intent, not haste. git pull origin main --allow-unrelated-histories fetches and immediately opens the join. Overlapping paths stop as add/add conflicts — both sides added the file from nothing, so Git can't prefer either. Open each one, compose the correct surviving content (often theirs-plus-yours, sometimes a full rewrite), stage it, and finish with a merge message that names both roots and explains why they joined.

Scale determines sanity. A dozen conflicts you can read carefully is a fine merge. Hundreds of conflicts is evidence you're unioning two projects, and no human reviews that faithfully — abort and pick reclone or subtree instead. After completing the join, inspect git show --stat HEAD and read the full diff of every conflicted file before pushing. The merge commit is the last checkpoint where the union is reviewable as one unit.

Push the result through a pull request, not directly. Reviewers see the join commit's combined diff and can spot duplicated trees, lost files, or wrong-side resolutions. The docs incident in this article would have been a five-minute review catch instead of a three-day duplication cleanup if the merge had faced one reviewer.

union-merge-safely.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Deliberate union: fetch, merge with the flag, resolve everything
# (run only after confirming BOTH sides hold real work worth joining)
git fetch origin
git merge origin/main --allow-unrelated-histories -m "Join local scaffold with seeded remote roots"

# Add/add conflicts on every overlapping path: inspect each, compose survivors
# (repeat per file until no unmerged paths remain)
git status --short | grep '^UU'
git add <resolved-file>

# Review the union as one unit BEFORE publishing (last checkpoint)
# (stat for shape, full diff for content)
git show --stat HEAD
git diff HEAD~1 HEAD -- <resolved-file>

# Publish through review, not direct push, whenever the branch is shared
# (direct push only for personal branches)
git push origin HEAD
⚠ Count conflicts before resolving them
A dozen conflicts is a merge. Hundreds is two projects colliding — abort with git merge --abort and choose reclone or subtree instead. Nobody faithfully reviews a 400-file union.
📊 Production Insight
The docs team measured the aftermath: 200 duplicated pages, 3 days live, plus redirect rules maintained to this day. The merge itself took 4 minutes. Unrelated-history joins are the clearest case in Git where review time should scale with the diff, not the command count.
🎯 Key Takeaway
Resolve every add/add conflict deliberately, review the union diff as one unit, and publish shared joins through pull requests. Abort and reclone when conflicts number in the hundreds.

When to Reclone Instead of Merging

Recloning is the honest fix whenever one side's history carries no value worth preserving in the join. Remote holds only template seeds? Clone it, copy your files in, commit once, push. Local repo is three scaffold commits and the remote holds the team's month of work? Clone the remote and port your changes over. In both cases the result is a single-root history anyone can understand, with no synthetic merge base and no phantom conflicts.

The procedure protects your work first: branch or copy your current state aside before deleting anything, so the 'losing' side remains recoverable. Then verify the fresh clone builds and tests pass before porting — there's no point grafting good work onto a broken base. Port changes as files plus a clean commit, or cherry-pick specific commits if the losing side held work worth attributing.

Choose this path aggressively for first-push collisions, tutorial repos, and template starts. The flag exists for histories that both matter. Most unrelated-history encounters in practice involve one side that doesn't, and a ten-minute reclone beats a permanent confusing root-merge that every future git log reader must puzzle over. Future you, reading log --graph at midnight, will thank present you for the clean single line.

reclone-instead.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Preserve the 'losing' side first: branch it so nothing is unrecoverable
# (run inside the old repo before touching anything)
git branch backup-before-reclone

# Fresh start from the side that wins (usually the seeded remote)
# (verify it builds BEFORE porting your work onto it)
git clone <remote-url> fresh-start
npm test

# Port your files over, keeping the remote's skeleton where it matters
# (copy project files; reconcile README/LICENSE deliberately, not blindly)
cp -r ../my-project/src fresh-start/src
git status --short

# Single honest commit on one root, then push normally
# (no flags, no synthetic merges, no phantom conflicts)
git add -A
git commit -m "Add project files onto remote skeleton"
git push -u origin main
📊 Production Insight
A contractor billed 6 hours resolving a 300-conflict unrelated merge that a reclone would have settled in 15 minutes — the remote was pure template. The invoice sparked a team rule now posted above every workstation: 'seeds versus work? reclone.' Consultants love billable merges; your team shouldn't fund them.
🎯 Key Takeaway
Reclone when one side is seeds, scaffolding, or disposable. Preserve the loser on a backup branch, verify the winner builds, port deliberately, and keep history single-rooted.

Subtree and Submodule: Better Joins for Vendored Code

Joining a library's repo into yours is the one case where independent roots are expected — and raw unrelated merges are still the worst tool for it. git subtree add --prefix=vendor/lib records the join with the prefix boundary intact, so future library updates merge cleanly and git log -- vendor/lib shows the vendored history sensibly. Submodules go further, keeping the library as a separate repo pinned by hash, which suits dependencies that evolve independently.

Compare that with a flag merge: the library's files scatter into your tree with no recorded boundary, future updates have no clean merge path, and history archaeology can't distinguish your code from theirs. The five minutes subtree costs upfront repays itself at the first library update, when git subtree pull --prefix=vendor/lib just works while the raw-merge team hand-resolves the same files again.

Decide by coupling. Tightly coupled code you edit alongside your own belongs in your tree via subtree. Independently versioned dependencies you never edit belong in submodules. Neither belongs in a bare unrelated merge — that option combines the permanence of vendoring with the traceability of nothing. Write the choice into your dependency policy so the next vendor addition starts from the right tool instead of rediscovering this lesson.

vendor-with-subtree.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Recorded join: library lands under vendor/lib with its history intact
# (preferred over a bare unrelated merge for vendored code)
git subtree add --prefix=vendor/lib <library-url> main --squash

# Future library updates merge along the recorded boundary
# (this is what raw flag-merges cannot do cleanly)
git subtree pull --prefix=vendor/lib <library-url> main --squash

# Independent dependency you never edit? Pin it instead of merging it
# (keeps the library a separate repo referenced by hash)
git submodule add <library-url> vendor/lib

# Inspect the join: boundary visible, histories traceable per side
# (compare with a flag-merge, where no boundary exists)
git log --oneline --graph -6
git log --oneline -- vendor/lib | head -5
📊 Production Insight
A team that vendored an auth library via flag-merge spent two full days hand-applying a security patch, unable to merge upstream because no boundary existed. Their sister team on subtree pulled the same patch in one command. The post-mortem mandated subtree-or-submodule for all vendoring, no exceptions.
🎯 Key Takeaway
Subtree records the vendor boundary for clean future updates; submodules pin independent deps by hash. Bare unrelated merges give you vendoring's permanence with none of its traceability.

Stop Manufacturing Second Roots

Every prevention here is a creation-time habit. Create remotes empty when you'll push existing code — uncheck README, license, and .gitignore seeds on every host. When the remote must carry template files, clone first and build inside the clone so your first commit descends from the remote root honestly. For migrations and re-creations, retire the old remote's URL rather than reusing it under a fresh repo, so stale clones never face a stranger root.

Add the diagnosis to team runbooks: rev-list roots on both sides before any flag use, and require pull-request review for every unrelated join on shared branches. A thirty-second root check plus one reviewer eliminates both the accidental unions and the unreviewed ones.

Finally, never normalize the flag. Don't alias it into pull, don't document it as 'the fix for first pull', and don't teach it before teaching reclone. It's a precision instrument for genuine two-root joins — rare, deliberate, and reviewed. Teams that treat it as routine eventually union something they never meant to, and discover it from users rather than from Git. Keep the guardrail loud and the override quiet. A team that reviews its Git runbook quarterly keeps these habits alive; a team that files it away relearns them per incident.

prevent-second-roots.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Thirty-second root check: run BEFORE ever reaching for the flag
# (identical hashes = related; different hashes = independent roots)
git rev-list --max-parents=0 HEAD
git fetch origin
git rev-list --max-parents=0 origin/main

# Safest first-push sequence for existing local code
# (empty remote + explicit upstream, no seeds, no surprises)
git remote add origin <empty-remote-url>
git push -u origin main

# Retiring a remote? Don't reuse its URL under a fresh repo
# (stale clones facing a stranger root is how mystery refusals start)
git remote set-url origin <brand-new-url>
git ls-remote origin | head -3
💡Uncheck the seeds, skip the incident
Creating the remote empty takes five seconds and prevents the most common unrelated-histories collision entirely. Make 'no seeds for existing code' a team default.
📊 Production Insight
After mandating empty-remote creation plus a root-check runbook entry, one org's Git support queue went a full quarter without a single unrelated-histories ticket — down from roughly two per month. Creation-time habits beat recovery skills by an order of magnitude.
🎯 Key Takeaway
Create remotes empty, clone-then-build for templated starts, check roots before flagging, and review every unrelated join. Never alias the flag into defaults.
● Production incidentPOST-MORTEMseverity: high

Docs Deploy Merged a README Twice and Duplicated 200 Pages for 3 Days

Symptom
On a Monday morning the documentation site's search started returning every page twice. An engineer investigating found the repo held two parallel trees: docs/getting-started.md from the original project and documentation/getting-started.md from the re-created remote, merged into one branch by a single join commit. The static-site build happily rendered both, so navigation showed duplicate sections and search indexed 200 mirrored pages. Readers couldn't tell which copy was current, and edits were landing on different copies depending on which path the author knew.
Assumption
The docs lead assumed the unrelated-histories refusal was a trivial first-pull hiccup and that the flag was the sanctioned fix. They ran the merge late Friday, saw 'Merge branch main of remote into main' succeed, and pushed without opening the merge commit. Nobody inspected what the join actually combined, because the command exited zero and the site built green.
Root cause
The local repo (initialized from the old manuscript, root commit A) and the re-created remote (seeded with a template including its own docs skeleton, root commit B) shared no ancestor. The flag merged both full trees using an empty base, so every overlapping file became an add/add conflict resolved by keeping both paths. The build passed because duplicate pages are valid content to a static generator. The duplication persisted 3 days because Friday's push preceded a weekend nobody checked search results.
Fix
The team picked the canonical tree, deleted the 200 mirrored files in a single cleanup commit, and added redirect rules from old paths to canonical ones so external links survived. They then protected the docs branch with required pull-request reviews, so no future merge — related or unrelated — could land without a second pair of eyes. Search results returned to single entries within a day of the cleanup deploy.
Key lesson
  • Exit zero is not review. An unrelated-histories merge combines two entire trees, and only a human reading the merge diff can judge whether the join is sane. Route every such merge through a pull request so the union of both histories gets inspected file by file.
  • Prefer reclone over union when one side is nearly empty. The remote's template skeleton could have been deleted in one commit or the local repo could have been cloned fresh. A 2-minute reclone beats a 3-day duplication cleanup every time.
  • Uncheck the seed files when you plan to push existing code. Creating a remote with README, license, or .gitignore pre-checked manufactures the second root commit that causes this whole category of incident.
Production debug guideFive scenarios that produce the refusal, each with the confirming command and the fix that fits — flag, reclone, or re-push.5 entries
Symptom · 01
Fresh git init plus a README-seeded remote refuses your first pull
→
Fix
Confirm with git log --oneline (one root locally) and git log --oneline origin/main (a different root remotely). If the remote side holds only seed files, skip the flag: git fetch origin, then git reset --hard origin/main only if your work is safely elsewhere — otherwise use the flag below. Simplest clean path is usually cloning fresh and copying your files in.
Symptom · 02
Both sides hold real work and you genuinely need the union
→
Fix
Run git pull origin main --allow-unrelated-histories. Expect an add/add conflict on every overlapping path. Resolve each to the correct surviving content, git add each file, and complete the merge commit with a message explaining why two roots joined. Review the full diff before pushing — the union deserves inspection.
Symptom · 03
The merge with the flag produces hundreds of conflicts
→
Fix
Stop and reconsider: hundreds of conflicts signal two full projects colliding, not a small join. Abort with git merge --abort, then choose: reclone the remote and copy your files in (remote wins), or push your history to a fresh empty remote (you win). Reserve the flag for joins you can actually review file by file.
Symptom · 04
An old checkout points at a re-created remote with the same URL
→
Fix
Confirm with git ls-remote origin showing commits your git log doesn't contain and vice versa. Don't merge strangers: back up your branch with git branch backup, clone the new remote fresh elsewhere, then cherry-pick or copy across only what you need. Rewriting the remote's replacement history with your stale objects corrupts everyone's clones.
Symptom · 05
You vendored a library repo and want its history joined to yours
→
Fix
Prefer git subtree add --prefix=vendor/lib <url> main or git submodule add over a raw unrelated merge: both record the boundary explicitly. If you already merged with the flag, verify with git log --oneline --graph that future library updates can merge cleanly — after the first join they share history and plain merges work.
Unrelated Histories Causes — Confirm, Fix, Prevent
Root CauseHow to ConfirmFixPrevention
Local init plus README-seeded remoterev-list roots differ; remote holds only README/LICENSEReclone the remote and copy files in, or push to an empty remoteCreate remotes empty when pushing existing code
Two genuine parallel starts needing unionBoth roots anchor real, valuable work on each sideMerge with --allow-unrelated-histories, resolve all, review via PRCoordinate scaffolding so parallel starts share one initial commit
Old checkout facing a re-created remotels-remote commits match nothing in local log and vice versaBack up, clone fresh, port only what's needed; don't merge strangersRetire URLs with repos; never reuse a URL under a replacement remote
Vendored library joined with a raw mergeLibrary files scattered with no recorded prefix boundaryUse subtree add/pull or submodules for boundary and update pathMandate subtree or submodule for all vendoring
Hundreds of conflicts from a flag mergeStatus shows unmerged paths across two full treesAbort and reclone; reserve the flag for reviewable-size joinsCount conflicts first; treat mass conflicts as a strategy signal
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
fix-seeded-remote.shgit rev-list --max-parents=0 HEADThe Classic Collision
union-merge-safely.shgit fetch originUsing the Flag Without Regretting It
reclone-instead.shgit branch backup-before-recloneWhen to Reclone Instead of Merging
vendor-with-subtree.shgit subtree add --prefix=vendor/lib main --squashSubtree and Submodule
prevent-second-roots.shgit rev-list --max-parents=0 HEADStop Manufacturing Second Roots

Key takeaways

1
Unrelated means no shared root, hence no merge base. Check roots with rev-list before choosing a strategy.
2
Seeded remotes cause most collisions. Create remotes empty for existing code; reclone when seeds already won.
3
The flag unions two full trees via an empty base. Every overlap becomes an add/add conflict to resolve.
4
Mass conflicts are a strategy signal
abort and reclone rather than resolving hundreds blindly.
5
Publish every unrelated join through pull-request review. Exit zero is not approval.
6
Vendor with subtree or submodules so boundaries survive and updates merge cleanly later.

Common mistakes to avoid

6 patterns
×

Using the flag as the default answer to every refusal

Symptom
Unrelated trees union silently, including cases where a wrong URL merged a stranger repo in, and nobody reviews the join because the command exited zero.
Fix
Check roots first, then choose reclone, empty-remote push, or a deliberate reviewed flag-merge. Type the flag deliberately every time.
×

Resolving hundreds of add/add conflicts by accepting one side wholesale

Symptom
An entire project's files vanish (checkout --ours everywhere) or duplicate (kept both paths), discovered days later by users rather than by Git.
Fix
Mass conflicts mean wrong strategy. Abort the merge and reclone. Only resolve unions small enough to review file by file.
×

Pushing the join commit directly to a shared branch

Symptom
The union of two trees lands unreviewed, duplicating paths or dropping files, and the team discovers it from broken search or builds rather than from review.
Fix
Publish every unrelated join through a pull request so the combined diff faces at least one reviewer before landing.
×

Creating remotes with seed files when pushing existing code

Symptom
Every new project starts with a refusal, and every developer learns the flag before learning reclone — manufacturing incidents on a schedule.
Fix
Create remotes empty for existing code. Clone first and build inside when the remote must carry templates.
×

Merging a re-created remote into a stale clone

Symptom
Two strangers' histories union, corrupting the replacement repo for everyone who already cloned it fresh, while your stale objects pollute the new line.
Fix
Back up your branch, clone the new remote fresh, and port selectively. Never merge a stranger root into a replacement history.
×

Vendoring with a bare flag-merge instead of subtree

Symptom
Library files scatter with no boundary, security patches can't merge cleanly later, and each update becomes a manual file-by-file ordeal.
Fix
Use git subtree add/pull with a prefix for coupled code, submodules for pinned deps. Record the boundary at join time.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What does 'refusing to merge unrelated histories' mean?
Q02SENIOR
Why did Git start refusing these merges? What does the flag actually do?
Q03SENIOR
First push to a seeded remote fails. Reclone or flag-merge — how do you ...
Q04SENIOR
Your flag-merge shows 300 conflicts. Walk through your next moves.
Q05SENIOR
How do subtree and submodule compare to a raw unrelated merge for vendor...
Q01 of 05JUNIOR

What does 'refusing to merge unrelated histories' mean?

ANSWER
The two sides share no common ancestor — each reaches its own root commit — so Git has no merge base and refuses to guess. It usually comes from a local init meeting a README-seeded remote. Fix by recloning, pushing to an empty remote, or deliberate --allow-unrelated-histories with full review.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Is --allow-unrelated-histories dangerous?
02
Why does GitHub's README checkbox cause this?
03
Can I undo a bad unrelated merge?
04
Does the flag affect future merges between the branches?
05
Should I ever alias pull with the flag?
06
Subtree or submodule for vendored code?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
✓ Verified
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
🔥

That's Git. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
Git Detached HEAD Recovery
50 / 51 · Git
Next
Git Remote Origin Already Exists Fix
→