Skip to content

Git: Convert a folder to another repository (or a Git submodule)

February 4, 2016

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.

bash
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:

bash
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.

bash
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:

bash
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:

bash
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

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