¿Cómo eliminar objetos no utilizados de un repositorio de git?

89

Agregué, comprometí y empujé accidentalmente un archivo binario enorme con mi última confirmación en un repositorio de Git.

¿Cómo puedo hacer que Git elimine los objetos que se crearon para esa confirmación para que mi .git directorio se reduzca a un tamaño razonable nuevamente?

Editar : Gracias por tus respuestas; Probé varias soluciones. Ninguno funcionó. Por ejemplo, el de GitHub eliminó los archivos del historial, pero el .gittamaño del directorio no ha disminuido:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Jonas H.
fuente
13
Solo un recordatorio para los moderadores, esta pregunta pertenece al 100% a SO, no al superusuario.
VonC
Como se menciona aquí ( stackoverflow.com/questions/685319/… ), ¿probaste un reempaquetado después de tu gc? git-repack -aseguido de, git-prune-packedpor ejemplo. Ver blog.felipebalbi.com/2007/12/19/…
VonC
2
@Jonas: ¿y si, después de hacer todo eso, clonas tu repositorio? ¿ Conseguirías entonces un clon con el tamaño reducido deseado?
VonC
1
@Jonas: después de todo lo que hicieron ( filter-branch, gc, repack, ...), no, usted no debe ver ninguna entrega mala en absoluto. Esta es una señal de que la limpieza no se realizó como se esperaba.
VonC

Respuestas:

127

¡Respondí esto en otro lugar y lo copiaré aquí ya que estoy orgulloso de ello!

... y sin más preámbulos, puedo presentarles este útil script, git-gc-all, garantizado para eliminar toda su basura git hasta que puedan generar variables de configuración adicionales:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
  -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
  -c gc.pruneExpire=now gc "$@"

La opción --aggressive puede resultar útil.

NOTA: esto eliminará TODAS las cosas no referenciadas, ¡así que no me vengas llorando si decides más tarde que querías quedarte con algunas de ellas!

Es posible que también debas ejecutar algo como esto primero, ¡oh, cielos, git es complicado!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ |
  xargs -n1 --no-run-if-empty git update-ref -d

Pongo todo esto en un guión, aquí:

http://sam.nipl.net/b/git-gc-all-ferocious

Sam Watkins
fuente
Como en stackoverflow.com/questions/1904860/… , +1 para ti nuevamente.
VonC
18
excelente: ¡D mi malvado plan para obtener más puntos clonando respuestas ha funcionado! 1;)
Sam Watkins
¡Si! Esto funcionó, pero tuve que ejecutar el script completo. Ejecutar solo el comando gc (con opciones de configuración) no fue suficiente.
Daniel
4
102m a 160k .. efectivo y destructivo
prusswan
4
¡Muchas gracias por el guión! Información adicional: el xargscomando produce un error en OS X debido a una opción no reconocida. La solución más simple: instale GNU xargs a través de homebrew brew install findutilsy reemplácelo xargspor gxargs.
qqilihq
26

Tu git reflog expire --alles incorrecto. Elimina las entradas de registro que son más antiguas que el tiempo de vencimiento, que por defecto es de 90 días. Utilice git reflog expire --all --expire=now.

Mi respuesta a una pregunta similar trata sobre el problema de borrar realmente los objetos no utilizados de un repositorio.

Josh Lee
fuente
18

1) Elimine el archivo del repositorio de git (y no del sistema de archivos):

  • git rm --cached path/to/file

2) Reducir el repositorio usando:

  • git gc,

  • o git gc --aggressive

  • o git prune

o una combinación de lo anterior como se sugiere en esta pregunta: Reducir el tamaño del repositorio de git

Jamie
fuente
10

Esta guía sobre la eliminación de datos confidenciales se puede aplicar utilizando el mismo método. Volverá a escribir el historial para eliminar ese archivo de todas las revisiones en las que estaba presente. Esto es destructivo y provocará conflictos de repositorio con cualquier otro pago, por lo que debe advertir primero a los colaboradores.

Si desea mantener el binario disponible en el repositorio para otras personas, entonces no hay una forma real de hacer lo que desea. Es prácticamente todo o nada.

Daenyth
fuente
8

La clave para mí resultó ser ejecutar git repack -A -d -fy luego git gcreducir el tamaño del paquete de git único que tenía.

Andrew Charneski
fuente
6

¡Hy!

Git solo recibe los objetos que realmente necesita al clonar repositorios (si lo entiendo correctamente)

Entonces puede modificar la última confirmación eliminando el archivo agregado por error, luego enviar sus cambios al repositorio remoto (con la opción -f para sobrescribir la confirmación anterior también en el servidor)

Luego, cuando haga un nuevo clon de ese repositorio, su directorio .git debe ser tan pequeño como antes de que se comprometieran los archivos grandes.

Opcionalmente, si también desea eliminar los archivos innecesarios del servidor, puede eliminar el repositorio en el servidor y enviar su copia recién clonada (que tiene el historial completo)

u-foka
fuente
4
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

Recuerde cambiar Filenamepor el que desea eliminar del repositorio.

Martín
fuente