ChaseMedallion
ChaseMedallion

Reputation: 21764

How can I extract a portion of a git repository into it's own repo while retaining history and file structure?

I have a large git repository with a folder structure like so:

/A
/B
/C
/D
...

I would like to extract the /A and /B folders into their own repo while maintaining history (I only care about the master branch). Thus, the new repo would look like:

/A
/B

How can I do this? I found git filter-branch which helps with the history re-write, but I'm not sure how to use it for keeping around multiple subdirectories.

Upvotes: 5

Views: 608

Answers (2)

KnightFox
KnightFox

Reputation: 3252

git clone initial final
cd final
git filter-branch --tree-filter 'rm -rf <list of folders separated by space>' HEAD

Above commands will remove any folders mentioned in the list but your original commit history will be maintained.

git filter-branch -f --prune-empty 

Can then be used to remove any empty commits that might show up from your list of deleted folders.

Alternately, if you have a large repository which has significantly long history, this could take a while. In that case, you could take a slightly different approach -

Start by creating separate repositories for each folder you want to migrate. This can be done using filter-branch command as follows

 git filter-branch –prune-empty –subdirectory-filter A/ master
 git filter-branch –prune-empty –subdirectory-filter B/ master

Each one will have the contents of the respective folders along with all their history. You can then push these as temp repositories on remote. ( these will also act as checkpoints in case you need to re-do the process)

Next, create your new repository

git clone <remote path> NewRepo
cd NewRepo

# add a readme file
touch Readme.md
git add .
git commit -am "Adding ReadMe file"

You can then merge your individual folders (A and B repos) into NewRepo

# Merge Repo A
git remote add -f A <remote path for A>
git merge -s ours --no-commit A/master
git read-tree --prefix=A/ -u A/master
git commit -m "Merge A into NewRepo"
git remote remove A

# Merge Repo B
git remote add -f B <remote path for B>
git merge -s ours --no-commit B/master
git read-tree --prefix=B/ -u B/master
git commit -m "Merge B into NewRepo"
git remote remove B

Next you can confirm that your origin is set to point to the NewRepo and push code

git remote add origin <remote path for NewRepo>
git push origin master

NewRepo should now contain both the folders and all their history.

Upvotes: 5

Christopher
Christopher

Reputation: 404

The filter-branch may take a while to run, but I would try duplicating the repository locally and using it for tests.

git clone repoA repoB
cd repoB
git filter-branch --tree-filter 'rm -rf C D <other files you DON'T want>' HEAD

Again, that may take a long time to run, but I think it will do what you're looking for.

Upvotes: 0

Related Questions