Cómo encontrar todos los repositorios git dentro de las carpetas dadas (rápido)


9

El enfoque ingenuo es find dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {} , pero es demasiado lento para mí, porque tengo muchas estructuras de carpetas profundas dentro de los repositorios de git (al menos creo que esta es la razón). He leído sobre eso que puedo usar prunepara evitar que el hallazgo vuelva a aparecer en los directorios una vez que encuentra algo, pero hay dos cosas. No estoy seguro de cómo funciona esto (quiero decir, no entiendo qué prunehace aunque haya leído la página de manual) y el segundo no funcionaría en mi caso, porque evitaría que se repita finden la .gitcarpeta pero no en todos otras carpetas

Entonces, lo que realmente necesito es:

para todos los subdirectorios, verifique si contienen una .gitcarpeta y si es así, deje de buscar en esta rama del sistema de archivos e informe el resultado. Sería perfecto si esto también excluyera cualquier directorio oculto de la búsqueda.



Respuestas:


8

De acuerdo, todavía no estoy totalmente seguro de cómo funciona esto, pero lo he probado y funciona.

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

6 directories, 0 files

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

Tengo muchas ganas de hacer lo mismo más rápido.


2
De -pruneesta manera: comienza en la raíz de un árbol, lo mueve hacia abajo y cuando se aplica una determinada condición, corta un subárbol completo (como una "poda" real), por lo que no verá más nodos en este subárbol .
phk

@phk oh, gracias. Parece que lo entiendo ahora. Estamos buscando directorios -type dpara qué condición test -e ...es verdadera y si es así, ejecutamos acciones, lo -print -pruneque significa imprimirlo y cortar el subárbol, ¿verdad?
user1685095

Sí, cortamos el subárbol del cual es la raíz.
phk

Una rápida para usar su solución para "actualizar" todos los repositorios de git: find . -type d -exec test -e '{}/.git' \; -print -prune | parallel cd "{}" \&\& git pull --rebaseGNU paralleles un reemplazo muy útil paraxargs
Marcello Romani

no obtendrá submódulos, que también son repositorios git. Es posible que desee obtenerlos recuperando submódulos de forma recursiva, una vez que este comando devuelva la lista de repositorios raíz.
hoijui

2

Solución posible

Para GNU findy otras implementaciones que admiten -execdir:

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

(ver los comentarios)

Cosas discutidas previamente

Solución si la poda a continuación .gites suficiente

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

Si -printf '%h'es compatible (como en el caso de GNU's find) no necesitamos dirname:

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

Una vez que se encuentre con una carpeta .giten la ruta actual, la generará y luego dejará de mirar hacia abajo en el subárbol.

Solución si todo el árbol de carpetas se debe podar una vez que .gitse encuentra

Usando -quitsi tu lo findadmite:

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

(De acuerdo con esta publicación detallada de Stéphane Chazelas, -quit se admite en GNU y FreeBSD findy en NetBSD como -exit).

De nuevo con -printf '%h'si es compatible:

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

Solución para podar al mismo nivel que donde está la .gitcarpeta

Consulte la parte "Posible solución" para ver la solución actual para este problema en particular.

(Ah, y obviamente las soluciones que usan xargsasumen que no hay líneas nuevas en los caminos, de lo contrario, necesitarías magia de byte nulo).


si dir1contiene dos directorios dirxy dirycada uno contiene un .gitdirectorio, esto solo informa dirx/.git
iruvar

@iruvar Ah OK, te entendí mal en ese caso, intentaré rehacer la solución entonces.
phk

El problema con su nueva solución es que si dir1/.gitexiste, aún desciende dir1/dirx, lo que, según mi lectura de los requisitos de OP, no es deseable
Iruvar

@iruvar OK, también agregó eso. ¿Alguna otra idea sobre lo que OP podría haber significado? ;-)
phk

@iruvar exactamente
user1685095

2

Idealmente, desearía rastrear árboles de directorios en busca de directorios que contengan una .gitentrada y dejar de buscar más abajo (suponiendo que no tenga más git repos dentro de git repos).

El problema es que con el estándar find, hacer este tipo de verificación (que un directorio contiene una .gitentrada) implica generar un proceso que ejecute una testutilidad utilizando el -execpredicado, que será menos eficiente que enumerar el contenido de algunos directorios.

Una excepción sería si usa la findconstrucción del boshshell (un tenedor POSIXified del shell Bourne desarrollado por @schily ) que tiene un -callpredicado para evaluar el código en el shell sin tener que generar un nuevo intérprete sh:

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

O use perl's 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' .

Más largo, pero más rápido que zsh's printf '%s\n' **/.git(:h)(que desciende a todos los directorios no ocultos), o GNU find' s find . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -printque ejecuta un testcomando en un nuevo proceso para cada directorio no oculto.


1
Tenga en cuenta que .gitpuede ser un archivo, así - a través degit worktree
Steven Penny

1
Gracias @StevenPenny, no estaba al tanto de eso. Ahora he cambiado el -ds a -e.
Stéphane Chazelas

1

Si usa localizar, puede encontrar directorios con:

locate .git | grep "/.git$"

La lista de resultados es rápida y el procesamiento posterior también es fácil.


2
locate '*/.git'debería ser suficiente.
Stéphane Chazelas

0

Utilizar

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

timeesto, para ver la diferencia con y sin -prune.

Esto se basa en una solución en el man find. Puede editar el CVSy svnsi no es necesario. sigue el contenido de la página man

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

Dado el siguiente directorio de proyectos y sus directorios administrativos SCM asociados, realice una búsqueda eficiente de las raíces de los proyectos:

repo/project1/CVS
repo/gnu/project2/.svn
repo/gnu/project3/.svn
repo/gnu/project3/src/.svn
repo/project4/.git

En este ejemplo, -pruneevita el descenso innecesario a directorios que ya han sido descubiertos (por ejemplo, no buscamos project3/srcporque ya lo encontramos project3/.svn), pero asegura que se encuentren los directorios hermanos ( project2y project3).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.