Fix the Git 'refusing to merge unrelated histories' error when pulling or merging disparate repositories on Ubuntu 20.04. Learn the root cause and resolution.
This guide addresses a common Git error encountered by developers and system administrators on Ubuntu 20.04 LTS servers: "fatal: refusing to merge unrelated histories". This error typically arises when attempting to merge or pull changes from a remote repository into a local one that Git deems to have no common ancestral commits. While seemingly a blocking issue, Git provides a clear mechanism to resolve it, ensuring your project histories can be aligned.
Symptom & Error Signature
When you attempt to integrate changes from a remote Git repository into your local working copy, typically using git pull or git merge, you might encounter the following error message in your terminal:
$ git pull origin main
From github.com:your-organization/your-repository
* branch main -> FETCH_HEAD
fatal: refusing to merge unrelated histories
Or, if you're trying a direct merge:
$ git merge origin/main
fatal: refusing to merge unrelated histories
This error halts the pull/merge operation, leaving your local repository in its current state without integrating the remote changes.
Root Cause Analysis
The "fatal: refusing to merge unrelated histories" error is a safety mechanism introduced in Git version 2.9 (released June 2016). Prior to this version, Git would attempt to merge any two branches you specified, even if they had no common commit history, potentially leading to a confusing and possibly destructive merge.
Git's core principle is to build a directed acyclic graph (DAG) of commits. When you try to merge two branches, Git normally expects to find a common ancestor commit from which both branches diverged. If no such common ancestor exists, Git considers their histories "unrelated."
Common scenarios that lead to unrelated histories include:
- Initializing an Empty Local Repo, Pulling from Existing Remote: You create a new project directory, run
git init, and then try togit pullfrom an existing remote repository that already has commits (e.g., aREADME.mdor initial project files). Your localHEADhas no commits, and the remoteHEADhas a history, so they don't share a common ancestor. - Remote Repository Initialized Separately: You create an empty repository on a platform like GitHub or GitLab, and then initialize it directly on the web interface by adding a
README.md,.gitignore, or license file. Simultaneously, you create a local repository withgit initand some initial commits without cloning the remote. When you later try togit pullfrom the remote into your local repo, their histories are unrelated. - Restoring from a "Working Directory" Backup: If you only backed up the
.gitfolder along with the working directory, and then restored it, or if you only backed up the working directory and then re-initialized Git withgit init, the new local.githistory might not align with the remote's history graph if not handled carefully. - Accidental Parallel Development: Two separate projects were started, both initialized as Git repositories, and later an attempt is made to merge them as if they were branches of a single project.
In essence, Git is preventing what it perceives as an attempt to merge two entirely distinct timelines, which could obscure project history or introduce unexpected changes.
Step-by-Step Resolution
The primary and recommended solution involves explicitly telling Git to allow merging of unrelated histories using the --allow-unrelated-histories flag.
1. Understanding the allow-unrelated-histories Flag
This flag instructs Git to proceed with the merge even if it cannot find a common ancestor between the two histories. When this flag is used, Git treats the first commit of one history and the first commit of the other history as their common base for the merge, effectively creating a merge commit that bridges the two distinct histories.
[!IMPORTANT] Use this flag with caution. While it resolves the immediate error, ensure you understand why the histories are unrelated. This action cannot be easily undone without rewriting history, which can be problematic in collaborative environments.
2. Safely Merging Unrelated Histories (Recommended Approach)
This method preserves both local and remote histories, combining them into a new merge commit.
2.1 Verify Current Status and Remote Configuration
Before proceeding, ensure your local repository is clean and correctly configured to point to the remote.
# Check for any uncommitted local changes (commit or stash them if necessary)
Verify your remote configuration
git remote -v
`
Expected output for git remote -v:
origin https://github.com/your-organization/your-repository.git (fetch)
origin https://github.com/your-organization/your-repository.git (push)
2.2 Fetch Remote Changes (Optional, but Good Practice)
It's often good practice to first fetch all remote changes without merging them. This allows you to inspect the remote's history if needed.
git fetch origin
2.3 Perform the Merge with --allow-unrelated-histories
Now, execute the git pull or git merge command with the crucial flag. Assuming you want to pull from the main branch of your origin remote:
git pull origin main --allow-unrelated-histories
If you prefer to fetch and then merge manually:
git merge origin/main --allow-unrelated-histories
Git will then attempt to merge the two histories.
2.4 Resolve Merge Conflicts (If Any)
[!IMPORTANT] It is highly probable that you will encounter merge conflicts after using
--allow-unrelated-histories, especially if both histories have different files or different versions of the same files at their respective roots (e.g., two differentREADME.mdfiles).
Your terminal will indicate any conflicting files:
Auto-merging README.md
CONFLICT (add/add): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
- Open the conflicting files in your preferred text editor (e.g.,
nano,vim,vscode). - Identify and resolve conflicts: Git marks conflicts with
<<<<<<<,=======, and>>>>>>>. -
`markdown - <<<<<<< HEAD
- This is the content from my local repository.
- =======
- This is the content from the remote repository.
- >>>>>>> origin/main
-
` - Edit the file to include the desired content.
- Stage the resolved files:
-
`bash - git add . # Or git add <conflicting-file-1> <conflicting-file-2>
-
` - Commit the merge: Git will typically provide a default merge commit message. You can accept it or modify it.
-
`bash - git commit -m "Merge remote main with –allow-unrelated-histories and resolved conflicts"
-
`
2.5 Push Changes to Remote (If Necessary)
Once the merge is complete and committed locally, you can push the new, unified history to your remote repository.
git push origin main
3. Alternative: Reinitialize Local Repository (Use with Caution)
This approach discards your local repository's history and state, effectively making it a fresh clone of the remote. This is suitable if your local repository has no important uncommitted changes, or if its history is completely irrelevant compared to the remote.
3.1 Backup Local Changes (If Any)
If you have any uncommitted or local-only committed changes that you wish to preserve, back them up.
# Stash uncommitted changes
Or, simply copy your entire project directory
cp -r /path/to/your/project /path/to/your/projectbackupdate +%Y%m%d%H%M%S
`
3.2 Remove Local .git Directory
Navigate into your project directory and remove the hidden .git folder. This effectively de-initializes your local repository.
cd /path/to/your/project
rm -rf .git
3.3 Re-clone the Remote Repository
Navigate to the parent directory of your project and clone the remote repository anew.
cd /path/to/parent/directory
git clone https://github.com/your-organization/your-repository.git your_project_name
cd your_project_name
3.4 Restore and Reapply Local Changes (If Any)
If you stashed changes in step 3.1, you can now try to apply them. Be aware that conflicts might still occur if the remote has diverged significantly.
# If you stashed changes and are in the newly cloned repo:
Alternatively, manually copy back specific files from your backup
cp /path/to/your/projectbackup/yourfile.js .
`
4. Alternative: Force Push (Use with EXTREME Caution)
This option is generally NOT recommended in collaborative environments. It should only be used if you are absolutely certain that your local repository's history should completely overwrite the remote's history, and no one else is working on that branch.
4.1 Ensure Local Repository is Exactly What You Want
Make sure your local branch (main in this example) contains the exact history and files you want to be on the remote.
4.2 Force Push
# Safer variant: only forces if the remote branch hasn't been updated since your last pull/fetch
More aggressive variant: forces regardless of remote updates, can overwrite others' work
# Use with extreme caution, only if you are absolutely sure.
# git push –force origin main
`
[!WARNING] The
git push --force-with-leaseorgit push --forcecommands will overwrite the remote branch history! All commits on the remote that are not present in your local branch will be permanently lost. This can cause significant problems for other developers working on the same branch. Only use this if you are absolutely certain of the consequences and have communicated with your team, or if you are the sole contributor and are certain the remote history is undesirable.
By understanding the root cause and carefully applying one of these resolution methods, particularly the --allow-unrelated-histories flag, you can effectively overcome the "fatal: refusing to merge unrelated histories" error and continue your development workflow on Ubuntu 20.04 LTS.
Leave a Reply