loading...

Git: How To Merge Repositories

nabbisen profile image Heddi Nabbisen Updated on ・3 min read

Introduction

I merged multiple Github repositories around one of my projects into a single one for the sake of integration this afternoon.
This post shows several ways to carry it out using local clones.
One of them is that I actually adopted and the others are perhaps good to know for some future :)

Environment

Version Control: Git 2.21.0

Overview

Here is a brief concept:


"repo1" as dest   <----merge----   "repo2" as src

Also, here is an example directory overview in this tutorial:


%owner-dir%/
  |
  +--repo1/     # as dest
  |    |
  |    +--file1
  |    +--common-dir/
  |    |    |
  |    |    +--fileX
  |    |
  |    +--dir1/
  |         |
  |         +--...
  |
  +--repo2/     # as src
       |
       +--file2
       +--common-dir/
       |    |
       |    +--fileY
       |
       +--dir2/
            |
            +--...

Tutorial

First, git clone the dest repository:

git clone repo1

Let's go into the directory:

cd %owner-dir%/repo1

Then, on the whole, there are just 4 steps to carry it out:

#1. Add the src repository as a new remote
#1-1. Case of using url to specify the location of the src repository
git remote add repo2 git@github.com:%owner-dir%/repo2
# or
git remote add repo2 https://.../%owner-dir%/repo2
#1-2. Case of using path; For example, doing after `git clone repo2 %owner-dir%`
git remote add repo2 %owner-dir%/repo2

#2. Fetch the contents of the src repository
git fetch repo2

#3. Merge them
### Here choose an operation from below. ###

#4. Push the changes
git push origin master

Operations

They are options for "#3. Merge them" above.
I think 1)-2) are basic and the others, 3)-4), are optional.

Prefaces

With Git 2.9.0 and later, git merge command for a different repository requires --allow-unrelated-histories option in order to avoid fatal: refusing to merge unrelated histories error.

The commit history in the src repository is preserved except 4).

1) Repository Merging

git merge repo2/master --allow-unrelated-histories

All files and directories of repo2 are added.

The Result:


repo1/
  |
  +--file1
  +--file2            (+)
  +--dir1/
  +--common-dir/
  |    |
  |    +--fileX
  |    +--fileY       (+)
  |
  +--dir2/            (+)

2) Subtree Merging

git merge -s subtree repo2/master --allow-unrelated-histories

Using this method, the subdirectories whose names are equal to those of the dest repo's and the files in the root directory are added.
Therefore, in this case, added are just 2 files, fileY in common-dir directory and file2 file in the root directory.

The Result:


repo1
  |
  +--file1
  +--file2            (+)
  +--dir1/
  +--common-dir/
       |
       +--fileX
       +--fileY       (+)

3) Subtree Merging With Specifying A Subdirectory

git merge -X<option> made me confused...

3)-1 Specifying the subdirectory which both the dest repo and the src one have
git merge -X subtree=common-dir repo2/master --allow-unrelated-histories

The files in the root directory and those in the specified subdirectory are added.

The Result:


repo1
  |
  +--file1
  +--file2            (+)
  +--dir1/
  +--common-dir/
       |
       +--fileX
       +--fileY       (+)

3)-2 Specifying the subdirectory which only the src repo has
git merge -X subtree=dir2 repo2/master --allow-unrelated-histories

Just the files in the root directory are added.

The Result:


repo1
  |
  +--file1
  +--file2            (+)
  +--dir1/
  +--common-dir/
       |
       +--fileX

3)-3 Specifying the subdirectory which only the dest repo has
git merge -X subtree=dir1 repo2/master --allow-unrelated-histories

The directory named as the specified one is created, and then all of the files and the directories in the src repo are added to it.

The Result:


repo1
  |
  +--file1
  +--dir1/
  |    |
  |    +...
  |    +--file2       (+)
  |    +--common-dir/ (+)
  |    |    |
  |    |    +--fileY  (+)
  |    |
  |    +--dir2/       (+)
  |
  +--common-dir/
       |
       +--fileX

4) Merging As A New Subdirectory

git read-tree --prefix=%new-subdir%/ repo2/master
git checkout -- .
git add .
git commit -m "commit messages"

The original commit history of the src repo isn't inherited.

The Result:


repo1
  |
  +--file1
  +--dir1/
  +--common-dir/
  |    |
  |    +--fileX
  |
  +--%new-subdir%     (+)
       |
       +--file2       (+)
       +--common-dir/ (+)
       |    |
       |    +--fileY  (+)
       |
       +--dir2/       (+)

In Closing

For the information, these are official documents about the Git commands and strategies above:

Thank you for your reading :)

Posted on by:

nabbisen profile

Heddi Nabbisen

@nabbisen

An ICT designer/developer and a security monk. "With a cool brain and a warm heart", I am challenging unsolved problems in our society. I use OpenBSD/Rust/etc.

Discussion

markdown guide
 

I wouldn't bother with cloning both. Clone the first and add the second as a remote, you basically do that in your second step.

 

Jesse, thank you so much for your kind feedback.
I understood I had had not to clone the second in order to just merge it.
I have updated my post and made my post simpler thanks to you :)

 

Thank you for your post. I was able to merge 2 repos and set it as new subdirectory. Cheers!

 

Thank you for your giving me a good news.
I'm happy to know your merging was a success.
I remember I was really confused when I was studying about merging git repos... 🤯
Cheers 😄