我刚刚将一个项目从Mercurial迁移到Git。当你添加标签时,Mercurial会添加空提交,所以我最终在Git中提交了我要删除的空提交。
如何从Git中删除空提交(其中没有任何文件的提交)?
感谢。
答案 0 :(得分:22)
执行此操作的一种简单(但缓慢)方法是使用git filter-branch
和--prune-empty
。没有其他过滤器,任何其他提交都不会被更改,但任何空提交都将被丢弃(这将导致所有后续提交都有新的父ID,因此仍然“重写历史记录”:如果这是你的初始从hg导入到git,但如果其他人已经在使用此存储库,那么这是一个大问题。
注意所有通常使用filter-branch的警告。 (另外,作为旁注,“空提交”实际上是与前一次提交具有相同树的那个:它不是根本没有文件,而是它具有所有相同的文件,具有相同的模式,与其父提交相同的内容。这是因为git为每个提交存储完整的快照,而不是从一个提交到下一个提交的差异。)
这是一个很小的例子,隐藏了许多你可以做更好的事情的地方:
$ ... create repository ...
$ cd some-tmp-dir; git clone --mirror file://path-to-original
(第一个克隆步骤是为了安全:filter-branch
可能非常具有破坏性,因此在新克隆而不是原始克隆上启动它总是好的。使用--mirror
表示它的所有分支和标签都是也反映在这个副本中。)
$ git filter-branch --prune-empty --tag-name-filter cat -- --all
(现在等待可能很长时间;请参阅有关加快这一点的方法的文档。)
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
(此步骤是从文档中复制出来的:它会在运行过滤器之前丢弃所有原始分支。换句话说,它会使过滤永久化。因为这是一个克隆,即使过滤器也是相当安全的出了问题。)
$ cd third-tmp-dir; git clone --mirror file://path-to-filtered-tmp
(这会对过滤后的副本进行干净,精心压缩的副本,过滤步骤中没有剩余的对象。)
$ git log # and other commands to inspect
一旦确定已过滤的克隆的克隆是好的,您就不需要过滤的克隆,并且可以使用最后一个克隆代替第一个克隆。 (也就是说,您可以用最终克隆替换“真实原始”。)
答案 1 :(得分:5)
使用--commit-filter应该比使用--prune-empty
更快 $ git filter-branch --tag-name-filter cat --commit-filter 'git_commit_non_empty_tree "$@"' -- --all
然后按照torek的回答
清理备份引用 $ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
从这里采取:Git - remove commits with empty changeset using filter-branch