Reputation: 4021
This question is based on Detach many subdirectories into a new, separate Git repository
My repository structure looks like this:
/apps
/AAA
/BBB
/CCC
/libs
/XXX
/YYY
/ZZZ
And I would like this instead:
/AAA
/XXX
The proposed solutions in the linked question keep the original paths of the folders. I would like instead to extract a set of folders located in different paths in a new repository, where all the folder are on root.
The other constraint, is that the commit history could involve both folders together, and I would like to preserve in the same way. For example, suppose the log in the original repository contains:
"My commit message"
/apps/AAA/file1.txt
/libs/XXX/file2.txt
I would like to see the equivalent in the new repo:
"My commit message"
/AAA/file1.txt
/XXX/file2.txt
How to achieve this?
Upvotes: 1
Views: 255
Reputation: 4021
I fixed my case this way:
1) split the subdirs from the original repo using git splits command:
git splits -b tmp_branch apps/AAA libs/XXX
2) move the folders to a new path using git-mv-with-history command (so preserving history):
git checkout tmp_branch
git-mv-with-history apps/AAA/=. libs/XXX/=.
3) push the branch to a new repo
git push ../new_repo/ +tmp_branch:master
Or, if you're working on GitHub:
git push [email protected]:accountname/new_repo +tmp_branch:master
Upvotes: 0
Reputation: 45659
The tricky part of this is history preservation. It can be done with git filter-branch
.
You almost could get by with a subdirectory-filter
, but you could only process one directory at a time (so it would be tricky) and any commit that affected multiple of the directories would not be represented nicely in the result..
Instead you need to use a tree-filter
, and unfortunately that means the process may take considerable time to run. Basically the process will check out each commit (including writing the work tree), run your filter script (which will move the directories you want and remove everything else), and commit the result. You probably want to run this on fast storage - even a RAMDisk wouldn't be overkill if there's much history at all.
Exactly what your filter script should look like depends somewhat on the environment you'll run in; but a sample filter.sh in bash might look like
#! /bin/bash
mv apps/AAA .
mv libs/XXX .
rm -r apps libs
and then you run
git filter-branch --tree-filter filter.sh --prune-empty
This creates some "backup refs" (e.g. originals/refs/heads/master
) which you'll want to clean up.
Once those refs are removed, the original commits are still in the repo. If you want to get rid of them, the cleanest way is to clone (using a file://
url if doing it locally).
Upvotes: 1