I have a Git repository which contains a number of subdirectories. Now I have found that one of the subdirectories is unrelated to the other and should be detached to a separate repository.
How can I do this while keeping the history of the files within the subdirectory?
I guess I could make a clone and remove the unwanted parts of each clone, but I suppose this would give me the complete tree when checking out an older revision etc. This might be acceptable, but I would prefer to be able to pretend that the two repositories doesn't have a shared history.
Just to make it clear, I have the following structure:
XYZ/
.git/
XY1/
ABC/
XY2/
But I would like this instead:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
Here is a small modification to CoolAJ86's "The Easy Way™" answer in order to split multiple sub folders (let's say
sub1
andsub2
) into a new git repository.The Easy Way™ (multiple sub folders)
Prepare the old repo
Note:
<name-of-folder>
must NOT contain leading or trailing characters. For instance, the folder namedsubproject
MUST be passed assubproject
, NOT./subproject/
Note for windows users: when your folder depth is > 1,
<name-of-folder>
must have *nix style folder separator (/). For instance, the folder namedpath1\path2\subproject
MUST be passed aspath1/path2/subproject
. Moreover don't usemv
command butmove
.Final note: the unique and big difference with the base answer is the second line of the script "
git filter-branch...
"Create the new repo
Link the new repo to Github or wherever
Cleanup, if desired
Note: This leaves all the historical references in the repository.See the Appendix in the original answer if you're actually concerned about having committed a password or you need to decreasing the file size of your
.git
folder.The original question wants XYZ/ABC/(*files) to become ABC/ABC/(*files). After implementing the accepted answer for my own code, I noticed that it actually changes XYZ/ABC/(*files) into ABC/(*files). The filter-branch man page even says,
In other words, it promotes the top-level folder "up" one level. That's an important distinction because, for example, in my history I had renamed a top-level folder. By promoting folders "up" one level, git loses continuity at the commit where I did the rename.
My answer to the question then is to make 2 copies of the repository and manually delete the folder(s) you want to keep in each. The man page backs me up with this:
Edit: Bash script added.
The answers given here worked just partially for me; Lots of big files remained in the cache. What finally worked (after hours in #git on freenode):
With the previous solutions, the repository size was around 100 MB. This one brought it down to 1.7 MB. Maybe it helps somebody :)
The following bash script automates the task:
I recommend GitHub's guide to splitting subfolders into a new repository. The steps are similar to Paul's answer, but I found their instructions easier to understand.
I have modified the instructions so that they apply for a local repository, rather than one hosted on GitHub.
It appears that most (all?) of the answers here rely on some form of
git filter-branch --subdirectory-filter
and its ilk. This may work "most times" however for some cases, for instance the case of when you renamed the folder, ex:If you do a normal git filter style to extract "move_me_renamed" you will lose file change history that occurred from back when it was initially move_this_dir (ref).
It thus appears that the only way to really keep all change history (if yours is a case like this), is, in essence, to copy the repository (create a new repo, set that to be the origin), then nuke everything else and rename the subdirectory to the parent like this:
git branch -a
git checkout --track origin/branchABC
cp -r oldmultimod simple
cd simple
git rm otherModule1 other2 other3
git mv moduleSubdir1/* .
rmdir moduleSubdir1
git status
git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
git remote -v
git push
git checkout branch2
This follows the github doc "Splitting a subfolder out into a new repository" steps 6-11 to push the module to a new repo.
This will not save you any space in your .git folder, but it will preserve all your change history for those files even across renames. And this may not be worth it if there isn't "a lot" of history lost, etc. But at least you are guaranteed not to lose older commits!
The Easier Way
git splits
. I created it as a git extension, based on jkeating's solution.Split the directories into a local branch
#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ XY1 XY2
Create an empty repo somewhere. We'll assume we've created an empty repo called
xyz
on GitHub that has path :git@github.com:simpliwp/xyz.git
Push to the new repo.
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz git@github.com:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master
Clone the newly created remote repo into a new local directory
#change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone git@github.com:simpliwp/xyz.git