git gc: ¿La recolección de basura está deshabilitada en la recepción posterior?

He intentado codificar un experimento que implica poner el siguiente código en el gancho git post-receive :

 unset GIT_DIR cd (path to some temp directory outside the repository) git clone --local (path to repository just pushed to) . git checkout dev git reset --hard HEAD^ git reflog expire --expire=now --all git gc --aggressive --prune=now 

Básicamente lo que estoy haciendo es clonar el repository que acaba de ser enviado, hacer un restablecimiento completo para eliminar el último compromiso y luego hacer la recolección de elementos no utilizados para eliminar los rastros del último compromiso del historial. Para comprobar que la recolección de basura realmente está haciendo su trabajo, dedico un gran file de 4 MB en la última confirmación, y luego verifico el tamaño de .git para ver si ha sido eliminado.

Entonces cuando ejecuto este código dentro del gancho "post-receive" de git, el reinicio parece funcionar bien; el repository clonado vuelve al estado sin el gran file. Sin embargo, la recolección de basura no parece haber funcionado. El tamaño de .git sigue siendo enorme.

Por otro lado, si ejecuto manualmente "git reflog" y "git gc" desde la command-line en este punto, elimina correctamente los rastros del file enorme, y el tamaño de .git se restaura a un tamaño manejable.

¿Alguna idea de por qué la recolección de basura puede comportarse de manera diferente cuando se ejecuta dentro de "post-recepción", en lugar de en un símbolo del sistema?

La recolección de basura agresiva de Git podría no estar haciendo lo que estás esperando. Linus publicó sobre esto aquí. Pero también se ha cubierto en otras publicaciones:

  • git gc –aggressive vs git repack
  • los problemas de "git gc -aggressive" (y cómo funcionan los deltas git)
  • Cómo usar git repack -a -d –depth = 250 –window = 250
  • La recolección de basura Git no parece funcionar completamente

De acuerdo, creo que logré llegar al background de esto. En realidad, no tiene nada que ver con estar en post-recepción, o no.

Solo un poco más sobre el problema que provocó esta pregunta. Tengo un repository, llámalo "repo". El último compromiso con este repository fue un file enorme, llámalo "BigFatFile.bin" Esto tiene 4 MB de tamaño. Este file no debe estar en el repository. Entonces mi bash de solucionar el problema es este:

  1. Clona el repository.
  2. Do git reset --hard para eliminar el último commit.

Estos pasos logran eliminar "BigFatFile.bin" del repository clonado. Sin embargo, los efectos de este empuje siguen siendo visibles, en el sentido de que el directory .git todavía es enorme: los 4MB de "BigFatFile.bin" aún se reflejan en el directory .git/objects/pack

En este punto, puedo probar varios commands de limpieza para tratar de deshacerme de los efectos de "BigFatFile.bin":

 git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin git reflog expire --expire=now --all git repack -a -d -f --depth=250 --window=250 git gc --aggressive --prune=now --force 

Estos pasos no tienen un efecto significativo en el tamaño de .git . Sin embargo, lo que descubrí es que si hago git push -f origin master inmediatamente después de git reset --hard , y luego hago los pasos de limpieza, el tamaño de .git vuelve a ser lo que era antes de que se "empujara BigFatFile.bin" . Esto no resuelve mi problema (porque aunque el repository clonado está de vuelta como estaba, el repository original aún está hinchado en tamaño). Sin embargo, responde mi pregunta acerca de por qué la recolección de basura (y otras medidas de limpieza) no estaban teniendo efecto: hasta que "presione" mis cambios, .git debe mantener no solo el contenido local de los files, sino también su contenido original.

Entonces mi pregunta original (¿por qué la limpieza no funcionó a nivel local?) Es respondida, aunque todavía no conozco la respuesta a la pregunta real, que es cómo restablecer el repository remoto para que no muestre los efectos del compromiso. de "BigFatFile.txt"