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?
To merge a A within B:
1) In the project A
2) In the project B
In this branch do all operations you need to do and commit them.
C) Then back to the master and a classical merge between the two branches:
A single branch of another repository can be easily placed under a subdirectory retaining its history. For example:
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:
Where
<rev>
is a SHA-1 commit hash. You can still see the history, blame some changes.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.
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.
I have gathered a lot of information here on Stack OverFlow, etc., and have manage to put a script together which solves the problem for me.
The caveat is that it only takes into account the 'develop' branch of each repository and merges it into a separate directory in a completely new repository.
Tags and other branches are ignored - this might not be what you want.
The script even handles feature branches and tags - renaming them in the new project so you know where they came from.
You can also get it from http://paste.ubuntu.com/11732805
First create a file with the URL to each repository, e.g.:
Then call the script giving a name of the project and the path to the script:
The script itself has a lot of comments which should explain what it does.
If you want to put the files from a branch in repo B in a subtree of repo A and also preserve the history, keep reading. (In the example below, I am assuming that we want repo B's master branch merged into repo A's master branch.)
In repo A, first do the following to make repo B available:
Now we create a brand new branch (with only one commit) in repo A that we call
new_b_root
. The resulting commit will have the files that were committed in the first commit of repo B's master branch but put in a subdirectory calledpath/to/b-files/
.Explanation: The
--orphan
option to the checkout command checks out the files from A's master branch but doesn't create any commit. We could have selected any commit because next we clear out all the files anyway. Then, without committing yet (-n
), we cherry-pick the first commit from B's master branch. (The cherry-pick preserves the original commit message which a straight checkout doesn't seem to do.) Then we create the subtree where we want to put all files from repo B. We then have to move all files that were introduced in the cherry-pick to the subtree. In the example above, there's only aREADME
file to move. Then we commit our B-repo root commit, and, at the same time, we also preserve the timestamp of the original commit.Now, we'll create a new
B/master
branch on top of the newly creatednew_b_root
. We call the new branchb
:Now, we merge our
b
branch intoA/master
:Finally, you can remove the
B
remote and temporary branches:The final graph will have a structure like this:
I wanted to move a small project to a subdirectory of a larger one. Since my small project did not have many commits, I used
git format-patch --output-directory /path/to/patch-dir
. Then on the larger project, I usedgit am --directory=dir/in/project /path/to/patch-dir/*
.This feels way less scary and way more cleaner than a filter-branch. Granted, it may not be applicable to all cases.
The submodule approach is good if you want to maintain the project separately. However, if you really want to merge both projects into the same repository, then you have a bit more work to do.
The first thing would be to use
git filter-branch
to rewrite the names of everything in the second repository to be in the subdirectory where you would like them to end up. So instead offoo.c
,bar.html
, you would haveprojb/foo.c
andprojb/bar.html
.Then, you should be able to do something like the following:
The
git pull
will do agit fetch
followed by agit merge
. There should be no conflicts, if the repository you're pulling to does not yet have aprojb/
directory.Further searching indicates that something similar was done to merge
gitk
intogit
. Junio C Hamano writes about it here: http://www.mail-archive.com/git@vger.kernel.org/msg03395.html