Neil
Neil

Reputation: 1215

Inverted shell globbing inside git filter-branch

I'm attempting a fairly complex git history pruning and failing to find a command that works with git filter-branch. Essentially I want to remove everything except a few matching files and directories.

The command I'd like to run is effectively

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

But the git-filter-branch script barfs on the parens.

/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)

I would've expected eval to handle the embedded parens fine, but this is also beyond my shell/zsh understanding.

And the offending code in 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"

Upvotes: 1

Views: 291

Answers (2)

jthill
jthill

Reputation: 60295

git filter-branch -f --index-filter '
        git read-tree --empty
        git reset $GIT_COMMIT fileA.java dirB dirC
' -- --all -- fileA.java dirB dirC

only ever sees the commits that touch those paths and (b) doesn't bother checking out content that will never be examined. The only time you need --prune-empty is when you're going to be encountering or generating commits that don't change anything, and the rev-list args (after the first --) skip all of those already.

Upvotes: 3

Neil
Neil

Reputation: 1215

Still unsure why I couldn't get this to work with zsh so resorted to wrapping in a bash script

$ 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

Upvotes: 1

Related Questions