带索引过滤器的Git filter-branch不起作用,并按预期删除目录

时间:2012-12-12 10:39:17

标签: git git-filter-branch git-rewrite-history

主分支中Git repo foo的结构

foo/refs/a.txt  
foo/bar/refs/b.txt  

在其他分支refs/可能在很多其他地方

目标

从Git(历史记录)中删除目录引用的所有实例(及其内容) 环境:使用Git Bash的Windows 7

删除引用(Git没有参与,尝试这只是为了看它自己工作)

find . -name refs -depth -exec rm -rf {} \;

成功,所有refs/及其内容都已删除(如果我不使用-depth,则会报告错误,即即使这些目标已被删除,也不会存在正确地)。

从Git

中删除引用
git filter-branch --index-filter \
'find . -name refs -depth -exec git rm -rf --cached --ignore-unmatch {} \;' \
--prune-empty --tag-name-filter cat -- --all

Removing directory refs from Git by rewriting the Git history

从图中可以看出(将temp/a视为temp/foo)命令会运行并重写所有提交,但不会删除refs/,因此以某种方式查找的输出是未按预期返回filter-branch --index-filter

类似的事情似乎适用于其他人 我错过了什么?

PS。是的,我已经阅读了数百个关于此的数百个帖子,文章等数小时,但它对我来说并不适用。

1 个答案:

答案 0 :(得分:4)

更新

虽然我的旧答案显然有助于原始海报部分地解决了他的问题,但似乎我可能实际上并不正确--index-filter仅适用于Git命令,因为在documentation for git filter-branch中,它给出了除Git命令外,还有一个与非Git shell命令一起使用的过滤器示例:

git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t\"*-&newsubdir/-" |
                GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                        git update-index --index-info &&
         mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD

可能就是这样,如果您要使用带有--index-filter的非Git命令,那么他们来操作存储库的索引,如上所示文档中的示例。

所以基本上,我不知道为什么原始海报的原始索引过滤器不起作用,但可能是他试图访问索引的部分存储库的情况filter不允许访问,或者他使用的任何非Git命令实际上都没有修改索引。

此外,as I point out in the comments

  

Git实际上将.git/refs/下的所有引用存储在非裸存储库中,工作副本根目录中......所以命令find . -name refs -depth实际上也会挖掘这些目录。

所以也许这会导致在过滤器分支期间出现可怕的错误?

旧答案

我认为问题可能是您尝试使用非{Gid shell工具filter-branch --index-filter选项而不是--tree-filter选项:

git filter-branch --index-filter \
'find . -name refs -depth -exec git rm -rf --cached --ignore-unmatch {} \;' \
--prune-empty --tag-name-filter cat -- --all

与为--tree-filter检查每个提交的新工作目录并在其上运行传递的shell脚本不同,--index-filter仅对Git repo本身的索引文件进行操作(它不是检查一个工作副本来操作)...所以只有Git命令才能使用它。

这可能是你运气好的原因,因为它将Git命令传递给filter-branch --index-filter

git filter-branch --index-filter \
'git rm -f --cached --ignore-unmatch *.zip && \
 git rm -rf --cached --ignore-unmatch refs' \
--prune-empty --tag-name-filter cat -- --all

这是git-filter-branch(1) --tree-filter的文档:

  

这是用于重写树及其内容的过滤器。参数在shell中计算,工作目录设置为签出树的根目录。

这是--index-filter(强调我的)的文档:

  

这是重写索引的过滤器。 它类似于树过滤器,但不检查树 ,这使得它更快。经常与git rm --cached --ignore-unmatch ...一起使用,请参阅下面的示例。对于毛病例,请参阅git-update-index(1)