Git: Convert a folder to another repository (or a Git submodule)
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