It’s a common doubt in Git how to organize your repositories: should I have separated repositories for modules or related apps? Should I throw everything in a single repository?

If you have used a single repository for different (though related) things, you may want in the future separete some folders in multiple repositories, maybe in intent of using Git submodules (or not).

Fortunaly, doing so in Git is easy with the filter-branch command. And it will keep all the history related to the folder untouched in the new repository!

Make a copy of the original repository

The filter-branch command is destructive: you will lose all history not relate to that folder! You are supposed to run it in a copy, not in the original repository.

cp -r my-repository my-repository-2
cd my-repository-2

Remove all the remotes

Just to prevent a big mess in case of an accidental force push:

git remote -v
=> origin http://github.com/yourusername/my-repository
git remote remove origin

Filter the history based in a directory

Here the magic happens. Just run the command below. Don’t forget ro replace my-folder with the folder you want to filter.

git filter-branch --subdirectory-filter my-folder -- --all

Now do git log and you will see that the history only contains commits related to the specified folder. Also, the filtered folder was moved to the root.

Optionally remove the folder from the previous repository history

About the original repository, you have two options: just delete the folder, commit and keep the history, or rewrite the entire history to remove past references of the directory. If you choose the latter, keep in mind that other people that contribute to the code will have to clone the repository again. Also, I strongly recommend a backup of the repository.

Doing it is simple as running the following command. Change my-directory to the name of the given directory:

cd ..
cd my-repository # the original one
git filter-branch --tag-name-filter cat --index-filter 'git rm -r --cached --ignore-unmatch my-directory' --prune-empty -f -- --all

Optionally use Git submodules

Git submodules is known to not be a good option if you don’t know what you are doing. Be sure to search if it is what you really want. If it is, do the following:

First, push the repository to its new home:

git remote add origin https://github.com/yourusername/my-repository-2.git
git push origin master --tags

After, go to the original repository and add the submodule

cd ..
cd my-repository
git submodule add https://github.com/yourusername/my-repository-2.git