Monorepos or “collection repositories” tend to grow over time. At some point, a part of them deserves its own life: independent deployments, a dedicated team, or separate release cycles.
The tricky part is obvious: How do you split out a subproject without losing its Git history?
The answer is a powerful tool called git-filter-repo.
Step 1: Clone the Repository into a New Directory
Do not work in your existing checkout.
Instead, clone the repository into a fresh directory by running the following commands in Git Bash:
git clone ssh://git@github.com/project/Collection.git
cd Collection
We avoid working directly on origin and create a temporary branch:
git checkout -b split
This provides a safety net while rewriting history.
Step 2: Filter the Repository
Now comes the crucial step. Using git-filter-repo, we keep only the desired path and move it to the repository root.
python -m git_filter_repo \
--path path/to/my/subproject/ \
--path-rename path/to/my/subproject/: \
--force
--pathdefines what should remain--path-renamemoves the directory to the repository root--forceis required because history is rewritten
After this step, the repository contains only the former subdirectory — with its full Git history intact.
Step 3: Push to new repository
Now point the repository to its new remote location:
git remote add origin ssh://git@github.com/project/NewProject.git
If an origin already exists, remove it first:
git remote remove origin
Rename the working branch to main:
git branch -m split main
Finally, push the rewritten history to the new repository:
git push -u origin main
That’s it — the new repository is ready, complete with a clean and meaningful history.
Conclusion
git-filter-repo makes it possible to split repositories precisely. Instead of copying files and losing context, you preserve history — which is invaluable for git blame, audits, and understanding how the code evolved.
When refactoring at repository level, history is not baggage. It’s documentation.
Happy splitting!