Jay Taylor's notes
back to listing indexDetach (move) subdirectory into separate Git repository
[web search]
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:
But I would like this instead:
|
|||||||||||||||
protected by lifetimes Jun 30 '13 at 0:11This question is protected to prevent "thanks!", "me too!", or spam answers by new users. To answer it, you must have earned at least 10 reputation on this site (the association bonus does not count). |
|||||||||||||||
|
|||||||||||||||
Update: This process is so common, that the git team made it much simpler with a new tool, You want to clone your repository and then use
Note: For most uses, Edit: various suggestions from comments below were incorporated to make sure, for instance, that the repository is actually shrunk (which was not always the case before). |
|||||||||||||||||||||||||||||||||
|
The Easy Way™It turns out that this is such a common and useful practice that the overlords of git made it really easy, but you have to have a newer version of git (>= 1.7.11 May 2012). See the appendix for how to install the latest git. Also, there's a real-world example in the walkthrough below.
... WalkthroughThese are the same steps as above, but following my exact steps for my repository instead of using Here's a project I have for implementing JavaScript browser modules in node:
I want to split out a single folder,
I now have a new branch,
Next I create a new repo on Github or bitbucket, or whatever and add it is the
Happy day! Note: If you created a repo with a
Lastly, I'll want to remove the folder from the bigger repo
... AppendixLatest git on OS XTo get the latest version of git:
To get brew for OS X: Latest git on Ubuntu
If that doesn't work (you have a very old version of ubuntu), try
If that still doesn't work, try
Thanks to rui.araujo from the comments. clearing your historyBy default removing files from git doesn't actually remove them from git, it just commits that they aren't there anymore. If you want to actually remove the historical references (i.e. you have a committed a password), you need to do this:
After that you can check that your file or folder no longer shows up in the git history at all
However, you can't "push" deletes to github and the like. If you try you'll get an error and you'll have to So if you want to delete history from the "origin" - meaning to delete it from github, bitbucket, etc - you'll need to delete the repo and re-push a pruned copy of the repo. But wait - there's more! - If you're really concerned about getting rid of a password or something like that you'll need to prune the backup (see below). making
|
|
git subtree is still part of the 'contrib' folder and isn't installed by default on all distros. github.com/git/git/blob/master/contrib/subtree
– onionjake
Aug 2 '13 at 14:06
|
||||
|
@krlmlr sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh sudo ln -s /usr/share/doc/git/contrib/subtree/git-subtree.sh /usr/lib/git-core/git-subtree To activate on Ubuntu 13.04
– rui.araujo
Aug 26 '13 at 6:39
|
||||
|
If you have pushed a password to a public repository, you should change the password, not try to remove it from the public repo and hope nobody saw it.
– Miles Rout
Sep 18 '13 at 3:43
|
||||
|
this seems to make a new repo with the contents of
ABC/ , but the new repo doesn't contain the folder ABC/ itself, as the question asked. How would you do this?
– woojoo666
Oct 8 '14 at 12:14
|
||||
|
|||||
Paul's answer creates a new repository containing /ABC, but does not remove /ABC from within /XYZ. The following command will remove /ABC from within /XYZ:
Of course, test it in a 'clone --no-hardlinks' repository first, and follow it with the reset, gc and prune commands Paul lists. |
|||||||||||||||||||||||||||||||||
|
I’ve found that in order to properly delete the old history from the new repository, you have to do a little more work after the
There is an explanation of this in the manual for filter-branch. |
|||||||||||||||||||||||||||||||||
|
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:
|
||||
Update: The git-subtree module was so useful that the git team pulled it into core and made it git-subtree may be useful for this http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (deprecated) http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/ |
|||||||||
|
This is no longer so complex you can just use the git filter-branch command on a clone of you repo to cull the subdirectories you don't want and then push to the new remote.
|
|||||||||||||||
|
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:
|
|||||||||||||||||||||||||||
|
To add to Paul's answer, I found that to ultimately recover space, I have to push HEAD to a clean repository and that trims down the size of the .git/objects/pack directory. i.e. $ mkdir ...ABC.git $ cd ...ABC.git $ git init --bare After the gc prune, also do: $ git push ...ABC.git HEAD Then you can do $ git clone ...ABC.git and the size of ABC/.git is reduced Actually, some of the time consuming steps (e.g. git gc) aren't needed with the push to clean repository, i.e.: $ git clone --no-hardlinks /XYZ /ABC $ git filter-branch --subdirectory-filter ABC HEAD $ git reset --hard $ git push ...ABC.git HEAD |
||||
Here is a small modification to CoolAJ86's "The Easy Way™" answer in order to split multiple sub folders (let's say The Easy Way™ (multiple sub folders)
|
|||||||||||||||
|
Proper way now is the following:
GitHub now even have small article about such cases. But be sure to clone your original repo to separate directory first (as it would delete all the files and other directories and you probable need to work with them). So your algorithm should be:
|
|||
For what it's worth, here is how using GitHub on a Windows machine. Let's say you have a cloned repo in residing in Github:
Bash Prompt:
|
||||
Use this filter command to remove a subdirectory, while preserving your tags and branches:
|
|||||||||
|
I had exactly this problem but all the standard solutions based on git filter-branch were extremely slow. If you have a small repository then this may not be a problem, it was for me. I wrote another git filtering program based on libgit2 which as a first step creates branches for each filtering of the primary repository and then pushes these to clean repositories as the next step. On my repository (500Mb 100000 commits) the standard git filter-branch methods took days. My program takes minutes to do the same filtering. It has the fabulous name of git_filter and lives here: https://github.com/slobobaby/git_filter on GitHub. I hope it is useful to someone. |
|||
As I mentioned above, I had to use the reverse solution (deleting all commits not touching my FIRST, This is a cosmetic issue which I can probably live with (he says...backing away slowly with eyes averted). SECOND the few commits that remain are pretty much ALL duplicated! I seem to have acquired a second, redundant timeline that spans just about the entire history of the project. The interesting thing (which you can see from the picture below), is that my three local branches are not all on the same timeline (which is, certainly why it exists and isn't just garbage collected). The only thing I can imagine is that one of the deleted commits was, perhaps, the single merge commit that In the case of crazy mergefest-O-RAMA, I'll likely be leaving that one alone since it has so firmly entrenched itself in my commit history—menacing at me whenever I come near—, it doesn't seem to be actually causing any non-cosmetic problems and because it is quite pretty in Tower.app. |
||||
You might need something like "git reflog expire --expire=now --all" before the garbage collection to actually clean the files out. git filter-branch just removes references in the history, but doesn't remove the reflog entries that hold the data. Of course, test this first. My disk usage dropped dramatically in doing this, though my initial conditions were somewhat different. Perhaps --subdirectory-filter negates this need, but I doubt it.
|
||||
The Easier Way
|
|||||||||
|
Check out git_split project at https://github.com/vangorra/git_split Turn git directories into their very own repositories in their own location. No subtree funny business. This script will take an existing directory in your git repository and turn that directory into an independent repository of its own. Along the way, it will copy over the entire change history for the directory you provided.
|
|||
It appears that most (all?) of the answers here rely on some form of
If you do a normal git filter to extract "move_me_renamed" you will lose file change history that occurred from back when it was initially named move_me (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, ex:
(follow steps 6-11 here if you want to push this 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. |
||||
Put this into your gitconfig:
|
|||
I'm sure git subtree is all fine and wonderful, but my subdirectories of git managed code that I wanted to move was all in eclipse. So if you're using egit, it's painfully easy. Take the project you want to move and team->disconnect it, and then team->share it to the new location. It will default to trying to use the old repo location, but you can uncheck the use-existing selection and pick the new place to move it. All hail egit. |
|||||||||
|
Your Answer
Not the answer you're looking for? Browse other questions tagged git git-subtree git-filter-branch or ask your own question.
asked |
7 years ago |
viewed |
181970 times |
active |
Linked
Related
Hot Network Questions
- I was allowed to enter the airport terminal by showing a boarding pass for a future flight. Should I be concerned about "security"?
- Simplify list of rules
- Are human fetal cells used to produce Pepsi?
- Is there a Pokémon that can solo the Elite Four without any restoring items?
- awk system call with inverted effect
- How to replace 8-sided dice with other dice
- Strange craters in Afghanistan
- Can I reset a CSS property rather than overriding it?
- Is it normal to treat Math Theorems as "Black Boxes"
- Goodness Giza Golf!
- What game did I see in Verona, Italy?
- What difficulty would the Roman Empire have besieging a fantasy kingdom's 49m wall?
- What's this hole with a lock symbol on the back of my monitor?
- Arrow not showing consistently in tikz \draw
- Can my employer see what I do on the internet when I am connected to the company network?
- Why rotational matrices are not commutative?
- Why do Internet forums tend to prohibit responding to inactive threads?
- Shortest path between two points with n hops
- What does the letter 'u' mean in /dev/urandom?
- Do n and n^3 have the same set of digits?
- Simple geometry. Or is it?
- How not to lose confidence in front of supervisor?
- Is it typical for a president to fill his cabinent with campaign staff and political allies?
- Is there an easier way to test argument validation and field initialization in an immutable object?
Technology | Life / Arts | Culture / Recreation | Science | Other | ||||||
---|---|---|---|---|---|---|---|---|---|---|