fbpx

Merging two Git repositories together in not a common task. In my own consulting work, this is a task that does come up every so often when the code I’m working on needs to be moved from an initial Git repository, whether it’s GitHub or Azure DevOps, to another Git repository that will be the final destination for the source code. Sure, it’s easy to “move” the source code to another repository by copying the files and making a commit, but it can be much more useful to preserve the commit history for tracking purposes. Luckily, Git does support this with the git merge command when setting up multiple remotes using git remote. Also, the git-filter-repo tool can be used to move files and their history to a new folder location within the same repository before making the move, in cases where one of the repositories needs to be moved while preserving history to a subfolder of the target / destination repository.

Let’s take a look at the bash or CLI commands to merge Git repositories while maintaining commit history!

The bash and CLI commands shown in this article for merging two Git repositories while maintaining commit history with with Git distributed version control. This means it will work with GitHub repositories, Azure DevOps repositories, or any other Git repositories!

Merge Two Git Repositories into One

To merge two Git repositories, you’ll need to perform the following steps:

  1. Determine which Git repositories are going to be the Source and Target. Target being the repository that will have the Source merged into.
  2. Create a working directory, such as /workspace
  3. Clone the Source repository into the /workspace/source folder
  4. Check out the branch of Source that you want to merge, via git checkout
  5. Clone the Target repository into the /workspace/target folder
  6. Create a new branch to receive the merged files and history in the Target repository, via git branch and git checkout commands
  7. Within the Target repository in the /workspace/target folder, add a new Git remote pointed towards the /workspace/source folder and the branch of the Source repository to be merged into Target, for example using git remote add -f local ../source
  8. Within Target, use the git merge command to merge in the local/main remote branch, using the --allow-unrelated-histories flag to make sure it all merges
  9. Use git push to push up the new merged branch to the Target repo
  10. Celebrate that your two Git repositories are now merged into one!

Here’s an example script that performs all these steps with comments to help you walk through the process of merging two Git repositories into one:

# Create a working directory
mkdir workspace
cd workspace

# Clone the 'source' repo getting merged into 'target' repo
git clone https://github.com/build5nines/source-repo.git source
cd source

# Checkout the 'main' branch of the 'source' repo
git checkout main

# Clone the 'target' repo that's the destination for the merge
cd ..
git clone https://github.com/build5nines/target-repo.git target

# Create new branch in 'target' repo for the merge
cd target
git branch merged-repos
git checkout merged-repos

# Add Git 'remote' to 'target' repo that pulls from 'source' repo folder
# Name the 'source' remote 'local'
git remote add -f local ../source

# Merge files and history from 'source' repo (via 'main' branch of 'local' remote) into 'target'
git merge --allow-unrelated-histories -m 'merge repos' local/main

# Push the finished 'target' repo merge branch to remote / GitHub
git push --set-upstream origin merged-repos

Merge Git Repository into Subfolder of another Git Repository

When merging two Git repositories that have files and/or folders with the names, then those files and folders will need to be either moved or renamed before merging to avoid conflicts. Thankfully, the git-filter-repo tool exists that allows you to easily move the contents of a Git repository to a new subfolder within the same repository while preserving history.

The git-filter-repo tool requires Python to run. You may need to perform a couple steps depending on if you’re installing on Windows, Linux or macOS. The git-filter-repo tool Install documentation will help you with this.

In general, you can use your favorite package manager to install it:

$ <fav-package-manager> install git-filter-repo

If you’re using macOS, then git-filter-repo can be installed easily using Homebrew:

// Homebrew on macOS
brew install git-filter-repo

Once, you have git-filter-repo installed, then it’s a single command that can be run with Git to perform the file with history move. Here’s the git-filter-repo command to move the entire root (/) contents of the Git repository to a subfolder named /Foo:

git filter-repo -f --to-subdirectory-filter Foo --tag-rename :foo-

Now that you have git-filter-repo installed, you will be able to merge the Source repository into a subfolder of the Target repository while preserving all commit history.

Here’s the above Git merge example with the use of git filter-repo added in the appropriate place to move the contents of the Source repository into a subfolder named /Foo within the repository before then merging it into the Target repository:

'# Create a working directory
mkdir workspace
cd workspace

# Clone the 'source' repo getting merged into 'target' repo
git clone https://github.com/build5nines/source-repo.git source
cd source

# Checkout the 'main' branch of the 'source' repo
git checkout main

# Use 'git-filter-repo' to move 'source' repo with history to subfolder named 'Foo'
git filter-repo -f --to-subdirectory-filter Foo --tag-rename :foo-
# After running the root '/' contents of 'source' repo will be located in '/Foo/' subfolder

# Clone the 'target' repo that's the destination for the merge
cd ..
git clone https://github.com/build5nines/target-repo.git target

# Create new branch in 'target' repo for the merge
cd target
git branch merged-repos
git checkout merged-repos

# Add Git 'remote' to 'target' repo that pulls from 'source' repo folder
# Name the 'source' remote 'local'
git remote add -f local ../source

# Merge files and history from 'source' repo (via 'main' branch of 'local' remote) into 'target'
git merge --allow-unrelated-histories -m 'merge repos' local/main

# Push the finished 'target' repo merge branch to remote / GitHub
git push --set-upstream origin merged-repos

I hope these examples help clarify what is necessary to perform both a simple merge of two Git repositories, as well as merging the contents of one repository into a subfolder of another Git repository.

Happy Git merging!

Microsoft MVP

Chris Pietschmann is a Microsoft MVP, HashiCorp Ambassador, and Microsoft Certified Trainer (MCT) with 20+ years of experience designing and building Cloud & Enterprise systems. He has worked with companies of all sizes from startups to large enterprises. He has a passion for technology and sharing what he learns with others to help enable them to learn faster and be more productive.
HashiCorp Ambassador Microsoft Certified Trainer (MCT) Microsoft Certified: Azure Solutions Architect

Discover more from Build5Nines

Subscribe now to keep reading and get access to the full archive.

Continue reading