Many moons ago I added a subtree to my
git repository. This subtree included several folders and files. I added the subtree instead of creating a submodule (as recommended). Now I realize I only want one of the files in the subtree and none of the rest. Even worse, when others
clone my repository, what they get is not what is expected—there is some conflict with the subtree and the other code that I've created.
I can get ride of the files/folders with
git rm subtree–folder1 subtree_folder2 subtree_files.*
however, I'm still left with a lengthy commit history from the subtree.
I've done a fair amount of development since I originally added the subtree and can't lose the commit history that I've generated.
In short this is what I would like:
Is this possible?
PS. One possible complication is that I moved the single header file I wanted to keep from the subtree to some folder in my code. I hope this is not what is keeping me from forgetting the subtree history.An Attempt
After a fresh checkout from the remote server I have the following:
$ ls .git CMakeLists.txt Read.cpp logging.conf .gitignore ENDF6 TestData src .sparse-checkout LICENCE doc test .travis.yml README.md include tools
.gitignore only has:
When I try the command as suggested I don't get a very happy response:
$ git filter-branch --index-filter 'git rm --cached -rf test tools src doc LICENCE README.md .travis.yml' HEAD Rewrite 2fec85e41e40ae18efd1b130f55b14166a422c7f (1/1701)fatal: pathspec 'test' did not match any files index filter failed: git rm --cached -rf test tools src doc LICENCE README.md .travis.yml
I'm not sure why it says it has a problem with
test when it is clearly there. I'm baffled.
You can use
git filter-branch to apply an operation to all the commits you made in a branch. This includes deleting files from each commit as you rewrite the entire history. A good description and instructions is available here: http://gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file.html. You may find the following question useful as well: Completely remove files from Git repo and remote on GitHub (it is where I found the link). The actual command you will run with this solution is going to be something like
git filter-branch --index-filter 'git rm --cached -rf subtree–folder1 subtree_folder2' HEAD.
Another way, which is probably overkill for what you are doing, is cherry-picking. Cherry-picking allows you to rewrite any portion of your history that you like with any level of detail you like:
http://git-scm.com/docs/git-cherry-pick. You will want to do something like
git reset --hard <HASH of commit that introduced the subtree>, followed by a series of
git cherry-pick -n <following commit hashes> git reset git add -p git commit
for each subsequent commit you had made. This will allow you to remove the subtree from each commit you made in the past. You can refer to partly cherry-picking a commit with git for more information on effective cherry-picking. When you are done with this version of the deletion, you will want to remove the old commits that are no longer part of your branch:
git reflog expire --expire-unreachable=now --all git gc --prune=now
Other referenced questions:How to move a branch backwards in git?Listing and deleting Git commits that are under no branch (dangling?)