删除 git 中的空提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28313664/
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
Remove empty commits in git
提问by Greeso
I just migrated a project from Mercurial to Git. Mercurial adds empty commits when you add tags, so I ended up with empty commits in Git that I would like to remove.
我刚刚将一个项目从 Mercurial 迁移到 Git。当您添加标签时,Mercurial 会添加空提交,因此我最终在 Git 中得到了我想删除的空提交。
How do I remove empty commits (commits that do not have any files in them) from Git?
如何从 Git 中删除空提交(其中没有任何文件的提交)?
Thanks.
谢谢。
回答by torek
One simple (but slow) way to do this is with git filter-branch
and --prune-empty
. With no other filters, no other commits will be altered, but any empty ones will be discarded (which will cause all subsequent commits to have new parent-IDs and is therefore still "rewrites history": not a big deal if this is your initial import from hg to git, but is a big deal if others are using this repository already).
一种简单(但缓慢)的方法是使用git filter-branch
and --prune-empty
。没有其他过滤器,不会改变其他提交,但任何空提交都将被丢弃(这将导致所有后续提交具有新的父 ID,因此仍然“重写历史”:如果这是您的初始提交,这没什么大不了的从 hg 导入到 git,但如果其他人已经在使用这个存储库,这是一个大问题)。
Note all the usual caveats with filter-branch. (Also, as a side note, an "empty commit" is really one that has the same tree as the previous commit: it's not that it has no files at all, it's that it has all the same files, with the same modes, and the same contents, as its parent commit. This is because git stores complete snapshots for each commit, not differences from one commit to the next.)
请注意 filter-branch 的所有常见警告。(另外,作为旁注,“空提交”实际上与前一次提交具有相同的树:并不是它根本没有文件,而是它具有所有相同的文件,具有相同的模式,以及与其父提交相同的内容。这是因为 git 存储了每次提交的完整快照,而不是一次提交与下一次提交的差异。)
Here is a tiny example that hides a lot of places you can do fancier things:
这是一个很小的例子,它隐藏了很多你可以做更漂亮的事情的地方:
$ ... create repository ...
$ cd some-tmp-dir; git clone --mirror file://path-to-original
(This first clone step is for safety: filter-branch
can be quite destructive so it's always good to start it on a new clone rather than the original. Using --mirror
means all its branches and tags are mirrored in this copy, too.)
(这第一个克隆步骤是为了安全:filter-branch
可能具有很大的破坏性,因此在新的克隆而不是原始克隆上启动它总是好的。使用--mirror
意味着它的所有分支和标签也被镜像到这个副本中。)
$ git filter-branch --prune-empty --tag-name-filter cat -- --all
(Now wait a potentially very long time; see documentation on methods to speed this up a bit.)
(现在等待可能很长时间;请参阅有关加快速度的方法的文档。)
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
(This step is copied out of the documentation: it discards all the original branches from before running the filter. In other words, it makes the filtering permanent. Since this is a clone, that's reasonably safe to do even if the filter went wrong.)
(这一步是从文档中复制出来的:它会在运行过滤器之前丢弃所有原始分支。换句话说,它使过滤成为永久性的。由于这是一个克隆,即使过滤器出错,这样做也是相当安全的。 )
$ cd third-tmp-dir; git clone --mirror file://path-to-filtered-tmp
(This makes a clean, nicely-compressed copy of the filtered copy, with no leftover objects from the filtering steps.)
(这会生成一个干净的、经过良好压缩的过滤副本副本,没有过滤步骤中的剩余对象。)
$ git log # and other commands to inspect
Once you're sure the clone of the filtered clone is good, you don't need the filtered clone, and can use the last clone in place of the first. (That is, you can replace the "true original" with the final clone.)
一旦您确定过滤克隆的克隆是好的,您就不需要过滤克隆,并且可以使用最后一个克隆代替第一个。(也就是说,您可以用最终的克隆替换“真正的原始”。)
回答by bengineerd
Using --commit-filter should be faster than using --prune-empty
使用 --commit-filter 应该比使用 --prune-empty 更快
$ git filter-branch --tag-name-filter cat --commit-filter 'git_commit_non_empty_tree "$@"' -- --all
$ git filter-branch --tag-name-filter cat --commit-filter 'git_commit_non_empty_tree "$@"' -- --all
Then clean the backup refs as in torek's answer
然后按照torek的回答清理备份参考
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
Taken from here: Git - remove commits with empty changeset using filter-branch