Splitting a large Git mono-repository into several smaller repositories is a bit like the old saying about cake: you want to have your cake and eat it too. As repositories grow, they become harder to manage—builds take longer, pipelines get more complex, and you may find yourself fixing issues in parts of the codebase unrelated to your work just to get your build to pass.
If this sounds familiar, you’re not alone. Eventually, the need arises to split a mono-repo. Having several smaller, focused repositories can simplify workflows and help teams take ownership of their code. But how do you do this without losing years of valuable history? Simply starting a new repo and ignoring the past isn’t ideal, and forking then deleting unrelated files leaves too much baggage. Is there a better way?
Let’s walk through the process. Git is a powerful tool, and with the help of some scripts, you can split a mono-repo while preserving the history of specific files.
Requirements
You’ll need the git-filter-repo
1 Python script. Install it with:
brew install git-filter-repo
# or
pip3 install git-filter-repo
Clone the original repository
Start by cloning your original repository under a new name:
git clone ssh://git@github.com/my/repo.git new-beginning
Disconnect from the old origin
Switch to your new clone and remove the old remote:
cd new-beginning
git switch -c feature/separate-xyz
git remote remove origin
Filter history to keep only what You need
List the files in your new repo:
ls -1
Decide which files you want to keep, then filter the history:
git filter-repo \
--force \
--path .gitattributes \
--path .gitignore \
--path .pre-commit-config.yaml \
--path CHANGELOG.md \
--path CONTRIBUTING.md \
--path Makefile \
# add other paths as needed
Clean up unreferenced files and commits
Run garbage collection to clean up:
git gc --aggressive
Set Up a New Origin
Create a new repository (if you haven’t already) and point your filtered repo to it:
git remote add origin ssh://git@github.com/my/new-beginning.git
git switch -c main
Warning
Depending on your automation and pipelines, pushing changes may trigger jobs or require updates to paths and names. Double-check everything before pushing.
If you need, modify any pipelines or automation to prevent unintended builds or release.
Push Your changes
Push your changes to the new repository:
git push -u origin HEAD:main
git push --tags
# If you need to overwrite history (be very careful!):
git push --force
Final Steps
Commit any remaining changes, push, and verify that everything works as expected.
Following this tutorial, you will end up with a new repo, with full history of changes in files that you listed and only those. It’s the cleanest way to achieve it, that I found.
“The real takeaway: You don’t have to lose your project’s history or clutter your new repo with old baggage. With the right tools and a careful approach, you can split a mono-repo cleanly and keep your workflow efficient.”