Categories
git git-subtree merge repository

How do you merge two Git repositories?

2007

Consider the following scenario:

I have developed a small experimental project A in its own Git repo. It has now matured, and I’d like A to be part of larger project B, which has its own big repository. I’d now like to add A as a subdirectory of B.

How do I merge A into B, without losing history on any side?

1

503

A single branch of another repository can be easily placed under a subdirectory retaining its history. For example:

git subtree add --prefix=rails git://github.com/rails/rails.git master

This will appear as a single commit where all files of Rails master branch are added into “rails” directory.
However the commit’s title contains a reference to the old history tree:

Add ‘rails/’ from commit <rev>

Where <rev> is a SHA-1 commit hash. You can still see the history, blame some changes.

git log <rev>
git blame <rev> -- README.md

Note that you can’t see the directory prefix from here since this is an actual old branch left intact.
You should treat this like a usual file move commit: you will need an extra jump when reaching it.

# finishes with all files added at once commit
git log rails/README.md

# then continue from original tree
git log <rev> -- README.md

There are more complex solutions like doing this manually or rewriting the history as described in other answers.

The git-subtree command is a part of official git-contrib, some packet managers install it by default (OS X Homebrew).
But you might have to install it by yourself in addition to git.

10

  • 2

    Here are instructions on how to install Git SubTree (as of June 2013): stackoverflow.com/a/11613541/694469 (and I replaced git co v1.7.11.3 with ... v1.8.3).

    – KajMagnus

    Jun 7, 2013 at 14:31

  • 1

    Thanks for the heads up about the below answer. As of git 1.8.4 ‘subtree’ still isn’t included (at least not on the Ubuntu 12.04 git ppa (ppa:git-core/ppa) )

    Sep 30, 2013 at 2:10

  • 1

    I can confirm that after this, git log rails/somefile will not display that file’s commits history except the merge commit. As @artfulrobot suggested, check Greg Hewgill’s answer. And you might need to use git filter-branch on the repo you want to include.

    Oct 8, 2013 at 12:07

  • 8

    Or read Eric Lee’s “Merging Two Git Repositories Into One Repository Without Losing File History” saintgimp.org/2013/01/22/…

    Oct 8, 2013 at 12:17


  • 6

    As others have said, git subtree may not do what you think! See here for a more complete solution.

    Feb 1, 2014 at 8:13

643

Here are two possible solutions:

Submodules

Either copy repository A into a separate directory in larger project B, or (perhaps better) clone repository A into a subdirectory in project B. Then use git submodule to make this repository a submodule of a repository B.

This is a good solution for loosely-coupled repositories, where development in repository A continues, and the major portion of development is a separate stand-alone development in A. See also SubmoduleSupport and GitSubmoduleTutorial pages on Git Wiki.

Subtree merge

You can merge repository A into a subdirectory of a project B using the subtree merge strategy. This is described in Subtree Merging and You by Markus Prinz.

git remote add -f Bproject /path/to/B
git merge -s ours --allow-unrelated-histories --no-commit Bproject/master
git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
git pull -s subtree Bproject master

(Option --allow-unrelated-histories is needed for Git >= 2.9.0.)

Or you can use git subtree tool (repository on GitHub) by apenwarr (Avery Pennarun), announced for example in his blog post A new alternative to Git submodules: git subtree.


I think in your case (A is to be part of larger project B) the correct solution would be to use subtree merge.

10

  • 1

    This works and seems to preserve the history, but not such that you could use it to diff files or bisect through the merge. Am I missing a step?

    – jettero

    May 7, 2012 at 12:44

  • 59

    this is incomplete. Yes you get a load of commits, but they no longer refer to the right paths. git log dir-B/somefile won’t show anything except the one merge. See Greg Hewgill’s answer references this important issue.

    Jun 1, 2012 at 14:52

  • 2

    IMPORTANT: git pull –no-rebase -s subtree Bproject master If you don’t do that, and you have pull set to rebase automatically, you’ll end up with “Could not parse object”. See osdir.com/ml/git/2009-07/msg01576.html

    Sep 16, 2012 at 14:35


  • 4

    This answer may be confusing because it has B as the merged subtree when in the question it was A. Result of a copy and paste?

    – vfclists

    Sep 20, 2012 at 11:32


  • 11

    If you’re trying to simply glue two repositories together, submodules and subtree merges are the wrong tool to use because they don’t preserve all of the file history (as other commenters have noted). See stackoverflow.com/questions/13040958/….

    – Eric Lee

    Jan 23, 2013 at 0:06

503

A single branch of another repository can be easily placed under a subdirectory retaining its history. For example:

git subtree add --prefix=rails git://github.com/rails/rails.git master

This will appear as a single commit where all files of Rails master branch are added into “rails” directory.
However the commit’s title contains a reference to the old history tree:

Add ‘rails/’ from commit <rev>

Where <rev> is a SHA-1 commit hash. You can still see the history, blame some changes.

git log <rev>
git blame <rev> -- README.md

Note that you can’t see the directory prefix from here since this is an actual old branch left intact.
You should treat this like a usual file move commit: you will need an extra jump when reaching it.

# finishes with all files added at once commit
git log rails/README.md

# then continue from original tree
git log <rev> -- README.md

There are more complex solutions like doing this manually or rewriting the history as described in other answers.

The git-subtree command is a part of official git-contrib, some packet managers install it by default (OS X Homebrew).
But you might have to install it by yourself in addition to git.

10

  • 2

    Here are instructions on how to install Git SubTree (as of June 2013): stackoverflow.com/a/11613541/694469 (and I replaced git co v1.7.11.3 with ... v1.8.3).

    – KajMagnus

    Jun 7, 2013 at 14:31

  • 1

    Thanks for the heads up about the below answer. As of git 1.8.4 ‘subtree’ still isn’t included (at least not on the Ubuntu 12.04 git ppa (ppa:git-core/ppa) )

    Sep 30, 2013 at 2:10

  • 1

    I can confirm that after this, git log rails/somefile will not display that file’s commits history except the merge commit. As @artfulrobot suggested, check Greg Hewgill’s answer. And you might need to use git filter-branch on the repo you want to include.

    Oct 8, 2013 at 12:07

  • 8

    Or read Eric Lee’s “Merging Two Git Repositories Into One Repository Without Losing File History” saintgimp.org/2013/01/22/…

    Oct 8, 2013 at 12:17


  • 6

    As others have said, git subtree may not do what you think! See here for a more complete solution.

    Feb 1, 2014 at 8:13