Em bash , sem a opção dotglob , os arquivos ocultos são ignorados, a menos que o glob explicitamente (que é um líder literal . ) os solicite. E . e .. não são ignorados (ao contrário do que os shells mais sensatos gostam de pdksh , zsh ou fish do).
Com dotglob , apenas . e .. são ignorados, a menos que a glob comece com . .
Com extglob , bash adiciona suporte a alguns dos operadores% glob extendido deksh. No entanto, aqui com um bug / misfeature quando se trata de !(...) one.
Em ksh (embora não pdksh ) e bash , @(.*) é um caso em que você solicita explicitamente os dotfiles (embora a documentação não deixe isso claro).
Mas em !(.git) você não está solicitando dotfiles. ksh e zsh in ksh emulation lidam com isso corretamente, mas bash presume que você esteja solicitando dotfiles. E isso inclui . e .. , mesmo com dotglob . Então .git será copiado como parte da cópia de . .
Para contornar esse problema, você pode usar !([.]git) (aqui [.] torna o . não explícito) em combinação com dotglob ou excluir . e .. explicitamente com !(.git|.|..) :
$ bash -O extglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !([.]git)'
foo .foo
$ bash -O extglob -c 'echo !(.git|.|..)'
foo .foo
No último caso, eu ainda adicionaria a opção dotglob , porque bash em uma versão futura pode ser corrigido para parar de incluir os dotfiles aqui como em outras shells.
Como eu uso o zsh que tem seus próprios operadores estendidos (com a opção extendedglob não ativada por padrão para manter a compatibilidade Bourne; ele também suporta ksh globs com a opção kshglob , mas esses são mais complicados), faria:
set -o extendedglob # (in my ~/.zshrc)
cp -a -- ^.git(D) target/
(observe que -a implica -r e você precisa do -- , pois não podemos garantir que os nomes dos arquivos não começarão com - ).
^.git é zsh de !(.git) do ksh. (D) para incluir dotfiles (mas nunca . nem .. ) apenas para esse glob.