When working with Git repositories, sometimes become necessary to move files/directories from one repository into a new one. This process isn’t simple as you might think especially if you want to preserve the history! So how to do that?
First of all you have to clone your repository into a temporary folder, with something like:
git clone -b <branch> <your-git-url> <new-git-url>
Now the black-magic:
cd <new-git-url>
git filter-branch --tree-filter 'rm -rf `ls|/usr/bin/grep -v <directory_or_filename_to_keep>`' --prune-empty HEAD
After entering in the directory <new-git-url>, you have basically to run the git filter-branch command applying the –tree-filter option for rewriting the tree and its content. The argument is evaluated as shell command in the working directory. So we are going to apply the command
rm -rf `ls|/usr/bin/grep -v <directory_or_filename_to_keep>`
which recursively remove all files and directory coming from the result of listing the content of the current working directory, filtered by grep. The grep -v switch will invert the pattern match, so we want a match all files and directories NOT matching <directory_or_filename_to_keep>. The execution of the command might take a while, but at the end you will get a clean repo having only the <directory_or_filename_to_keep> you want including its related history you can check with
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
Finally we have to do our last operations, cleanup unnecessary files and optimize the local repository
git gc --aggressive git prune git clean -df
setup the new remote
git remote set-url origin <new-git-url> git push --force
and we are done!
If we want to go further with more complicated pattern matches fitting our repository content, we could use the grep power but don’t forget to apply -v for the inverse matching otherwise you get the contrary ;-)!