删除已删除文件上的提交

3

我使用以下命令通过git filter-branch清理我的存储库,以删除一些文件夹:

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch folder' \ 
    --prune-empty --tag-name-filter cat -- --all

在此之后,我还有一些仅与已删除文件相关的提交。是否有办法清理这些内容,即删除不再历史记录中的文件上的提交?


我认为你需要影响历史才能做到这一点,这是个问题吗? - OliverRadini
@OliverRadini 没有啊,我在删除文件夹的同时已经修改了历史记录。 - Holt
2个回答

2

简述

如果确实存在这种情况,您可以使用--prune-empty运行一个除了这些提交无其他作用的第二个filter-branch命令来丢弃它们。

详细说明及实验

之后,我仍然有一些提交只与已删除的文件相关。

这应该很少见,因为您已经包含了:

--prune-empty

这个命令会指示filter-branch忽略任何与其父提交相同的简单(非合并)提交。

有可能您有一些合并提交,将两个在其输入点上完全相同的分支合并在一起,但是这些提交不能被删除,因为它们合并了在其输入点上完全相同的分支。

比如说,在过滤之前,我们有以下分支结构:

          B--C
         /    \
...--o--A      M--o--...
         \    /
          D--E

提交记录 M 是一个合并记录,必须保留(因此已经保留),但是假设在过滤后 A 对比 B 折叠掉了,而且 C 对比 B(或对比 A)也由于相同的原因折叠掉了,那么就会得到:

...--o--A'-----M'-o--...
         \    /
          D'-E'

(字母后面的撇号或小符号表示这些是原始提交的副本——如果没有更改,A'确实可以是A,但这涵盖了更一般的情况)。在这里,M确实仍然需要保持逻辑结构,即使在最初删除文件时可以进行快进。

更有趣的情况是DE本身消失了,因为现在M仍然存在于过滤分支过程中,并且仍然具有两个父级,但是两个父级都映射到提交A'本身。我不确定在没有查看的情况下会发生什么:filter-branch是否可以使用A'作为M'的两个父级之一进行合并提交?如果它尝试这样做,git commit-tree会将提交M'写为普通的非合并提交吗?测试结果是否定的:

$ mkdir mtest
$ cd mtest
$ git init
Initialized empty Git repository in ...
$ echo test commit-tree > README
$ git add README
$ git commit -m initial
[master (root-commit) 1db1f76] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ echo log msg | git commit-tree -p HEAD -p HEAD HEAD^{tree}
error: duplicate parent 1db1f76a4e7217d5198c0f178464b7a087e94078 ignored
44f91061b7bd08c39a4dc9e8ebb1f4f7c588ea9e

看起来,一个天真的filter-branch会尝试创建M'并将其作为单亲提交:

...--o--A'-M'-o--...

其中M'A'没有差异。不过,filter-branch代码对此进行了检查:

    for parent in $parents; do
            for reparent in $(map "$parent"); do
                    case "$parentstr " in
                    *" -p $reparent "*)
                            ;;
                    *)
                            parentstr="$parentstr -p $reparent"
                            ;;
                    esac
            done
    done

如果你提供自己的父筛选器,这将在检查之后发生,并且你需要进行重新检查。因此,如果你得到这种类型的 `...--A'-M'-...` 结果,则使用仅包含 `--prune-empty` 的第二个筛选分支将其排除。

我已经尝试了另一个 git filter-branch --prune-empty,但提交记录仍然存在。我使用 git show 进行了检查,发现这些提交记录只包含在第一个 git filter-branch 中已删除的文件上所做的更改。 - Holt
小心使用 git show 和合并提交:Git 默认会显示合并差异,有意省略文件以使差异更有用。添加 -m 以使 Git 对每个父提交进行差异比较。(如果它们不是合并提交,我不确定这里发生了什么。) - torek
我尝试了 git show -m COMMIT_ID,并且得到了相同的输出。 - Holt
我正在查看由 git log 返回的提交,这些不是已更新的吗? - Holt
他们应该是。对于我现在要做的任何更多的事情,我需要看到存储库和提交记录... (如果您可以构建一个简单的重现者) - torek
显示剩余2条评论

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接