Merge two Git repositories into one
How do I combine two separate repos while keeping both histories?
Short answer
Add the second repository as a remote, fetch it, and merge with --allow-unrelated-histories into a subdirectory. Both sets of commits end up in one repository with their history intact.
git remote add other ../other-repo
git fetch other
git merge other/main --allow-unrelated-histories
Pull another repository's full history into this one
Does this match your situation?
- Two projects should live in one monorepo.
- A library you wrote separately now belongs inside the main app.
- You want to consolidate repositories without losing either history.
Step-by-step fix
Back up both repositories
This rewrites nothing by default, but a merge across unrelated histories is fiddly enough to be worth a safety copy of each side.
step 1git clone --mirror ../repo-a ../repo-a-backup.git git clone --mirror ../repo-b ../repo-b-backup.gitMove the incoming repo's files into a subdirectory first
Doing this on the other repository before merging avoids every root-level collision — two READMEs, two .gitignores, two package.json files.
step 2cd ../repo-b mkdir -p libs/widget git mv $(git ls-files | grep -v '^libs/') libs/widget/ 2>/dev/null git commit -m "Move files into libs/widget for merge"Or use git filter-repo --to-subdirectory-filter libs/widget, which rewrites the whole history as if it always lived there.
Fetch it into the main repository
A local path works as a remote URL, so nothing needs to be published anywhere.
step 3cd ../repo-a git remote add widget ../repo-b git fetch widgetMerge the unrelated history
The flag is required because the two histories share no ancestor. With the files already namespaced, this usually merges without a single conflict.
step 4git merge widget/main --allow-unrelated-histories git log --oneline | head -20Clean up
Drop the temporary remote and verify both histories are present and attributed correctly.
step 5git remote remove widget git log --oneline --graph | head -30 git log --format="%an" | sort -u
Why this works
Git has no notion of a repository identity inside its object database — there are only objects and refs. Fetching from another repository copies its objects in, and because a merge commit can have any two parents, joining two entirely separate histories is structurally legal. The --allow-unrelated-histories flag exists purely because doing this accidentally is far more common than doing it deliberately. Namespacing the incoming files into a subdirectory first is what turns a conflict-ridden merge into a clean one.
If that didn’t work
- git subtree add --prefix=libs/widget ../repo-b main is a one-command alternative that handles the namespacing for you.
- If you don't need the second repository's history, copying the files in as a single commit is far simpler.
- Use git filter-repo --to-subdirectory-filter on the incoming repo for a cleaner result than git mv.
How to stop it happening again
- Decide early whether related projects belong in one repository.
- If you expect to consolidate later, keep each project's files under a top-level directory from the start.
Commands used in this guide
git remoteManage the named URLs your repository syncs with.
git fetchDownload new commits from the remote without changing any of your files.
git mergeCombine another branch's history into the current one.
git subtreeVendor another repository into a subdirectory - without submodules' friction.
git filter-repoRewrite an entire repository's history - the supported way to purge a leaked secret or a huge file.
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
How do I merge two Git repositories keeping both histories?
Add the second repo as a remote, fetch it, then git merge <remote>/main --allow-unrelated-histories. Move the incoming files into a subdirectory beforehand so root-level files don't collide.
Why do I need --allow-unrelated-histories?
Because the two repositories share no common ancestor, so Git has no base to merge against and refuses by default. The flag confirms you genuinely intend to join two independent histories.
Will I keep the original commit authors and dates?
Yes. A merge copies the existing commit objects unchanged, so authors, dates, messages and hashes from both sides are preserved exactly.
Related rescue guides
How do I extract a folder from my repo into a separate repo with its history?
git filter-repo --path <dir> --path-rename <dir>/: keeps only that directory and moves it to the root, preserving every commit that touched it. Work on a fresh clone so your original repository is never at risk.
Read the fix →Always fixableGit says refusing to merge unrelated histories — what does that mean?
The two branches share no common ancestor, so Git won't guess how to combine them. Adding --allow-unrelated-histories permits the merge — but first check you aren't accidentally merging two genuinely different projects, which is what this guard is protecting you from.
Read the fix →Always fixableI cloned a repo and the submodule folders are empty — how do I fix it?
Cloning records submodules but doesn't populate them. Run git submodule update --init --recursive, or clone with --recurse-submodules next time so it happens automatically.
Read the fix →Always fixableGit says I have merge conflicts — how do I fix them?
Git pauses and marks the clashing sections with <<<<<<<, ======= and >>>>>>>. Edit each file to the version you actually want, delete the markers, git add the file, then git merge --continue. If it gets overwhelming, git merge --abort returns you to exactly where you started.
Read the fix →