我刚刚将一个项目从Mercurial迁移到Git。Mercurial 在添加标签时会添加空提交,所以我最终在 Git 中得到了我想删除的空提交。
如何从 Git 中删除空提交(其中没有任何文件的提交)?
谢谢。
一种简单(但缓慢)的方法是使用 git filter-branch
和 --prune-empty
。 如果没有其他过滤器,不会更改其他提交,但任何空提交都将被丢弃(这将导致所有后续提交具有新的父 ID,因此仍然是"重写历史记录":如果这是您从 hg 到 git 的初始导入,这没什么大不了的,但如果其他人已经在使用此存储库,那就没什么大不了的了)。
请注意所有带有过滤器分支的常见警告。 (另外,作为旁注,"空提交"实际上是与上一个提交具有相同树的提交:并不是说它根本没有文件,而是它具有与其父提交相同的文件,具有相同的模式和相同的内容。 这是因为 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
确定筛选的克隆的克隆良好后,就不需要筛选的克隆,可以使用最后一个克隆代替第一个克隆。 (也就是说,您可以将"真正的原始"替换为最终克隆。
commit-filter 应该比使用 --prune-empty 更快
$ git filter-branch --tag-name-filter cat --commit-filter 'git_commit_non_empty_tree "$@"' -- --all
然后清理备份参考,如托雷克的答案
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
取自这里: Git - 使用过滤器分支删除带有空变更集的提交