Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge nested git repo into parent repo, retaining history?

Tags:

git

Now I know most git experts will immediately think of git rebase, but I am using the word "rebase" in the more general sense: I have the following structure of my project:

.
..
.git
tools
lib
src
    .git
build

Both . and ./src directory are evidently git repositories, and have literally a long history and large number of commits each. The repository in . ignores src directory (which is its own repo).

I have just realized that I would instead want to just have one single repo in . tracking everything including the source files, because frankly, the build system is evolving along with the source code, and has become quite extensive.

My problem is that I don't know how to have this repository retain history that is now part of the repository in src. Is it even possible? This is what I meant by 'rebasing' - if changes in ./src/main.c are tracked by ./src/.git across some N commits, then I want to retain these changes and have them be part of the new repository ./.git. Same history, rebased file path.

UPDATE

Subtree merging is something else than what I want, from what I gathered on SO. In short, it does much more than what I need. I merely need the content of the old repo, together will all branches of development and all commits, tags, etc to look as if they were always part of the parent repo. In essense, the only change is paths to files themselves - where before the child repo tracked ./main.c, the new repo will now track ./src/main.c, and since as I have heard, git tracks content, not files, then changing file paths like the above and references to these paths, should be rather trivial, correct?

like image 270
amn Avatar asked Feb 12 '13 16:02

amn


1 Answers

Quick and easy way:

Rename all files in src, so they will start with src/. Add src repo as remote, fetch & merge. Drop old src repo, everything is now in ./.

This will leave you with this action recorded in history.

History rewrite:

To make this merge invisible, you need to use git filter-branch --tree-filter to add src/ prefix in src repository. Then add this as a remote to ./ repository and fetch it (no merge yet). To blend history nicely, you need to reorder commits. Use git log --date-order master src/master to retrieve these commits in correct order and cherry-pick them:

git checkout -b new-master your-first-commit
git log --format='%H' --date-order --reverse master src/master | xargs git cherry-pick

This basically does merge sort on your commits and lines them up to linear history.

This is will not preserve your merges, so dont do it unless you have flat history. In that case use only filter-branch and then do normal merge.

like image 163
Josef Kufner Avatar answered Nov 15 '22 04:11

Josef Kufner