How to merge two Git repositories into one (not two branches)

Updated: January 27, 2024 By: Guest Contributor Post a comment

Overview

Merging two separate Git repositories into one without intertwining their histories is a task that may be needed when combining products, services, or simply for organizational consolidation. Careful planning and execution are vital to keep history intact and avoid potential conflicts. This tutorial will lead you through these steps, providing examples ranging from basic to advanced scenarios.

Preparatory Work

Backup First: Always create backups prior to proceeding with a merge. It’s a safeguard against any potential loss of data.

Basic Merge: No Shared History

$ git clone URL-of-repository-A new-repository
$ cd new-repository
$ git remote add repoB URL-of-repository-B
$ git fetch repoB
$ git merge --allow-unrelated-histories repoB/master
$ git push origin master

The critical option --allow-unrelated-histories is used to enable merging two repositories that do not share a commit history.

Preserving Directories

If each repository should be preserved in its own directory, the following should be executed:

$ mkdir repoA
$ mv !(repoA) repoA/
$ git add .
$ git commit -m "Moved repoA content into subdir"

$ git remote add repoB URL-of-repository-B
$ git fetch repoB
$ git checkout -b repoB-master repoB/master
$ mkdir repoB
$ git mv * repoB/
$ git commit -m "Moved repoB content into subdir"

$ git checkout master
$ git merge repoB-master --allow-unrelated-histories
$ git remote remove repoB
$ git push origin master

This sequence of commands creates separate directories for each repository, moves the content into these folders, and then proceeds with the merge.

Advanced Merge Scenario: Overlapping Project Histories

For projects that have overlapping histories but have diverged, the rebase approach might be more appropriate:

$ git clone URL-of-repository-A combined-repository
$ git checkout -b repository-A-branch

$ git remote add repoB URL-of-repository-B
$ git fetch repoB
$ git checkout -b repoB-branch --track repoB/master

$ git rebase --onto repository-A-branch --root repoB-branch
$ git checkout master
$ git merge repoB-branch
$ git push origin master

Note the use of --root with git rebase which allows you to rebase the entire branch from its first commit.

Handling Conflicts

Conflicts might arise during the merge process. Resolving them requires manual intervention:

$ git mergetool
$ git commit
$ git push

After calling git mergetool, use the interactive tool to resolve conflicts. Attempting to push changes without correctly resolving may lead to erroneous histories.

Combining Complex Histories with Replacements

Combining two complex histories might need the replacements functionality:

$ git clone URL-of-repository-A complex-repository
$ cd complex-repository
$ git remote add repoB URL-of-repository-B
$ git fetch repoB

$ git replace repoB's_first_commit repoA's_commit_before_diverge
$ git merge repoB/master
$ git push origin master

This technique uses git replace to link historical lines together and alter the perception of the repository’s history.

Cleaning up Repository

After a successful merge, clean up the repository by removing unnecessary remote tracking branches:

$ git remote remove repoB
$ git branch -d repoB-master
$ git push origin --prune

Cleaning up keeps the repository tidy and free of stale references.

Optimizing Merged Repository

For better performance, optimize the merged repository:

$ git gc --aggressive

This will clean up unnecessary files and optimize the local repository.

Conclusion

Merging two Git repositories can range from a simple command to a complex series of steps depending on the history and structure of your projects. By following the guidelines outlined above, you can preserve history, maintain project structure, and combine your codebases successfully. Remember to backup frequently and test thoroughly at each step to ensure a smooth transition.