The title of this post may make it sound like it’s going to be about how git changed the face of software development and entered us into a new era of coding collaboration. No. This post is about how to copy a subtree from one git repository to another, while keeping its history.
Let’s say you’ve been working on a component in an incubator-style repository, and it’s time to move it to the main project’s repository. Simply copying the code would destroy the valuable history in the target repo, so that should be avoided. There are also lots of other components in the incubator repo that you don’t want to move.
Step 1: Export your component to a temporary repository
You can do this using git filer-branch
. Warning: this will reduce your local copy of the incubator repository to just your component.
Either clone it locally to a different path or be prepared to clone it again from the remote.
1
|
|
Now your repository has been reduced to just the contents and history of components/my-component
.
Step 2: Create a patch for the entire history of your component
Use git format-patch
to export all of your commits to a patch file. Props to @rombert for this idea.
1
|
|
I feel like this command could use some explaining. First off, we’re telling format-patch
to output everything to --stdout
. Otherwise,
it would create one patch file per commit, which can get pretty clumsy if there are lots of them. Second, we’re passing the output of
git rev-list HEAD | tail -n 1
for the --root
parameter. The enclosed command will find find the sha1
of the very first commit, while
the --root
parameter will tell format-patch
to include that commit, not start from it. Lastly, HEAD
is the target ref, which is
basically the most recent commit.
Step 3: Apply the patch
Now it’s time to add your component to the main project. Of course, you don’t want to add your component to the root of the repository (which is what all the paths in the patch are relative to). Thankfully, git supports prepending a path to all filenames in a patch.
1
|
|
Now your main project contains your component and all of its history. Some notes:
- Only one branch will be copied. If your component development happened on multiple branches, that will be lost.
- No tags will be copied to the main repository, you will need to tag your commits manually.
- Commit IDs will change, so you will not be able to copy your tags automatically.
Pretty neat.