3

I want to use extended globbing in an "index-filter" , e.g.

git filter-branch --index-filter "git rm --cached --ignore-unmatched Modules/!(ModuleA|ModuleB)"

but I get an error:

eval: line 336: syntax error near unexpected token `('

I already tried:

git filter-branch --index-filter "shopt -s extglob && git rm --cached
--ignore-unmatched Modules/!(ModuleA|ModuleB)"

So the general question is: how do I enable specific shell options for the shell used to evaluate these expressions?

manol
  • 572
  • 3
  • 13

2 Answers2

2

You can circumvent the problem by having your shell invoking git filter-branch evaluate the glob for you (assuming you enabled extglob there):

git filter-branch --index-filter "git rm --cached --ignore-unmatch $(ls -xd Modules/!(ModuleA|ModuleB))"

Update: You need to supply parameters to ls: -x to separate entries by space instead of new line and -d to print the directory name instead of its contents. For more than a handful of files you may also need to add -w 1000 (or a similarly large number) to make ls assume a very wide terminal and fit everything in a single line.

kynan
  • 13,235
  • 6
  • 79
  • 81
  • doesn't seem to work. it finds the files that ls outputs and throws errors on those. – robdodson Dec 02 '12 at 19:05
  • 1
    i ran `git filter-branch --index-filter "git rm --cached --ignore-unmatch $(ls application/!(services|modules))"` . There is an error message for every file or directory that doesnt match the $(ls ...) command. eg: "/usr/lib/git-core/git-filter-branch: 51: eval: scripts: not found" . "scripts" is a directory in /application . – Mike Graf Jan 30 '13 at 18:43
  • The problem is that for some reason `$(ls ...)` print by column instead of per line. I've updated my answer. – kynan Jan 31 '13 at 00:57
  • On Ubuntu, I'm finding that ls -x doesn't put this on one line. I had to use $(ls -md apps/!(AAA) libs/!(XXX) | sed -e 's/, /,/g' | sed -e 's/ /\\ /g' | sed -e 's/&/\\&/g' | sed -e 's/,/ /g' | tr -d '\r\n') The -m separated the output by commas instead of the column based output I was getting. Ands seds to deal with spaces, ampersands in file names before replacing the commas with spaces and getting rid of newlines. – Bae Mar 20 '14 at 00:25
  • 2
    @Bae You're right, you get multiple lines if it's more than a handful of files. You can however add `-w 1000` (or some other large number) to make `ls` assume a very wide terminal and get the output back to a single line. – kynan Mar 22 '14 at 23:41
  • 1
    If the shell invoking git filter-branch does the globbing it's evaluated against the current directory layout. I wanted to rewrite the history with a lot of changes of the directory structure inside. It can be solved with a tree-filter instead of an index-filter, but this is multiple times slower since it does a full checkout for each revision. – manol Apr 06 '16 at 16:15
0

I realize this is not what you asked, but may still solve your problem. I made a list of the paths that aren't docs or research and then removed them.

PATHS_TO_REMOVE=$(git log --all --pretty=format: --name-only | sed 's@/.*@@' | sort | uniq | egrep -v '^docs$|^research$' | xargs)
git filter-branch -f --index-filter "git rm -r --cached --ignore-unmatch $PATHS_TO_REMOVE" --tag-name-filter cat -- --all

You should be able to do something similar for subdirectories.

Jayen
  • 5,653
  • 2
  • 44
  • 65