Monday, November 25, 2013

Splitting a Git repository into multiple repositories

Today I thought I would pass along a helpful code organization tip. Occasionally I've run across the need to split an existing git repository into multiple repositories and have wanted to keep the histories intact for each split out repository. One common scenario where this arises is when you want to refactor out a piece of code or submodule from an existing project into it's own library for re-use.

Splitting an existing git repository into multiple repositories is actually pretty straight forward if you use git's subtree command. A git subtree is simply a sub folder within the existing repository that you can commit, branch, and merge. The easiest way to explain how to do this is with an example.


Let's pretend we have a project called MyProj that is really made up of two sub-projects ProjA and ProjB that we want to split into their own repositories. The first thing we need to do is make sure we're in the directory of the git repository that we want to split up.

$ cd /path/to/MyProj

I like to remove the origin remote so I don't accidentally push something to origin. This allows me to always start over if I mess something up.

$ git remote rm origin

Now we can split ProjA and ProjB into their own subtrees.  We're going to use the -b argument which tells git to create a new branch for the split subtree with it's own complete history

$ git subtree split -P relative/folder/for/ProjA -b ProjA
$ git subtree split -P relative/folder/for/ProjB -b ProjB
For me the easiest thing to do at this point is to create a new empty git repository for ProjA and ProjB where I can fetch the new branch, add my new remote repository, and then push it to the origin remote's master branch. This presupposes that you've created new empty remote repositories for ProjA and ProjB.

Here I'm going to create the new local repository for ProjA as a sibling folder to the original project. Creating the new ProjB repository is the exact same process.

$ cd ..
$ mkdir ProjARepo
$ cd ProjARepo

Before we do anything with the ProjA subtree we need to initialize our new empty git repository

$ git init

Now that we have an empty git repository we can fetch the ProjA branch from the origin MyProj repository.

$ git fetch ../MyProj ProjA
$ git checkout -b master FETCH_HEAD

The last thing we have to do is add the origin remote for the repository and push our changes to it's master branch.

$ git remote add origin git@github.com:ProjA.git
$ git push -u origin master

And there you have it. You now have separate repositories for ProjA and ProjB.  At this point you can remove them from MyProj or remove MyProj alltogether if ProjA and ProjB were the only things in the original repository.

No comments:

Post a Comment