Agregue recursivamente archivos por patrón

172

¿Cómo agrego recursivamente archivos por un patrón (o glob) ubicado en diferentes directorios?

Por ejemplo, me gustaría agregar A/B/C/foo.javay D/E/F/bar.java(y varios otros archivos java) con un comando:

git add '*.java'

Desafortunadamente, eso no funciona como se esperaba.

Michel Krämer
fuente
2
Funciona para mí (Mac OS X, Git 1.7.1+). ¿Qué sistema operativo y versión de Git estás usando?
Chris Johnsen
3
Si tiene algunos .javaarchivos (ya rastreados) en su directorio actual, es posible que se encuentre con, por ejemplo, un complicado manejo de comodines entre bash y el "ayudante" de la línea de comandos de msys . No estoy seguro de una solución. Puede probar varias capas de comillas: git add '"*.java"'( bash toma las comillas simples para evitar la expansión global, las comillas dobles las toma la capa msys para evitar la expansión global).
Chris Johnsen
1
Gracias por la nota Desafortunadamente, eso tampoco funciona. Dicen que se ha solucionado, pero ya tengo la última versión.
Michel Krämer
1
git add *.javafunciona para mí (en PowerShell con el cliente GitHub)
ThaDafinser

Respuestas:

89

La respuesta de Sergio Acosta es probablemente su mejor opción si algunos de los archivos que se van a agregar pueden no ser rastreados. Si desea limitarse a los archivos que ya conoce git, puede combinarlos git-ls-filescon un filtro:

git ls-files [path] | grep '\.java$' | xargs git add

Git no proporciona ningún mecanismo sofisticado para hacer esto por sí mismo, ya que es básicamente un problema de shell: ¿cómo se obtiene una lista de archivos para proporcionar como argumentos a un comando dado?

Cascabel
fuente
8
¡Gracias! Mejoré un poco tu comando y ahora está haciendo lo que estaba buscando:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Michel Krämer
169

Puede usar git add [path]/\*.javapara agregar archivos Java desde subdirectorios,
por ejemplo , git add ./\*.javapara el directorio actual.

De la git adddocumentación :

Agrega contenido de todos los *.txtarchivos en el Documentationdirectorio y sus subdirectorios:

$ git add Documentation/\*.txt

Tenga en cuenta que el asterisco *se cita del shell en este ejemplo; esto permite que el comando incluya los archivos de subdirectorios de Documentation/directorio.

Sergey Glotov
fuente
2
@ MichelKrämer probablemente no lo fue, pero lo es ahora.
Alberto
77
Esta es la mejor solución, también funciona en Windows.
TheTFo
1
"el asterisco * se cita del shell". Creo que te refieres a "escapado". En cualquier caso, la barra diagonal inversa evita que el shell lo expanda.
gwideman
1
@gwideman Creo que tienes razón, pero no soy yo. Es una cita de los documentos git-scm.com/docs/git-add#_examples
Sergey Glotov
62

Con zshusted puede correr:

git add "**/*.java"

y todos sus *.javaarchivos se agregarán de forma recursiva.

Olivier Verdier
fuente
Gracias por eso, pero estoy trabajando con msysgit en Windows y solo tiene un bash.
Michel Krämer
1
Bueno, veo que hay un zshshell para Windows ... te harás un favor para usarlo en lugar de bash, en mi humilde opinión.
Olivier Verdier
1
El puerto de Windows de zsh se basa en una versión muy antigua y se bloquea todo el tiempo (por ejemplo, cuando entro ls).
Michel Krämer
Wow perfecto. ¡No sabía sobre esa característica!
Tomáš Votruba
1
Esto no tiene nada que ver con zsh. Creo que esta respuesta pierde el punto de que desea pasar el camino con comodines intactos para git y dejar que git lo procese. Por lo tanto, desea evitar que cualquier shell que esté utilizando expanda los comodines. Para hacer esto, debe citarlo de alguna manera que sea apropiada para el shell que está utilizando. Ver otras respuestas para más detalles.
gwideman
55

Un poco fuera de tema (no específicamente relacionado con git) pero si estás en Linux / Unix, una solución podría ser:

find . -name '*.java' | xargs git add

Y si esperas caminos con espacios:

find . -name '*.java' -print0 | xargs -0 git add

Pero sé que eso no es exactamente lo que preguntaste.

Sergio Acosta
fuente
66
Problema menor con este enfoque: si "encuentra" un archivo que coincide con su .gitignore, entonces git se queja de que está tratando de agregar un archivo que le dijo que ignorara.
yoyo
2
@yoyo - Acabo de agregar -f al final, y eso solucionó eso
Maslow
55
@Maslow, eso agregará por la fuerza el archivo, aunque se suponía que debía ignorarse (basado en .gitignore). Prefiero recibir la queja y no agregar el archivo (que es el comportamiento predeterminado)
Yoyo
¿Cómo es esto de alguna manera mejor que dejar que git realice la expansión comodín?
gwideman
12

La respuesta de Sergey (no me creas) está funcionando:

You can use git add [path]/\*.java

con un git reciente:

$git version
git version 1.7.3.4

Archivos para la prueba:

$find -name .git -prune -o -type f -print | sort
./dirA/dirA-1/dirA-1-1/file1.txt
./dirA/dirA-1/dirA-1-2/file2.html
./dirA/dirA-1/dirA-1-2/file3.txt
./dirA/dirA-1/file4.txt
./dirB/dirB-1/dirB-1-1/file5.html
./dirB/dirB-1/dirB-1-1/file6.txt
./file7.txt

Estado de Git:

$git status -s
?? dirA/
?? dirB/
?? file7.txt

Agregando * .txt:

$git add \*.txt

Estado actualizado:

$git status -s
A  dirA/dirA-1/dirA-1-1/file1.txt
A  dirA/dirA-1/dirA-1-2/file3.txt
A  dirA/dirA-1/file4.txt
A  dirB/dirB-1/dirB-1-1/file6.txt
A  file7.txt
?? dirA/dirA-1/dirA-1-2/file2.html
?? dirB/dirB-1/dirB-1-1/file5.html
Alberto
fuente
8

Si ya está rastreando sus archivos y ha realizado cambios en ellos y ahora desea agregarlos selectivamente en función de un patrón, puede usar la --modifiedbandera

git ls-files --modified | grep '<pattern>' | xargs git add

Por ejemplo, si solo desea agregar los cambios de CSS a esta confirmación, puede hacer

git ls-files --modified | grep '\.css$' | xargs git add

Ver man git-ls-filespara más banderas

RAM
fuente
5

Solo úsalo git add *\*.java. Esto agregará todos los archivos .java en el directorio raíz y todos los subdirectorios.

Jan Lovstrand
fuente
Gran respuesta. Git add * / pom.xml para agregar todos los nombres de archivos pom.xml.
Philip Rego
4

Agregar una solución de línea de comandos de Windows que aún no se mencionó:

for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
sellador
fuente
3

Solo quería agregar archivos que tuvieran una determinada cadena basada en git status:

git status | grep string | xargs git add

y luego fue capaz de git commit -m 'commit msgconfirmar todos los archivos modificados con "cadena" en el título del archivo

bdanin
fuente
2

Como se menciona en " git: ¿Cómo agrego recursivamente todos los archivos en un subárbol de directorio que coinciden con un patrón global? ", Si escapa correctamente o cita su globbing de camino específico (como '*.java'), entonces sí, git add'*.java'

Git 2.13 (Q2 2017) mejora eso para la adición interactiva:

Ver commit 7288e12 (14 de marzo de 2017) por Jeff King ( peff) .
(Fusionada por Junio ​​C Hamano - gitster- en commit 153e0d7 , 17 mar 2017)

add --interactive: no expanda las rutas de acceso con ls-files

Cuando queremos obtener la lista de archivos modificados, primero expandimos las especificaciones de ruta proporcionadas por el usuario con " ls-files", y luego alimentamos la lista resultante de rutas como argumentos para " diff-index" y " diff-files".
Si su ruta específica se expande en una gran cantidad de rutas, puede encontrarse con uno de dos problemas:

  1. El sistema operativo puede quejarse del tamaño de la lista de argumentos y negarse a ejecutarse. Por ejemplo:

    $ (ulimit -s 128 && git add -p drivers)
    Can't exec "git": Argument list too long at .../git-add--interactive line 177.
    Died at .../git-add--interactive line 177.
    

Eso está en el linux.gitrepositorio, que tiene alrededor de 20K archivos en el directorio "drivers" (ninguno de ellos modificado en este caso). El " ulimit -s" truco es necesario para mostrar el problema en Linux incluso para un conjunto de caminos tan gigantesco.
Otros sistemas operativos tienen límites mucho más pequeños (por ejemplo, se vio un caso del mundo real con solo archivos de 5K en OS X).

  1. Incluso cuando funciona, es realmente lento. El código de camino específico no está optimizado para grandes cantidades de caminos. Aquí está el mismo caso sin el ulimit:

    $ time git add -p drivers
      No changes.
    
    real  0m16.559s
    user    0m53.140s
    sys 0m0.220s
    

Podemos mejorar esto omitiendo " ls-files" por completo y simplemente alimentando las rutas de acceso originales a los comandos diff.

Históricamente, el lenguaje pathpec soportado por " diff-index" era más débil, pero ese ya no es el caso.

VonC
fuente
1

poner línea en ~ / .gitconfig

[alias] addt = !sh -c 'git ls-files | grep \"\\.$1*\" | xargs git add' -

Si desea agregar todos los archivos Java modificados, simplemente puede hacer: git addt java

Del mismo modo, si desea agregar todos los archivos python modificados, simplemente puede hacer: git addt py

Hong Emrys
fuente