38

I have two sub-directories each with a repo, thus :

PPP/
 |--ABC/
 |   |--.git/
 |   |--AAA/
 |   |    BBB/
 |   |   CCC/
 |   
 |--DEF/
 |   |--.git/
 |   |--DDD/
 |   |--EEE/

And would like to combine them into one repo, so, I would assume the directory structure would be like this:

PPP/
 |--.git/
 |--ABC/
 |   |--AAA/
 |   |--BBB/
 |   |--CCC/
 |   
 |--DEF/
 |   |--DDD/
 |   |--EEE/

Is this posible?

Also currently several people have the repos on their machines. How much more complicated does that make life?

Ta.

MiniQuark
  • 46,633
  • 36
  • 147
  • 183
user74159
  • 383
  • 1
  • 3
  • 5
  • 1
    See [Combining multiple git repositories](http://stackoverflow.com/questions/277029/combining-multiple-git-repositories). – Pat Notz Mar 05 '09 at 14:29

4 Answers4

45

You can do what you are describing like this:

  1. Move the content of ABC to an ABC/ subdirectory, and fix the history so that it looks like it has always been there:

    $ cd /path/to/ABC
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t-&ABC/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    

    Now your directory structure is ABC/ABC/your_code

  2. Same for the content of DEF:

    $ cd /path/to/DEF
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t-&DEF/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    

    Now your directory structure is DEF/DEF/your_code

  3. Finally, create the PPP repository and pull both ABC and DEF into it:

    $ mkdir /path/to/PPP
    $ cd /path/to/PPP
    $ git init
    $ git pull /path/to/ABC
    $ git pull /path/to/DEF
    

    Now you have PPP/ABC/your_code and PPP/DEF/your_code, along with all the history.

You should probably ask you collegues to run the previous commands on their system, in order for everyone to be synchronized.

Note: the funky filter-branch commands come from the man page. :-)

digitalextremist
  • 5,952
  • 3
  • 43
  • 62
MiniQuark
  • 46,633
  • 36
  • 147
  • 183
  • 2
    Note that this will only update the current checked-out branch in each subproject, and will only pull those branches into the new repo. – Lily Ballard Aug 26 '10 at 01:52
  • 12
    BTW, an alternate way to modify the current repo to move everything into a subdir is something like `git filter-branch --tag-name-filter cat --index-filter 'SHA=$(git write-tree); rm $GIT_INDEX_FILE && git read-tree --prefix=ABC/ $SHA' -- --all`. This will also rewrite all branches and tags, not just HEAD. – Lily Ballard Aug 26 '10 at 01:55
  • 1
    The funky filter-branch command is from git's filter-branch man pages. You should say that as: a) it should be attributed correctly b) I won't run such a command just because someone, even with high reputation, posted it on StackOverflow. Knowing it's from man pages I will. – tymtam Nov 14 '11 at 02:52
  • 3
    Hi Tymek. You're perfectly right, I just added a note. I've been using this funky command for some time, and I had long forgotten where I got it from (I may even have believed that I came up with it!). "Good artists borrow, great artists steal", said Picasso (or was it me?). – MiniQuark Dec 06 '11 at 18:01
  • 2
    A problem that I just ran into with the index filter: If your first commit makes no changes to files (such as an import from Subversion that only created a directory), the index.new file does not get created and the `mv` command has no source and fails. You can either rebase and squash the first two commits or add `||:` after the `mv` command, which always results in success, even if the first `mv` fails. – Wil Cooley Aug 08 '12 at 05:52
5

Do you really need to merge the two existing repositories into one repository, or do you just want to group them?

If you just want to group them, then git-submodule will do what you want: you'll end up with three repositories where the top-level one links to the current two.

As a guide:

  • You should merge them into a single repository if you're going to increase the coupling between them so that it no longer makes sense to use one version of repo A with a different version of repo B.

  • You should use submodules if they remain somewhat separate (it would sometimes makes sense to work on one in isolation), but you want the convenience of being able to work with them together (e.g. download both at once, checkpoint known-good states across both, etc).

Using submodules will avoid problems with existing copies of the repositories, since the history doesn't change. Merging them will create a new history and it will be harder for people working from the existing branches to merge their changes.

Thomas Leonard
  • 7,068
  • 2
  • 36
  • 40
0

For me it seems hard to do the way you want it because the history of both project won't merge.

My best advice would be to create a new repository to contain ABC and DEF, keeping old repo from these two to have history backup and start a fresh history with this new project.

claf
  • 9,043
  • 17
  • 62
  • 79
0

(2022) answer: consider git filter-repo over git filter-branch.

filter-repo is much faster and is the recommended approach for something like this.

Example use case:

  1. Merging repoA/develop -> repoB/develop and into the folder /android

Example command (which renames all commits from the baseDir and moves them into the /android/path/to/file

filter-repo --path-rename :android/ --force

Documentation: https://github.com/newren/git-filter-repo

fengelhardt
  • 965
  • 11
  • 24