Git: How To Merge Repositories

nabbisen - Apr 16 '19 - - Dev Community

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

Enter fullscreen mode Exit fullscreen mode

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/
            |
            +--...

Enter fullscreen mode Exit fullscreen mode

Tutorial

First, git clone the dest repository:

git clone repo1
Enter fullscreen mode Exit fullscreen mode

Let's go into the directory:

cd %owner-dir%/repo1
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

All files and directories of repo2 are added.

The Result:


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

Enter fullscreen mode Exit fullscreen mode

2) Subtree Merging

git merge -s subtree repo2/master --allow-unrelated-histories
Enter fullscreen mode Exit fullscreen mode

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       (+)

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

The Result:


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

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

Just the files in the root directory are added.

The Result:


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

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

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

Enter fullscreen mode Exit fullscreen mode

4) Merging As A New Subdirectory

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

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/       (+)

Enter fullscreen mode Exit fullscreen mode

In Closing

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

Thank you for your reading :)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .