17

I have a number of projects that are in separate Git repositories right now. They are, likewise, in separate eclipse projects (because I was unable to use parent projects using the Maven plugin for a long time due to bugs in the m2 plugin). Now that works.

So I combined the projects in Maven, making a base pom project, adding that as the parent to the others. Then I nested the subprojects.

When I went to commit the base project as a git project, it had decided that the subdirectories were submodules, even though there was no .gitmodules file in the root directory.

Looks like the only way to get this done would be to lose all the history in the projects that are being combined.

Just to be super clear, current have:

Project A (repo A)
Project B (repo B)
Project C (repo C)

what I want is:

New Base Project D (repo D)
   /Project A
   /Project B
   /Project C

I would rather not lose any history but if I have to, I guess I could attic the prior versions. I don't think I want submodules, as those seem to be geared towards including remote repos that are not under your control.

Turned the solution into a bash script. It assumes that the subs you want to add are in subdirectories on the same level with the parent. Here it is:

#! /bin/bash
git remote add -f $1 ../$1
git merge -s ours --no-commit $1/master
git read-tree --prefix=$1 -u $1/master
git commit -m "Added project $1"

Git is amazing..

Rob
  • 11,446
  • 7
  • 39
  • 57

3 Answers3

13

You can do something called a "subtree merge" to combine multiple repositories into one. Let's suppose want to merge ~/projects/alpha and ~/projects/beta into a new project, ~/projects/multi:

$ cd ~/projects/multi
$ git init

Merge in the "alpha" project...

$ git remote add -f alpha ~/projects/alpha
$ git merge -s ours --no-commit --allow-unrelated-histories alpha/master
$ git read-tree --prefix=alpha -u alpha/master
$ git commit -m "Added project alpha"

Merge in the "beta" project the same way. If the change is permanent, then you can delete the alpha remote in your new project. If there is still development in the alpha repo, then you can not only keep history, but pull in new changes too.

All history will still be there, and the project will be in a subdirectory. I use this on my home computer for the "dead projects repository" -- a massive git repository containing everything I've ever worked on that is either abandoned or not large enough for its own repo.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • This looks like a great solution, will try this tonight. Thanks. – Rob May 25 '11 at 01:17
  • Nice, just finished doing this on the first 2 projects. Looks great. Thanks. – Rob May 25 '11 at 02:20
  • Hi Dietrich? Went and did a git log on one of the files for the first time since migrating. Only shows my commit moving the file into the project, so it looks like this history is gone. – Rob May 26 '11 at 22:46
  • I assure you the history is there. Look in `git log` or `gitk` to reassure yourself. Try running `git blame` or `git annotate` on the file. From what I gather, `git log --follow` doesn't always do the right thing — the history is still there, the tool to look at it is broken. – Dietrich Epp May 28 '11 at 11:16
  • Hey Dietrich, would adding --log to the merge command make it easier to get at the commit history when using git log? – Topher Fangio Sep 15 '11 at 21:25
  • I don't know if I was doing something wrong but I got the error message: "fatal: refusing to merge unrelated histories". This is quite an old answer so something might have changed in between. Anyway, the command completed when I added "--allow-unrelated-histories" as in "git merge -s ours --no-commit --allow-unrelated-histories alpha/master". I still don't know if that was a correct solution though. – loop Dec 17 '20 at 13:47
  • Yes, `--allow-unrelated-histories` is now required. – Dietrich Epp Dec 17 '20 at 20:54
2

I don't have enough reputation to comment on your history question, so I have to write an answer.

Use --follow with log

--follow
       Continue listing the history of a file beyond renames (works only
       for a single file).
tewe
  • 2,707
  • 3
  • 22
  • 18
  • Unfortunately, `git log --follow` doesn't work in this situation. Try it yourself — it gives empty output. Apparently it doesn't follow merge commits very well. – Dietrich Epp May 28 '11 at 11:17
  • I didn't know that, but at least I can comment now :) – tewe May 30 '11 at 07:21
0

What I would do is go for submodules. But if you really want to combine the repos, do the following:

  • create the new repository
  • make an initial commit
  • make branches from there to every project what you want to merge
  • for every project that you want to merge:
    • switch to its temporary branch
    • merge the original repository
    • move it to its project directory (with git mv)
    • commit
  • merge (to master) and delete every temporary project branches
tamasd
  • 5,747
  • 3
  • 25
  • 31