ABCplus
ABCplus

Reputation: 4021

Copy subdirectories from Git repo into a new repository (with a new directory structure)

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

Answers (2)

ABCplus
ABCplus

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

Mark Adelsberger
Mark Adelsberger

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

Related Questions