I've been following this excellent answer to extract a subdirectory of my git repository into its own repository, while retaining the complete history.
My repository looks like:
src/
http/
math/
tests/
http/
math/
I want to create a new branch that only contains the src/math
and tests/math
directories.
If I run the following command:
git subtree split -P src/math -b math
It creates a branch that contains the contents of the src/math
directory, but discards the src/math/
prefix.
If I try the same command with two directories:
git subtree split -P src/math -P tests/math -b math
It only extracts the contents of tests/math
, ignoring src/math
, and also discarding the tests/math
prefix.
To summarize, I would like my final repository to look like:
src/
math/
tests/
math/
That is, keeping the original directory structure but discarding everything that's not explicitly mentioned in the command-line.
How can I do that?
Depending on your needs you might get away with git filter-branch
.
I'm not entirely sure what you are trying to achieve, but if you merely want to have a repository with two directories removed (in the history?) this is probably your best shot.
See also Rewriting Git History.
$ git filter-branch --tree-filter 'rm -rf tests/http src/http' --prune-empty HEAD
This will look into each commit and remove the two directories from this commit.
Be aware that this rewrites history (i.e.: alters your commit sha) and will cause headaches if you have a common history with another repository.
Use git-subtree add
to split-in
# First create two *split-out* branches
cd /repos/repo-to-split
git subtree split --prefix=src/math --branch=math-src
git subtree split --prefix=test/math --branch=math-test
# Now create the new repo
mkdir /repos/math
cd /repos/math
git init
# This approach has a gotcha:
# You must commit something so "revision history begins",
# or `git subtree add` will complain about.
# In this example, an empty `.gitignore` is commited.
touch .gitignore
git add .gitignore
git commit -m "add empty .gitignore to allow using git-subtree"
# Finally, *split-in* the two branches
git subtree add --prefix=src/math ../repo-to-split math-src
git subtree add --prefix=test/math ../repo-to-split math-test
It worked for me with git --version
2.23.0. Also note that you can setup different prefixes at split-in time, i.e. add the src/math/
to src/
and test/math/
to test/
.
Side note: use git log
at the new repo before commiting to a remote, to see if resultant history is ok enought for you. In my case I have some commits with duplicated messages, because my repo history was so dirty, but it's ok for me.
Source
Use git-filter-repo
This is not part of git as of version 2.25.
This requires Python3 (>=3.5) and git 2.22.0
git filter-repo --path src/math --path tests/math
For my repo that contained ~12000 commits git-filter-branch took more than 24 hours and git-filter-repo took less than a minute.