How to extract a git subdirectory and make a submodule out of it?

Nowadays there's a much easier way to do it than manually using git filter-branch: git subtree

Installation

NOTE git-subtree is now part of git (if you install contrib) as of 1.7.11, so you might already have it installed. You may check by executing git subtree.


To install git-subtree from source (for older versions of git):

git clone https://github.com/apenwarr/git-subtree.git

cd git-subtree
sudo rsync -a ./git-subtree.sh /usr/local/bin/git-subtree

Or if you want the man pages and all

make doc
make install

Usage

Split a larger into smaller chunks:

# Go into the project root
cd ~/my-project

# Create a branch which only contains commits for the children of 'foo'
git subtree split --prefix=foo --branch=foo-only

# Remove 'foo' from the project
git rm -rf ./foo

# Create a git repo for 'foo' (assuming we already created it on github)
mkdir foo
pushd foo
git init
git remote add origin [email protected]:my-user/new-project.git
git pull ../ foo-only
git push origin -u master
popd

# Add 'foo' as a git submodule to `my-project`
git submodule add [email protected]:my-user/new-project.git foo

For detailed documentation (man page), please read git-subtree.txt.


Checkout git filter-branch.

The Examples section of the man page shows how to extract a sub-directory into it's own project while keeping all of it's history and discarding history of other files/directories (just what you're looking for).

To rewrite the repository to look as if foodir/ had been its project root, and discard all other history:

   git filter-branch --subdirectory-filter foodir -- --all

Thus you can, e.g., turn a library subdirectory into a repository of its own.
Note the -- that separates filter-branch options from revision options, and the --all to rewrite all branches and tags.