2

I am using the answer to this question to strip a clone of a repository to a list of files I want to keep in a spin off of this project. Say I want to strip all but directory src/main and its sub-directories. Because I will have multiple files and directories, I use --index-filter instead of --subdirectory-filter.

I thought the following should work:

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ↩
  src/!(main)" --prune-empty -- --all

But all I get is

-bash: !: event not found

I tried all sorts of different paths instead of src/!(main). I always get exactly that error message. It seems to be a bash problem, because that line also doesn't enter my command line history?


That is to say, if I have top level files A, and B, and subdirectory C/D, how can I remove all but these three things?

Community
  • 1
  • 1
0__
  • 66,707
  • 21
  • 171
  • 266
  • In the meantime, I have success by giving `gm rm` a list of all files to __remove__, instead of specifying the ones to __keep__. Quite a pain in this case because there are many compared to the few I want to keep; but it seems to work. – 0__ Sep 24 '12 at 12:23

3 Answers3

4

The ! is the issue, since it is used for command history recall. Inside quotes, putting a backslash in front does not help either, so the \! must be outside quotes. Can be illustrated using a few examples with echo:

/home/user1> echo "src/!(main)"
-bash: !: event not found
/home/user1> echo "src/\!(main)"
src/\!(main)
/home/user1> echo "src/"\!"(main)"
src/!(main)
cdarke
  • 42,728
  • 8
  • 80
  • 84
  • It's meant to be an *extglob* matching everything in `src` but `main`. – kynan Apr 03 '13 at 11:01
  • @kynan: globbing (including extglob) does not work inside quotes. Are you attempting to use an extglob pattern for filename expansion? – cdarke Apr 04 '13 at 07:35
  • 1
    That's what the OP was intending: have a look at the question clarification and my answer for how to fix it. – kynan Apr 04 '13 at 11:14
3

To answer the the actual question added in the clarification: you're trying to use bash's extglob to remove everything in src but main in a git index-filter. This doesn't work because the index-filter command is not executed by your shell, but by sh via eval (see /usr/lib/git-core/git-filter-branch:327).

You can't tell git to enable extglob when doing this, but you can make your shell expand the extglob before passing it to index-filter:

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd src/!(main))" --prune-empty -- --all
Community
  • 1
  • 1
kynan
  • 13,235
  • 6
  • 79
  • 81
0

The exclamation point is used in Bash's syntax to do history expansion, which is what causes the confusion. You must escape it using backslash or single quotes:

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ↩
  src/\!(main)" --prune-empty -- --all
unwind
  • 391,730
  • 64
  • 469
  • 606
  • Hmmm. That just gives me `syntax error near unexpected token '('` - `eval: line 349: 'git rm -r -f --cached --ignore-unmatch src/\!(main)'` – 0__ Sep 24 '12 at 12:20
  • Unfortunately, when used inside quotes, the \ is retained. – cdarke Sep 24 '12 at 12:44