2012-01-05 13 views
85

Me he comprometido con id 56f06019 (por ejemplo). En esa confirmación he cometido accidentalmente un archivo grande (50Mb). En otro commit, agrego el mismo archivo pero en el tamaño correcto (pequeño). Ahora mi repo cuando clon es demasiado pesado :(Cómo eliminar ese archivo grande de la historia de recompra para reducir el tamaño de mi repoGit: cómo eliminar el archivo de la confirmación histórica?

+0

en mi caso, no es un archivo de gran tamaño, pero un archivo de configuración que contienen créditos de bases de datos. Estaba estudiando git, en ese momento no tenía conocimiento de .gitignore. – Rashi

+0

posible duplicado de [¿Cómo eliminar/eliminar un archivo grande del historial de confirmación en el repositorio de Git?] (Http: // stackoverflow.com/questions/2100907/how-to-remove-delete-a-large-file-from-commit-history-in-git-repository) –

Respuesta

123

El capítulo 9 del libro Pro Git tiene una sección en Removing Objects.

Permítanme exponer brevemente los pasos aquí:

git filter-branch --index-filter \ 
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \ 
    --tag-name-filter cat -- --all 

Al igual que la opción de cambio de base descrito antes, filter-branch está reescribiendo la operación. Si tiene historial publicado, tendrá que --force presionar las nuevas referencias.

El enfoque filter-branch es considerablemente más potente que el enfoque rebase, ya que

  • le permite trabajar en todas las ramas/referencias a la vez,
  • cambia el nombre de las etiquetas sobre la marcha
  • opera limpiamente incluso si ha habido varias confusiones de fusión desde la adición del archivo
  • funciona limpiamente incluso si el archivo fue (re) agregado/eliminado varias veces en el historial de (a) rama (s)
  • no crea nuevas confirmaciones no relacionadas, sino que las copia al modificar los árboles asociados a ellas. Esto significa que cosas como confirmaciones firmadas, notas, etc. cometen se conservan

filter-branch mantiene copias de seguridad también, por lo que el tamaño de la cesión temporal no va a disminuir de inmediato a menos que caducan los reflogs y limpieza de la memoria:

rm -Rf .git/refs/original  # careful 
git gc --aggressive --prune=now # danger 
+1

Vale la pena señalar que esto no parece funcionar en windows cmd.exe. Parece que funciona bien bajo cygwin, sin embargo. –

+1

Obtuve la rama de filtro git anterior para que funcione mediante el uso de comillas dobles en lugar de comillas simples (en cmd.exe de Windows Server 2012) – JCii

+0

Lo que funcionó para mí fue esta línea de comando de rama de filtro. 'git filter-branch --force --index-filter 'git rm --ignore-unmatch --caché PathTo/MyFile/ToRemove.dll' - fbf28b005^..' Luego 'rm --recursive - force .git/refs/original' y 'rm --recursive --force .git/logs' Luego usé el 'git ciruela --expire now' y' git gc --aggressive' Esto funcionó mejor para mí que tus pasos exactos enumerados arriba. Gracias por incluir el enlace al libro de Git Pro ya que fue invaluable. –

1

Tendrá que git rebase en el modo interactivo ver un ejemplo aquí:? How can I remove a commit on GitHub? y how to remove old commits.

Si su confirmación se HEAD menos 10 compromete:

$ git rebase -i HEAD~10 

Después de la edición de su historia, es necesario empujar la "nueva" historia, es necesario agregar la + a la fuerza (ver el refspec en el push options):

$ git push origin +master 

Si otras personas ya han clonado su repositorio, deberá informarles, porque acaba de cambiar el historial.

+3

Eso ** ** no ** elimina el archivo grande del historial. Además, la forma canónica de forzar push es 'git push --force' o' git push -f' (que no requiere que las personas conozcan el destino del branch push) – sehe

+0

Basado en la pregunta, el nuevo archivo es exactamente el mismo como el archivo anterior, es decir, el mismo camino. Esta es la razón por la cual no se puede usar 'git rm' directamente en la ruta. –

+2

@sehe, si haces una rebase eliminando la confirmación con el gran archivo, se va para siempre. – vonbrand

Cuestiones relacionadas