I recently needed to extract a feature from a project to its own repo so I could publish as a standalone library:
# from
/some-project/src/some-folder/some-feature/*
# to
/some-package/src/*
Additionally, I wanted to retain the history so the new repo would show the full development process.
The Git command to accomplish this would have been filter-branch
but it has been depreciated in favour of a Python addon to Git called git filter-repo.
The addon did exactly what I wanted, but took quite a lot of experimentation to crack (mainly because of moving from src
to src
) so I've outlined the process and steps below so you can see how it is done.
The addon requires Git 2.22.0 as a minimum, so check your version and upgrade if needs be:
git --version
Then install the addon. I found the easiest way was via the Python package installer:
pip3 install git-filter-repo
Before looking the code, let's look at the steps the code takes.
- clone the repo that contains the feature to a new folder
- remove the origin to prevent accidentally changing the original repo
- optionally checkout a branch if you need to
- run
git filter-repo
to:- filter the original repo to the feature folder
- reparent the folder to a temp root folder
tmp
(because from and to folders are both namedsrc
) - rename the temp folder to
src
- use the
force
flag because we removed the origin
- optionally rename any checked out branch if you need to
- optionally delete all tags
Here is the code using placeholders so you can understand how it works:
git clone <repo_url> <package_name>
cd <package_name>
git remote rm origin
git checkout <branch name> # optional
git filter-repo \
--path <feature_path> \
--to-subdirectory-filter tmp \
--path-rename tmp/<feature_path>:src \
--force
git branch -m master # optional
git tag | xargs git tag -d #optional
Things to note:
- the folder names
tmp
andsrc
should be changed if you need to (because of conflicts, or you want a different structure) - the rename format is
old_name:new_name
so feel free to change this if your use case is different - the slashes allow the code to be written using multiple lines
This is the same code using concrete examples so you can see how it should look:
git clone https://github.com/some-user/some-project.git some-package
cd some-package
git remote rm origin
git checkout some-branch # optional
git filter-repo \
--path src/some-folder/some-feature \
--to-subdirectory-filter tmp \
--path-rename tmp/src/some-folder/some-feature:src \
--force
git branch -m master # optional
git tag | xargs git tag -d #optional
You should now have a brand new repo with full commit history and a folder structure like so:
+- some-package
+- src
+- *
Add your readmes, bundlers, etc. then you're done!