Formas de mejorar el rendimiento del estado de git

80

Tengo un repositorio de 10 GB en una máquina Linux que está en NFS. La primera vez git statusdura 36 minutos y la siguiente git status8 minutos. Parece que Git depende del sistema operativo para almacenar archivos en caché. Solo los primeros gitcomandos como commit, statusque implican empaquetar / reempaquetar todo el repositorio, requieren mucho tiempo para un repositorio enorme. No estoy seguro de si lo ha utilizado git statusen un repositorio tan grande, pero ¿alguien se ha encontrado con este problema?

He tratado git gc, git clean, git repackpero el tiempo que se tarda es todavía / casi lo mismo.

¿Ayudarán los submódulos o cualquier otro concepto como dividir el repositorio en otros más pequeños? Si es así, ¿cuál es la mejor opción para dividir un repositorio más grande? ¿Hay alguna otra forma de mejorar el tiempo necesario para los comandos git en un repositorio grande?

Senthil A Kumar
fuente
2
NFS es prácticamente el cuello de botella aquí. lstat es una operación bastante sincronizada.
user611775
1
El posible duplicado del estado
Seth Battin

Respuestas:

45

Para ser más precisos, git depende de la eficiencia de la lstat(2)llamada al sistema, por lo que ajustar el “tiempo de espera de la caché de atributos” de su cliente podría ser suficiente.

El manual para git-update-index, esencialmente un modo manual para git-status, describe lo que puede hacer para aliviar esto, utilizando la --assume-unchangedbandera para suprimir su comportamiento normal y actualizar manualmente las rutas que ha cambiado. Incluso puede programar su editor para que desactive este indicador cada vez que guarde un archivo.

La alternativa, como sugiere, es reducir el tamaño de su pago (el tamaño de los archivos de paquete no entra en juego aquí). Las opciones son un pago escaso, submódulos o la herramienta de repositorio de Google .

(Hay un hilo de la lista de correo sobre el uso de Git con NFS , pero no responde a muchas preguntas).

Josh Lee
fuente
31
Lo que te perdiste: el parche de Linus allí realmente se fusionó, y se puede habilitar estableciéndolo core.preloadindexen verdadero; consulta los git-configdocumentos para obtener una descripción más detallada. (Mi lugar de trabajo usa NFS y me encontré exactamente con este problema, pero nunca noté la configuración de preloadindex. ¡Gracias por indicarme el camino correcto!)
Cascabel
1
'git config core.preloadindex true' debe agregarse a la respuesta aceptada aquí. posiblemente con la bandera -uno de user1077329
ostler.c
2
core.preloadindexLa bandera se establece en verdadero de forma predeterminada a partir de Git 2.1.0: git.kernel.org/pub/scm/git/git.git/tree/Documentation/RelNotes/…
Petr Gazarov
38

También veo este problema en un gran proyecto compartido a través de NFS.

Me tomó algo de tiempo descubrir el flag -uno que se puede asignar tanto a git commit como a git status.

Lo que hace esta bandera es deshabilitar la búsqueda de archivos sin seguimiento. Esto reduce significativamente el número de operaciones nfs. La razón es que para que git descubra archivos sin seguimiento, tiene que buscar en todos los subdirectorios, por lo que si tiene muchos subdirectorios, esto lo perjudicará. Al deshabilitar a git para que no busque archivos sin seguimiento, eliminas todas estas operaciones NFS.

Combine esto con el indicador core.preloadindex y puede obtener un rendimiento razonable incluso en NFS.

usuario1077329
fuente
Como se menciona en git-status (1), se puede configurar como predeterminado configurando el status.showUntrackedFilesarchivo config.
johankj
33

Prueba git gc . Además, git clean puede ayudar.

ACTUALIZACIÓN : no estoy seguro de dónde vino el voto en contra, pero el manual de git establece específicamente:

Ejecuta una serie de tareas de limpieza dentro del repositorio actual, como comprimir revisiones de archivos (para reducir el espacio en disco y aumentar el rendimiento ) y eliminar objetos inalcanzables que pueden haber sido creados a partir de invocaciones anteriores de git add.

Se anima a los usuarios a ejecutar esta tarea de forma regular dentro de cada repositorio para mantener una buena utilización del espacio en disco y un buen rendimiento operativo.

¡Siempre noto una diferencia después de ejecutar git gc cuando el estado de git es lento!

ACTUALIZACIÓN II : no estoy seguro de cómo me perdí esto, pero el OP ya lo intentó git gcy git clean. Juro que originalmente no estaba allí, pero no veo ningún cambio en las ediciones. ¡Lo siento por eso!

Jabari
fuente
5
Tampoco entiendo el voto en contra; esto es realmente útil. git gcreduzca el tiempo de git logejecución de 15 segundos a 0 en uno de mis repositorios.
GreenRaccoon 23
@NicolasC ¡Ah! No estoy seguro de cómo me perdí eso, pero también votaría en contra de mi respuesta. : - /
Jabari
1
git cg es bueno, git clean ¿tal vez podría eliminar algún archivo no deseado?
Luca Reghellin
18

Si su repositorio de git hace un uso intensivo de submódulos, puede acelerar enormemente el rendimiento del estado de git editando el archivo de configuración en el directorio .git y configurando ignore = dirtylos submódulos particularmente grandes / pesados. Por ejemplo:

[submodule "mysubmodule"]
url = ssh://mysubmoduleURL
ignore = dirty

Perderá la conveniencia de un recordatorio de que hay cambios sin etapas en cualquiera de los submódulos que puede haber olvidado, pero aún conservará la conveniencia principal de saber cuándo los submódulos no están sincronizados con el repositorio principal. Además, aún puede cambiar su directorio de trabajo al submódulo mismo y usar git status dentro de él como de costumbre para ver más información. Consulte esta pregunta para obtener más detalles sobre lo que significa "sucio".

beno
fuente
7

El rendimiento del estado de git debería mejorar con Git 2.13 (segundo trimestre de 2017).

Consulte la confirmación 950a234 (14 de abril de 2017) de Jeff Hostetler ( jeffhostetler) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 8b6bba6 , 24 de abril de 2017)

> string-list: use ALLOC_GROWmacro al reasignarstring_list

Utilice ALLOC_GROW()macro al reasignar una string_listmatriz en lugar de simplemente aumentarla en 32.
Esta es una optimización del rendimiento.

Durante el estado de un repositorio muy grande y hay muchos cambios, un porcentaje significativo del tiempo de ejecución total se dedica a reasignar la wt_status.changesmatriz .

Este cambio reduce el tiempo wt_status_collect_changes_worktree()de 125 segundos a 45 segundos en mi gran repositorio.


Además, Git 2.17 (Q2 2018) introducirá un nuevo rastreo, para medir dónde se pasa el tiempo en las operaciones con muchos índices.

Consulte la confirmación ca54d9b (27 de enero de 2018) de Nguyễn Thái Ngọc Duy ( pclouds) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 090dbea , 15 de febrero de 2018)

trace: mide dónde se gasta el tiempo en las operaciones con muchos índices

Se miden todos los bloques de código pesado conocidos (excepto el acceso a la base de datos de objetos). Esto debería ayudar a identificar si una optimización es efectiva o no.
Un estado de git no optimizado daría algo como a continuación:

0.001791141 s: read cache ...
0.004011363 s: preload index
0.000516161 s: refresh index
0.003139257 s: git command: ... 'status' '--porcelain=2'
0.006788129 s: diff-files
0.002090267 s: diff-index
0.001885735 s: initialize name hash
0.032013138 s: read directory
0.051781209 s: git command: './git' 'status'

El mismo Git 2.17 (Q2 2018) mejora git statuscon:

revision.c: reducir las consultas de la base de datos de objetos

En mark_parents_uninteresting(), verificamos la existencia de un archivo de objeto para ver si debemos tratar una confirmación como analizada. El resultado es establecer el bit "analizado" en la confirmación.

Modifique la condición para verificar solo has_object_file()si el resultado cambiaría el bit analizado.

Cuando una rama local es diferente de su referencia ascendente, " git status" calculará los recuentos de adelante / atrás.
Esto usa paint_down_to_common()y golpea mark_parents_uninteresting().

En una copia del repositorio de Linux con una instancia local de "master" detrás de la rama remota " origin/master" por ~ 60,000 confirmaciones, encontramos que el rendimiento de " git status" pasó de 1.42 segundos a 1.32 segundos, para una diferencia relativa de -7.0%.


Git 2.24 (Q3 2019) propone otra configuración para mejorar el git statusrendimiento:

Consulte confirmar aaf633c , confirmar c6cc4c5 , confirmar ad0fb65 , confirmar 31b1de6 , confirmar b068d9a , confirmar 7211b9e (13 de agosto de 2019) por Derrick Stolee ( derrickstolee) .
(Combinado por Junio ​​C Hamano - gitster- en commit f4f8dfe , 09 de septiembre de 2019)

repo-settings: crea la configuración feature.manyFiles

La feature.manyFilesconfiguración es adecuada para repositorios con muchos archivos en el directorio de trabajo.
Al establecer index.version=4y core.untrackedCache=true, los comandos como " git status" deberían mejorar.

Pero:

Con Git 2.24 (Q4 2019), la ruta de código que lee la index.versionconfiguración se rompió con una actualización reciente, que se ha corregido.

Consulte la confirmación c11e996 (23 de octubre de 2019) de Derrick Stolee ( derrickstolee) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 4d6fb2b , 24 de octubre de 2019)

repo-settings: lee un int para index.version

Firmado por: Derrick Stolee

Varias opciones de configuración se combinaron en una repo_settingsestructura en ds / feature-macros, incluido un movimiento de la configuración de configuración "index.version" en 7211b9e (" repo-settings: consolidar algunas configuraciones de configuración", 2019-08-13, Git v2.24.0-rc1 - fusión listada en el lote # 0 ).

Desafortunadamente, ese archivo parecía un montón de texto estándar y lo que es claramente un factor de sobrecarga de copiar y pegar, la configuración de configuración se analiza con en repo_config_ge_bool()lugar de repo_config_get_int(). Esto significa que una configuración "index.version = 4" no se registraría correctamente y volvería a la versión predeterminada de 3.

Capté esto al incorporar v2.24.0-rc0 en el código base de VFS para Git, donde realmente nos importa que el índice esté en la versión 4.

Esto no fue detectado por el código base porque las comprobaciones de versión realizadas t1600-index.shno probaron lo suficiente el escenario "básico". Aquí, modificamos la prueba para incluir estas configuraciones normales para que no sean anuladas por features.manyFileso GIT_INDEX_VERSION.
Si bien la versión "predeterminada" es la 3, se degrada a la versión 2 do_write_index()cuando no es necesario.

VonC
fuente
Consulte también stackoverflow.com/a/43667992/6309 y la nueva index.threadsconfiguración de configuración
VonC
GIT_TRACE = true git log Así es como se ejecuta el rastreo y se encuentra el cuello de botella
dhavale
@dhavale En realidad, desde Git .22, también tiene trace2: stackoverflow.com/a/56094711/6309
VonC
4

git config --global core.preloadIndex true

Hizo el trabajo por mí. Consulta la documentación oficial aquí .

klimat
fuente
¿Qué versión de Git estás usando?
VonC
2.7.4. Utilizo Linux Subsystem para Windows e incluso actualizado apt-getparece tener referencias a paquetes bastante antiguos.
klimat
1
Vale, tiene sentido. No creo que sea necesario con una versión más reciente.
VonC
Esto incluso me ayudó con la versión 2.17.1 de git
Markus Zeller
1

En nuestro código base donde tenemos en algún lugar en el rango de 20 a 30 submódulos,
git status --ignore-submodules
aceleró drásticamente las cosas. Tenga en cuenta que esto no informará sobre el estado de los submódulos .

ciudad rodeada
fuente
1

Algo que no se ha mencionado todavía es activar el caché del sistema de archivos en máquinas con Windows (los sistemas de archivos de Linux son completamente diferentes y git fue optimizado para ellos, por lo que probablemente esto solo ayude en Windows).

git config core.fscache true


Como último recurso, si git sigue siendo lento, se podría desactivar la inspección del tiempo de modificación, que git necesita averiguar qué archivos han cambiado.

git config core.ignoreStat true

PERO: Los archivos modificados deben ser agregados posteriormente por el desarrollador con git add. Git no encuentra cambios por sí mismo.

fuente

dCSeven
fuente
Esto me ayudó en Windows 10, aunque tenía una versión bastante reciente de Git para Windows. Gracias. Mi repositorio era de ~ 100 Gb en la carpeta .git (git lfs)
Alex Sorokoletov
0

index.lockArchivos sobrantes

git statuspuede ser patológicamente lento cuando tiene index.lockarchivos sobrantes .

Esto sucede especialmente cuando lo tiene git submodules, porque entonces a menudo no nota los archivos sobrantes.

Resumen: Ejecute find .git/ -name index.locky elimine los archivos sobrantes después de comprobar que ningún programa que se esté ejecutando actualmente los esté utilizando.


Detalles

Descubrí que el estado de mi shell git era extremadamente lento en mi repositorio, con git 2.19 en Ubuntu 16.04.

Cavé y encontré que /usr/bin/time git statusen miassets submódulo git tomó 1.7 segundos.

Encontrado con straceese git, leyó todos mis archivos grandes allí con mmap. No suele hacer eso, normalmente states suficiente.

Busqué en Google el problema y encontré el problema Uso del índice y Racy Git .

Intenté git update-index somefile(en mi caso gitignoreen el pago del submódulo) que se muestra aquí pero falló con

fatal: Unable to create '/home/niklas/src/myproject/.git/modules/assets/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.

Este es un error clásico. Por lo general, lo nota en cualquier operación de git, pero para los submódulos con los que no se compromete a menudo, es posible que no lo note durante meses, porque solo aparece al agregar algo al índice; la advertencia no se genera en modo de solo lectura git status.

Eliminar el index.lockarchivo, se git statushizo rápido de inmediato,mmaps desapareció y ahora es 1000 veces más rápido.

Entonces, si su estado de git es anormalmente lento, verifique find .git/ -name index.locky elimine las sobras.

nh2
fuente
0

Es una pregunta bastante antigua. Sin embargo, me sorprende que nadie haya comentado sobre el archivo binario dado el tamaño del repositorio.

Mencionaste que tu repositorio git es ~ 10GB. Parece que, aparte del problema de NFS y otros problemas de git (que se pueden resolver git gcy cambiar la configuración de git como se describe en otras respuestas), los comandos de git (git status, git diff, git add) pueden ser lentos debido a la gran cantidad de archivos binarios en el repositorio . git no es bueno para manejar archivos binarios. Puede eliminar el archivo binario innecesario usando el siguiente comando (se proporciona un ejemplo para el archivo NetCDF; tenga una copia de seguridad del repositorio de git antes):

git filter-branch --force --index-filter \  
'git rm --cached --ignore-unmatch *.nc' \   
--prune-empty --tag-name-filter cat -- --all

No olvide poner '* .nc' en el archivo gitignore para evitar que git vuelva a enviar el archivo.

EM_
fuente