如何在`Git`中使用`filter-branch`命令对多个子目录进行处理并保留它们的父级目录?

4
假设我有一个仓库,其文件夹结构类似于这样:
|-dir1
|-dir2
| |-subdir1
| |-subdir2
| |-subdir3
|-dir3

我希望我可以简单地使用git filter-branch --subdirectory-filter来解决这个问题,但是我似乎遇到了两个挑战:
  • 似乎我不能提供多个--subdirectory-filter参数?至少它似乎没有包括我想要的所有子目录。
  • git似乎会剥离掉父目录。
那么如果我想过滤我的仓库以获得这个结果,该怎么办呢?
|-dir1
|-dir2
| |-subdir1
| |-subdir3

附加说明:
如评论所建议的那样,我已经尝试过:
git filter-branch --tree-filter 'rm -rf dir2/subdir2' --prune-empty

但是这样做非常缓慢,所以我对它感到不耐烦。`git help filter-branch`似乎建议我可以使用`--index-filter`而不是`--tree-filter`来加快速度,所以我希望能够简单地改用以下方法:
git filter-branch --index-filter 'rm -rf dir2/subdir2' --prune-empty

然而,尽管似乎通过我的提交进行了一些操作,但最终以以下信息结束:

警告:参考 'refs/heads/master' 未更改

目录 'dir2/subdir' 及其内容仍然留在我的工作副本中。因此,我显然误解了某些东西。我很想知道使用 --index-filter 的正确方法是什么?

1
我认为你需要使用 git filter-branch --tree-filter 'rm -rf dir2/subdir2 dir3/' 命令。如果需要的话,可以加上 -f 参数。 - ElpieKay
@ElpieKay 我会试一下。 - Thomas Arildsen
@ElpieKay,“--tree-filter”需要很长时间,所以我尝试使用“--index-filter”,因为各种来源似乎表明这应该具有相同的效果。然而,即使它在重新编写提交时非常繁忙,它在我的实际工作副本中没有任何效果,并以消息“警告:Ref 'refs/heads/master'未更改”结束。我可能做错了什么? - Thomas Arildsen
抱歉,我还没有遇到过你的问题。你的代码库中有大量的文件和提交吗? - ElpieKay
你可以将你提出的 --index-filter 编辑到问题中。在这里我要注意的是,树过滤器中的命令很简单(但速度较慢);相应的命令放入索引过滤器中往往更难编写。 - torek
@torek,我现在详细阐述了我的方法。希望有人能帮我找出我做错了什么。 - Thomas Arildsen
1个回答

4

实际上这就是问题所在:

git filter-branch --index-filter 'rm -rf dir2/subdir2' --prune-empty

一个索引过滤器必须对Git的索引(也称为暂存区或缓存,具体取决于您查看的Git文档)进行操作。

幸运的是,对于这种特殊情况,有一个Git命令等同于rm -rf,只对Git的索引进行操作:

git rm --cached -rf --ignore-unmatch dir2/subdir2

我们需要使用--cached参数来仅在索引上生效,-r参数让它的行为类似于rm -r-f --ignore-unmatch参数让它的行为类似于rm -f。 因此完整的filter-branch命令至少包括:
git filter-branch \
    --index-filter 'git rm --cached -rf --ignore-unmatch dir2/subdir2' \
    --prune-empty

您可能想添加--tag-name-filter cat和/或其他filter-branch选项。

由于filter-branch命令必须复制它“过滤”的每个提交,因此它充满了小小的怪癖,这非常缓慢。 --tree-filter最简单易用,因为它可以使用所有正常的文件系统操作,但也使它成为最慢的选择。


有没有一种方法可以重写这个命令,使得我们可以列出想要保留的文件/目录,而不是在“--ignore-unmatch”中列出想要删除的文件/目录? - Roberto
@Roberto:不过,一个不同的--index-filter可以做到这一点。编写起来并不完全简单,但已经有人写了一个。我只是不知道哪个StackOverflow答案中有它... - torek
找到了这个 https://dev59.com/dGIj5IYBdhLWcg3wuHXP - 尽管对于每个提交删除所有内容然后重置听起来非常慢。你觉得呢? - Roberto
删除和重置索引并不是很慢。(作为树形过滤器,它确实非常慢。)还有另一种方法使用git update-indexsed,但是接受的答案,使用索引过滤器进行加速,应该是可以的。 - torek

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