在 git 过滤器分支中反转 shell globbing

Inverted shell globbing inside git filter-branch

我正在尝试相当复杂的 git 历史 p运行ing,但未能找到适用于 git filter-branch 的命令。基本上我想删除除了一些匹配的文件和目录之外的所有内容。

我想要运行的命令是有效的

git filter-branch -f --prune-empty --tree-filter 'rm -rf ^(FileA.java|dirB)' HEAD

但是 git-filter-branch 脚本在括号中 barfs。

/usr/local/Cellar/git/HEAD/libexec/git-core/git-filter-branch: eval: line 360: syntax error near unexpected token `('
/usr/local/Cellar/git/HEAD/libexec/git-core/git-filter-branch: eval: line 360: `rm -rf ^(FileA.java|dirB)'
tree filter failed: rm -rf ^(FileA.java|dirB)

我本以为 eval 可以很好地处理嵌入式括号,但这也超出了我 shell/zsh 的理解范围。

以及 git-filter-branch

中的违规代码
if [ "$filter_tree" ]; then
    git checkout-index -f -u -a ||
        die "Could not checkout the index"
    # files that $commit removed are now still in the working tree;
    # remove them, else they would be added again
    git clean -d -q -f -x
    eval "$filter_tree" < /dev/null ||
        die "tree filter failed: $filter_tree"

仍然不确定为什么我不能让它与 zsh 一起工作所以求助于包装在 bash 脚本中

$ cat ../purge.sh
#!/bin/bash
shopt -s extglob
rm -rf -- !(FileA.java|dirB|dirC)

$ git filter-branch -f --prune-empty --tree-filter '../purge.sh' HEAD
git filter-branch -f --index-filter '
        git read-tree --empty
        git reset $GIT_COMMIT fileA.java dirB dirC
' -- --all -- fileA.java dirB dirC

只会看到触及这些路径的提交,并且 (b) 不会费心检查永远不会检查的内容。您唯一需要 --prune-empty 的时间是当您将遇到或生成不改变任何内容的提交时,并且 rev-list args(在第一个 -- 之后)跳过所有那些已经.