Say your git repo consists of a subdirectory “app” and a subdirectory “database” (or “frontend” and “backend” or “team-a” and “team-b”) and you realize each directories content should be in its own repository. Here is how to split the repo.
To create a repo that consists of the content of the “database” dir and its history, execute
git filter-branch --prune-empty --tag-name-filter cat --subdirectory-filter database -- --all
and then push it to a new remote:
git remote rename origin old-origin
git remote add origin <new-remote>
git push -u origin --all
git push -u origin --tags
This is what Gitlab states on a newly created project page. However in
git push -u origin --all
“-all” should be replaced with “–mirror” because “-all” pushes all local branches only so you would need to checkout all branches you want to keep. “–mirror” pushes remote branches, too.
In the same fashion apply “filter-branches” to the “app” directory.
How does it work? "git filter-branches" rewrites git revision history of the mentioned branches by applying filters:
- The mentioned branches states "--all" so filters are applied to all branches of the repo (you need "--" before "--all" because otherwise "--all" would get interpreted as a revision)
- "--subdirectory-filter" means "only look at the history which touches this directory" and also make that directory the root of the repo.
- "--prune-empty" removes any empty commits that may get created
- Git itself recommends using "--tag-name-filter cat" when not stated, it simply updates tags (apparently "--all" does not include tags).
Top comments (3)
I like the general idea that you've got here, but I'd like to see you (or someone) break down that long command to help people understand what's actually going on.
Hi Corey, I have updated the post to explain how it works. Hope this helps.
That's awesome. Thank you for taking the extra time to explain it.