Encontre arquivos que não estão no .gitignore

12

Eu tenho o comando find que exibe arquivos no meu projeto:

find . -type f -not -path './node_modules*' -a -not -path '*.git*' \
       -a -not -path './coverage*' -a -not -path './bower_components*' \
       -a -not -name '*~'

Como posso filtrar os arquivos para que não mostrem os que estão no .gitignore?

Eu pensei que eu uso:

while read file; do
    grep $file .gitignore > /dev/null && echo $file;
done

mas o arquivo .gitignore pode ter padrões glob (também não funcionará com caminhos se o arquivo estiver em .gitignore), como posso filtrar arquivos com base em padrões que podem ter globs?

jcubic
fonte

Respostas:

11

gitfornece git-check-ignorepara verificar se um arquivo é excluído por .gitignore.

Então você pode usar:

find . -type f -not -path './node_modules*' \
       -a -not -path '*.git*'               \
       -a -not -path './coverage*'          \
       -a -not -path './bower_components*'  \
       -a -not -name '*~'                   \
       -exec sh -c '
         for f do
           git check-ignore -q "$f" ||
           printf '%s\n' "$f"
         done
       ' find-sh {} +

Observe que você pagaria um alto custo por isso porque a verificação foi realizada para cada arquivo.

cuonglm
fonte
O que há find-sh {} +no final?
Jcubic
Ok, e o que é find-sh?
jcubic
@jcubic é o nome que você deu para o script inline-sh, por isso, ocorre erro caso, você teria uma mensagem de erro significativa
cuonglm
@jcubic Tente find /tmp -exec sh -c ': "${non_existed_var:?foo}"' find-sh {} +por exemplo
cuonglm
9

existe um comando git para fazer exatamente isso: por exemplo

my_git_repo % git grep --line-number TODO                                                                                         
desktop/includes/controllers/user_applications.sh:126:  # TODO try running this without sudo
desktop/includes/controllers/web_tools.sh:52:   TODO: detail the actual steps here:
desktop/includes/controllers/web_tools.sh:57:   TODO: check if, at this point, the menurc file exists. i.e. it  was created

Como você declarou, ele fará um grep básico com a maioria das opções normais de grep, mas não pesquisará .gitnem nenhum dos arquivos ou pastas no seu .gitignorearquivo.
Para mais detalhes, consulteman git-grep

Sub-módulos:

Se você tiver outros repositórios git dentro desse repositório git (eles devem estar nos submódulos), use o sinalizador --recurse-submodulespara pesquisar também nos submódulos

the_velour_fog
fonte
Ótimo, quase funcionou porque eu tenho outros repositórios git dentro do diretório atual, é por isso que tenho "* .git".
jcubic
8

Para mostrar os arquivos que estão no seu checkout e que são rastreados pelo Git, use

$ git ls-files

Este comando possui várias opções para mostrar, por exemplo, arquivos em cache, arquivos não rastreados, arquivos modificados, arquivos ignorados etc. Veja git ls-files --help.

Kusalananda
fonte
Também penso, git ls-filesmas não acho, que tenha a opção de mostrar arquivos não rastreados, qual?
amigos estão dizendo sobre cuonglm
1
@cuonglm -o(outro). Por exemplo,git ls-files -o -X .gitignore
Kusalananda
Ah, sim, mas não consigo lidar com o caso em que o arquivo foi rastreado antes, mas incluí-lo .gitignore.
amigos estão dizendo sobre cuonglm
Nota secundária: isso não lista os arquivos reais do sistema, mas os arquivos incluídos no histórico do git. Isso pode ser uma diferença sutil em sistemas que não diferenciam maiúsculas de minúsculas (por exemplo, compartilhamentos do Windows). Digamos, confirmei ./foo.txt, mas renomeie-o para ./Foo.txt. Alguns clientes git não reconhecerão essa alteração e git ls-filesproduzirão ./foo.txt enquanto findproduziriam ./Foo.txt
#
2

Você pode usar uma matriz na qual o bash glob será executado.

Tendo arquivos como este:

touch file1 file2 file3 some more file here

E ter um ignorearquivo como este

cat <<EOF >ignore
file*
here
EOF

Usando

arr=($(cat ignore));declare -p arr

O resultado será o seguinte:

declare -a arr='([0]="file" [1]="file1" [2]="file2" [3]="file3" [4]="here")'

Você pode usar qualquer técnica para manipular esses dados.

Pessoalmente, prefiro algo assim:

awk 'NR==FNR{a[$1];next}(!($1 in a))'  <(printf '%s\n' "${arr[@]}") <(find . -type f -printf %f\\n)
#Output
some
more
ignore
George Vasiliou
fonte
gitignoreé superconjunto de bashglob, você vai perder para algo como!file*
cuonglm
@cuonglm Como assim !file*? Como padrão glob em ignorar arquivo ou como nome de arquivo?
George Vasiliou
gitignoreaceito padrão de arquivo como !file*para excluir arquivos começar com file, e também estrela dupla**
cuonglm
.gitignorepossui vários recursos, os quais podem não ser tão fáceis de implementar diretamente no Bash: git-scm.com/docs/gitignore . Embora ignora que consistem em apenas globs simples devem ser factível em Bash simples, sem awk ou tal
ilkkachu
@cuonglm Você quer dizer a tradução de !como não? Talvez o globing estendido possa lidar com essa situação. Sobre o doublestar, o bash pode lidar com isso shopt -s globstar.
George Vasiliou