There are several subtrees in my repo (e.g. ./sub1/, ./sub2/, ..) which I would like to extract into separate repos, keeping commit history and the same dir structure, i.e. a new repo for sub1 should have ./sub1/ subtree from the main repo. How can I do this?
1 Answer
You can use git's filter-branch with subtree filter.
Here are the steps:
Clone a working copy. This operation will alter local repo, so we must have a working copy first. You can either do a git clone as below or just copy it.
git clone --no-hardlinks <original repository> <working copy>Use subtree fileter.
cd <working copy> git filter-branch --subdirectory-filter <subdir path to be splited> --prune-empty --tag-name-filter cat -- --all # reset current working directory git reset --hardWe have accomplished our task, it is better to do some cleaning work, because lots of old objects became unreachable.
Delete old remote
git remote rm originRemove old reflog
# clean unneeded reflog in order to free space refbak=$(git for-each-ref --format="%(refname)" refs/original/) if [ -n "$refbak" ];then echo -n $refbak | xargs -n 1 git update-ref -d fi git reflog expire --expire=now --allRepack and compress the repo
# prune loose objects git gc --aggressive --prune=now
This will make the repos structure change from
repo/ |-- sub1/ |-- sub11 |-- sub12 |-- sub2 to
repo/ |-- sub11 |-- sub12 But, it seems you want it to became
repo/ |-- sub1/ |-- sub11 |-- sub12 Then, there is one more step need to be done, rewrite the git commit history with index-filter.
# replace <subdir path> with the actual subdir path, for this case, it should be "sub1" git filter-branch --index-filter 'git ls-files -s | sed "s-\t-&<subdir path>/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD