Linus sugirió (ver a continuación la publicación completa de la lista de correo) usar git gc --aggressive
solo cuando tenga, en sus palabras, "un paquete realmente malo" o "deltas realmente horriblemente malos", sin embargo, "casi siempre, en otros casos, es realmente un mal cosas que hacer." ¡El resultado puede incluso dejar su repositorio en peores condiciones que cuando comenzó!
El comando que sugiere para hacer esto correctamente después de haber importado "una historia larga y complicada" es
Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST)
From: Linus Torvalds <torvalds at linux-foundation dot org>
To: Daniel Berlin <dberlin at dberlin dot org>
cc: David Miller <davem at davemloft dot net>,
ismail at pardus dot org dot tr,
gcc at gcc dot gnu dot org,
git at vger dot kernel dot org
Subject: Re: Git and GCC
In-Reply-To: <[email protected]>
Message-ID: <[email protected]>
References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
El jueves 6 de diciembre de 2007, Daniel Berlin escribió:
En realidad, resulta que git-gc --aggressive
hace esta tontería empacar archivos a veces, independientemente de si ha convertido de un repositorio SVN o no.
Absolutamente. git --aggressive
es mayormente tonto. Realmente solo es útil para el caso de "Sé que tengo un paquete realmente malo y quiero deshacerme de todas las malas decisiones de empaque que he tomado".
Para explicar esto, vale la pena explicar (probablemente lo sepas, pero déjame repasar los conceptos básicos de todos modos) cómo funcionan las cadenas delta de git y cómo son tan diferentes de la mayoría de los otros sistemas.
En otros SCM, una cadena delta generalmente es fija. Puede ser "hacia adelante" o "hacia atrás" y puede evolucionar un poco a medida que trabaja con el repositorio, pero generalmente es una cadena de cambios en un solo archivo representado como algún tipo de entidad SCM única. En CVS, obviamente es el *,v
archivo, y muchos otros sistemas hacen cosas bastante similares.
Git también hace cadenas delta, pero las hace mucho más "sueltas". No existe una entidad fija. Los deltas se generan contra cualquier otra versión aleatoria que git considere un buen candidato delta (con varias heurísticas bastante exitosas), y no hay absolutamente ninguna regla de agrupación estricta.
En general, esto es algo muy bueno. Es bueno por varias razones conceptuales ( es decir , git internamente nunca necesita preocuparse por toda la cadena de revisión, realmente no piensa en términos de deltas), pero también es genial porque deshacerse de las inflexibles reglas delta significa que git no tiene ningún problema al fusionar dos archivos, por ejemplo, simplemente no hay *,v
“archivos de revisión” arbitrarios que tengan algún significado oculto.
También significa que la elección de deltas es una cuestión mucho más abierta. Si limita la cadena delta a un solo archivo, realmente no tiene muchas opciones sobre qué hacer con los deltas, pero en git, realmente puede ser un problema totalmente diferente.
Y aquí es donde --aggressive
entra en juego lo realmente mal llamado . Si bien git generalmente intenta reutilizar la información delta (porque es una buena idea, y no desperdicia el tiempo de la CPU para encontrar todos los deltas buenos que encontramos antes), a veces quiero decir "comencemos de nuevo, con una pizarra en blanco, ignoremos toda la información delta anterior e intente generar un nuevo conjunto de deltas".
Así --aggressive
que no se trata realmente de ser agresivo, sino de perder el tiempo de la CPU volviendo a tomar una decisión que ya tomamos antes.
A veces eso es bueno. Algunas herramientas de importación en particular podrían generar deltas realmente horriblemente malos. Cualquier cosa que use git fast-import
, por ejemplo, probablemente no tenga un gran diseño delta, por lo que podría valer la pena decir "Quiero comenzar desde cero".
Pero casi siempre, en otros casos, es realmente algo realmente malo. Va a desperdiciar tiempo de CPU, y especialmente si realmente ha hecho un buen trabajo en deltaing antes, el resultado final no va a reutilizar todos esos buenos deltas que ya encontró, por lo que en realidad terminará con mucho peor resultado final también!
Enviaré un parche a Junio para eliminar la git gc --aggressive
documentación. Puede ser útil, pero generalmente es útil solo cuando realmente comprende a un nivel muy profundo lo que está haciendo, y esa documentación no lo ayuda a hacerlo.
Generalmente, hacer incrementos git gc
es el enfoque correcto y mejor que hacerlo git gc --aggressive
. Va a reutilizar los deltas antiguos, y cuando no se puedan encontrar esos deltas antiguos (¡la razón para hacer GC incremental en primer lugar!), Creará otros nuevos.
Por otro lado, es definitivamente cierto que una "importación inicial de una historia larga y complicada" es un punto en el que puede valer la pena dedicar mucho tiempo a encontrar los deltas realmente buenos . Entonces, todos los usuarios posteriores (¡siempre que no lo git gc --aggressive
deshagan!) Obtendrán la ventaja de ese evento único. Entonces, especialmente para proyectos grandes con una larga historia, probablemente valga la pena hacer un trabajo adicional, diciéndole al código de búsqueda delta que se vuelva loco.
Entonces, el equivalente de git gc --aggressive
, pero hecho correctamente , es hacer (durante la noche) algo como
git repack -a -d --depth=250 --window=250
donde esa profundidad se trata de cuán profundas pueden ser las cadenas delta (hazlas más largas para la historia antigua, vale la pena el espacio), y la cuestión de la ventana se trata de qué tan grande es la ventana de objeto que queremos que escanee cada candidato delta.
Y aquí, es posible que desee agregar la -f
bandera (que es "eliminar todos los deltas antiguos", ya que ahora está tratando de asegurarse de que este realmente encuentre buenos candidatos.
Y luego tomará una eternidad y un día ( es decir , una cosa de "hazlo de la noche a la mañana"). Pero el resultado final es que todos los usuarios posteriores a ese repositorio obtendrán paquetes mucho mejores, sin tener que gastar ningún esfuerzo en ellos.
Linus
Como mencioné en " La recolección de basura de Git no parece funcionar completamente ", a
git gc --aggressive
no es suficiente ni siquiera suficiente por sí solo.Y, como explico a continuación , a menudo no es necesario.
La combinación más efectiva sería agregar
git repack
, pero tambiéngit prune
:Nota: Git 2.11 (Q4 2016) establecerá la
gc aggressive
profundidad predeterminada en 50Consulte la confirmación 07e7dbf (11 de agosto de 2016) de Jeff King (
peff
) .(Combinado por Junio C Hamano -
gitster
- en el compromiso 0952ca8 , 21 de septiembre de 2016)(Ver compromiso para estudio )
Hablando de ahorro de CPU, "
git repack
" aprendí a aceptar la--threads=<n>
opción y pasarla a pack-objects.Consulte la confirmación 40bcf31 (26 de abril de 2017) de Junio C Hamano (
gitster
) .(Combinado por Junio C Hamano -
gitster
- en el compromiso 31fb6f4 , 29 de mayo de 2017)Ya lo hacemos por
--window=<n>
y--depth=<n>
; esto ayudará cuando el usuario quiera forzar--threads=1
pruebas reproducibles sin verse afectado por las carreras de múltiples hilos.fuente
git gc --aggressive
se ha solucionado dos veces: primero, hacer lo que Linus sugirió en 2007 como un "mejor método de empaque". Y luego en Git 2.11 para evitar la profundidad de objeto excesiva que Linus había sugerido pero que resultó ser dañina (ralentiza todas las operaciones futuras de Git y no ahorró ningún espacio del que valga la pena hablar).man git-repack
dice para-d
: `También ejecuta git prune-pack para eliminar archivos de objetos sueltos redundantes. '¿Ogit prune
también hace eso?man git-prune
diceIn most cases, users should run git gc, which calls git prune.
, entonces, ¿para qué sirve despuésgit gc
? ¿No sería mejor o suficiente usar sologit repack -Ad && git gc
?El problema
git gc --aggressive
es que el nombre de la opción y la documentación son engañosos.Como explica el propio Linus en este correo , lo que
git gc --aggressive
básicamente hace es esto:Por lo general, no es necesario volver a calcular los deltas en git, ya que git determina que estos deltas son muy flexibles. Solo tiene sentido si sabes que tienes deltas muy, muy malos. Como explica Linus, principalmente las herramientas que utilizan
git fast-import
caen en esta categoría.La mayoría de las veces, git hace un buen trabajo determinando deltas útiles y el uso
git gc --aggressive
te dejará con deltas que son potencialmente incluso peores y pierden mucho tiempo de CPU.Linus termina su correo con la conclusión de que
git repack
con un gran--depth
y--window
es la mejor opción en la mayor parte del tiempo; especialmente después de importar un proyecto grande y querer asegurarse de que git encuentre buenos deltas.fuente
Precaución. No lo ejecute
git gc --agressive
con un repositorio que no esté sincronizado con el remoto si no tiene copias de seguridad.Esta operación recrea los deltas desde cero y podría provocar la pérdida de datos si se interrumpe correctamente.
Para mi computadora de 8GB, el gc agresivo se quedó sin memoria en el repositorio de 1Gb con 10k pequeñas confirmaciones. Cuando OOM killer terminó el proceso de git, me dejó con un repositorio casi vacío, solo sobrevivieron el árbol de trabajo y pocos deltas.
Por supuesto, no era la única copia del repositorio, así que simplemente lo recreé y lo saqué del control remoto (la búsqueda no funcionó en el repositorio roto y se bloqueó en el paso 'resolver deltas' varias veces, intenté hacerlo), pero si su repositorio es Repositorio local de un solo desarrollador sin ningún tipo de control remoto: primero haga una copia de seguridad.
fuente
Nota: tenga cuidado con el uso
git gc --aggressive
, como aclara Git 2.22 (Q2 2019).Ver confirmar 0044f77 , confirmar daecbf2 , confirmar 7384504 , confirmar 22d4e3b , confirmar 080a448 , confirmar 54d56f5 , confirmar d257e0f , confirmar b6a8d09 (07 de abril de 2019) y confirmar fc559fb , confirmar cf9cd77 , confirmar b11e856 (22 de marzo de 2019) por Ærvar Bjarmajöson (Ærvar Bjarmajöson
avar
) .(Combinado por Junio C Hamano -
gitster
- en el compromiso ac70c53 , 25 de abril de 2019)Eso significa que la documentación de git-gc ahora incluye :
Y ( comete 080a448 ):
fuente