Como encontrar todos os repositórios git dentro de determinadas pastas (rápido)

7

A abordagem ingênua é find dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {} , mas é muito lenta para mim, porque eu tenho estruturas de pastas muito profundas dentro de repositórios git (pelo menos eu acho que essa é a razão). Eu li sobre isso que eu posso usar prune para evitar encontrar para recorrer aos diretórios, uma vez que encontrou algo, mas há duas coisas. Não tenho certeza de como isso funciona (quero dizer, não entendo o que o prune faz, embora eu tenha lido man page) e o segundo não funcionaria no meu caso, porque evitaria que find recurasse na pasta .git , mas não em todas as outras pastas.

Então, o que eu realmente preciso é:

para todos os subdiretórios, verifique se eles contêm uma pasta .git e, se estiver, pare de procurar nessa ramificação do sistema de arquivos e relate o resultado. Seria perfeito se isso também excluísse quaisquer diretórios ocultos da pesquisa.

    
por user1685095 30.12.2016 / 20:14

5 respostas

4

Ok, ainda não sei ao certo como isso funciona, mas testei e funciona.

.
├── a
│   ├── .git
│   └── a
│       └── .git
└── b
    └── .git

6 directories, 0 files

% find . -type d -exec test -e '{}/.git' ';' -print -prune
./a
./b

Estou ansioso para fazer o mesmo mais rápido.

    
por 31.12.2016 / 00:43
2

Solução possível

Para o% GNUfind e outras implementações que suportam -execdir :

find dir1 dir2 dir3 -type d -execdir test -d '.git' \; -print -prune

(veja os comentários)

Material previamente discutido

Solução se a remoção abaixo de .git for suficiente

find dir1 dir2 dir3 -type d -path '*/.git' -print -prune | xargs -I {} dirname {}

Se -printf '%h' for suportado (como no caso do find do GNU), não precisamos de dirname :

find dir1 dir2 dir3 -type d -path '*/.git' -printf '%h\n' -prune

Quando encontrar uma pasta .git no caminho atual, ela será impressa e, em seguida, parará de procurar mais abaixo na subárvore.

Solução se toda a árvore de pastas for removida quando for encontrado .git

Usando -quit se o seu find for compatível:

for d in dir1 dir2 dir3; do
  find "$d" -type d -name .git -print -quit
done | xargs -I {} dirname {}

(De acordo com esta postagem detalhada de Stéphane Chazelas -quit é suportada no GNU's e no find do FreeBSD e no NetBSD como -exit .)

Novamente com -printf '%h' , se suportado:

for d in dir1 dir2 dir3; do
  find "$d" -type d -name .git -printf '%h\n' -quit
done

Solução para remoção no mesmo nível de onde a pasta .git é

Consulte a parte "Solução possível" para a solução atual para esse problema específico.

(Ah e obviamente as soluções usando xargs assumem que não há novas linhas nos caminhos, caso contrário você precisaria de magia de byte nulo.)

    
por 30.12.2016 / 21:07
1

O ideal é que você queira rastrear árvores de diretórios para diretórios que contenham uma entrada .git e pare de pesquisar mais abaixo (supondo que você não tenha mais git repos dentro do git repos).

O problema é que com o padrão find , fazer esse tipo de verificação (que um diretório contém uma entrada .git ) envolve gerar um processo que executa um utilitário test usando o predicado -exec , que é para ser menos eficiente do que listar o conteúdo de alguns diretórios.

Uma exceção seria se você usasse o find embutido do bosh shell (um fork POSIXified do shell Bourne desenvolvido por @schily ) que tem um predicado -call para avaliar código no shell sem ter que gerar um novo interpretador sh:

#! /path/to/bosh
find . -name '.?*' -prune -o \
  -type d -call '[ -e "$1/.git" ]' {} \; -prune -print

Ou use perl ' File::Find :

perl -MFile::Find -le '
  sub wanted {
    if (/^\../) {$File::Find::prune = 1; return}
    if (-d && -e "$_/.git") {
       print $File::Find::name; $File::Find::prune = 1
    }
  }; find \&wanted, @ARGV' .

Mais longo, mas mais rápido que zsh ' printf '%s\n' **/.git(:h) (que desce para todos os diretórios não ocultos) ou find do GNU find . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -print que executa um comando test em um novo processo para cada diretório não oculto.

    
por 29.10.2018 / 14:05
0

Use find ~ / GIT-REPOSITORIES (-exec test -d '{}' /. git \;) -print -prune

tempo isso para ver a diferença com e sem poda.

Isso é baseado na solução na página man do find. Você pode editar o cvs e o svn se não for necessário. o conteúdo da página man segue

encontre repo / (-exec test -d '{}' /. svn \; -or \        -exec test -d {} /. git \; -ou -exec test -d {} / CVS \; )        -print -prune

Dado o seguinte diretório de projetos e seus diretórios administrativos associados ao SCM, faça uma pesquisa eficiente sobre as raízes dos projetos:        repo / project1 / CVS        repo / gnu / project2 / .svn        repo / gnu / project3 / .svn        repo / gnu / project3 / src / .svn        repo / project4 / .git

Neste exemplo, -prune impede a descida desnecessária em diretórios que já        foi descoberto (por exemplo, não pesquisamos project3 / src porque já encontramos        project3 / .svn), mas garante que os diretórios irmãos (project2 e project3) sejam

    
por 29.10.2018 / 13:37
0

Se você usar locate, poderá encontrar diretórios com:

locate .git | grep "/.git$"

A lista de resultados é rápida e o processamento posterior é fácil também.

    
por 30.10.2018 / 18:13

Tags