如何删除以前添加的 git 子树及其历史记录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26107798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove previously added git subtree and its history
提问by jlconlin
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.
许多个月前,我在我的git
存储库中添加了一个子树。这个子树包括几个文件夹和文件。我添加了子树而不是创建子模块(如推荐)。现在我意识到我只想要子树中的一个文件,其余的都不想要。更糟糕的是,当其他人使用clone
我的存储库时,他们得到的不是预期的 - 与子树和我创建的其他代码存在一些冲突。
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:
简而言之,这就是我想要的:
- Remove all the subtree files/folders.
- Forget the history of all the subtree commits.
- Left with only my code and my history.
- 删除所有子树文件/文件夹。
- 忘记所有子树提交的历史。
- 只留下我的代码和我的历史。
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
Where .gitignore
only has:
build/
debug/
其中.gitignore
只有:构建/调试/
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.
我不知道为什么它说它test
在明显存在时有问题。我很困惑。
回答by Andrew C
You need to use a filter-branch along with the --prune-empty option to remove any commits that no longer introduce new changes.
您需要使用 filter-branch 和 --prune-empty 选项来删除不再引入新更改的任何提交。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch -rf dir1 dir2 dirN file1 file2 fileN' --prune-empty -f HEAD
After that, if you want to recover disk space you will need to delete all the original refs that filter branch saved, expire the reflog, and garbage collect.
之后,如果要恢复磁盘空间,则需要删除过滤器分支保存的所有原始引用,使引用日志过期并进行垃圾收集。
回答by Mad Physicist
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
.
您可以使用git filter-branch
将操作应用于您在分支中所做的所有提交。这包括在重写整个历史记录时从每次提交中删除文件。这里有一个很好的描述和说明:http: //gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file.html。您可能会发现以下问题也很有用:从 GitHub 上的 Git 存储库和远程文件中完全删除文件(这是我找到链接的地方)。您将使用此解决方案运行的实际命令将类似于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
另一种可能对你正在做的事情来说有点矫枉过正的方法是挑选樱桃。Cherry-picking 允许您以您喜欢的任何详细程度重写您喜欢的历史记录的任何部分:http://git-scm.com/docs/git-cherry-pick
. 你会想要做一些类似的事情git reset --hard <HASH of commit that introduced the subtree>
,然后是一系列
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 gitfor 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 部分挑选提交以获取有关有效挑选的更多信息。完成此版本的删除后,您将需要删除不再属于您的分支的旧提交:
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?)