ver pendientes oneline modificados log eliminar commits archivos git version-control git-rebase git-rewrite-history

pendientes - ¿Cómo eliminar/eliminar un archivo grande del historial de confirmaciones en el repositorio Git?



git ver archivos modificados (14)

¿Por qué no usar este comando simple pero poderoso?

git filter-branch --tree-filter ''rm -f DVD-rip'' HEAD

La opción --tree-filter ejecuta el comando especificado después de cada verificación del proyecto y luego vuelve a enviar los resultados. En este caso, elimina un archivo llamado DVD-rip de cada instantánea, ya sea que exista o no.

Vea este enlace .

Ocasionalmente, coloqué un DVD-rip en un proyecto de sitio web, y luego, descuidadamente, git commit -a -m ... , y, zap, el repo fue hinchado por 2,2 conciertos. La próxima vez hice algunas ediciones, eliminé el archivo de video y lo confirmé todo, pero el archivo comprimido todavía está allí en el repositorio, en la historia.

Sé que puedo comenzar ramas desde esos compromisos y cambiar de base una rama a otra. Pero, ¿qué debo hacer para unir los 2 confirmaciones para que el archivo grande no se muestre en el historial y se limpie en el procedimiento de recolección de basura?


(La mejor respuesta que he visto a este problema es: https://.com/a/42544963/714112 , copiado aquí ya que este hilo aparece alto en los rankings de búsqueda de Google pero ese otro no)

🚀 Una cáscara increíblemente rápida de una sola línea 🚀

Este script de shell muestra todos los objetos de blob en el repositorio, ordenados de menor a mayor.

Para mi muestra de recompra, corrió unas 100 veces más rápido que los otros que se encuentran aquí.
En mi confiable sistema Athlon II X4, maneja el repositorio de Linux Kernel con sus 5,622,155 objetos en poco más de un minuto .

El guión base

git rev-list --objects --all / | git cat-file --batch-check=''%(objecttype) %(objectname) %(objectsize) %(rest)'' / | awk ''/^blob/ {print substr($0,6)}'' / | sort --numeric-sort --key=2 / | cut --complement --characters=13-40 / | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

Cuando ejecute el código anterior, obtendrá una salida agradable y legible para el ser humano como esta:

... 0d99bb931299 530KiB path/to/some-image.jpg 2ba44098e28f 12MiB path/to/hires-image.png bd1741ddce0d 63MiB path/to/some-video-1080p.mp4

🚀 Eliminación rápida de archivos 🚀

Supongamos que desea eliminar los archivos a y b de cada confirmación accesible desde HEAD , puede usar este comando:

git filter-branch --index-filter ''git rm --cached --ignore-unmatch a b'' HEAD


Básicamente hice lo que estaba en esta respuesta: https://.com/a/11032521/1286423

(Para la historia, lo copiaré y pegaré aquí)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD $ rm -rf .git/refs/original/ $ git reflog expire --all $ git gc --aggressive --prune $ git push origin master --force

No funcionó, porque me gusta cambiar el nombre y mover muchas cosas. Por lo tanto, algunos archivos grandes estaban en carpetas que han sido renombradas, y creo que el gc no pudo eliminar la referencia a esos archivos debido a la referencia en tree objetos del tree que apuntan a esos archivos. Mi solución definitiva para matarlo realmente fue:

# First, apply what''s in the answer linked in the front # and before doing the gc --prune --aggressive, do: # Go back at the origin of the repository git checkout -b newinit <sha1 of first commit> # Create a parallel initial commit git commit --amend # go back on the master branch that has big file # still referenced in history, even though # we thought we removed them. git checkout master # rebase on the newinit created earlier. By reapply patches, # it will really forget about the references to hidden big files. git rebase newinit # Do the previous part (checkout + rebase) for each branch # still connected to the original initial commit, # so we remove all the references. # Remove the .git/logs folder, also containing references # to commits that could make git gc not remove them. rm -rf .git/logs/ # Then you can do a garbage collection, # and the hidden files really will get gc''ed git gc --prune --aggressive

Mi repositorio (el .git ) cambió de 32MB a 388KB, que incluso la rama de filtro no pudo limpiar.


Cuando se encuentre con este problema, git rm no será suficiente, ya que git recuerda que el archivo existió una vez en nuestro historial y, por lo tanto, mantendrá una referencia a él.

Para empeorar las cosas, la reorganización tampoco es fácil, ya que cualquier referencia a la mancha evitará que el recolector de basura Git limpie el espacio. Esto incluye referencias remotas y referencias de reflog.

Puse git forget-blob , un pequeño script que intenta eliminar todas estas referencias, y luego usa git filter-branch para reescribir cada confirmación en la rama.

Una vez que tu blob no esté referenciado completamente, git gc se deshará de él.

El uso es bastante simple git forget-blob file-to-forget . Puedes obtener más información aquí

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

Puse esto junto gracias a las respuestas de y algunas entradas de blog. Créditos a ellos!


Después de probar virtualmente cada respuesta en SO, finalmente encontré esta gema que eliminó y eliminó rápidamente los archivos grandes en mi repositorio y me permitió sincronizar nuevamente: http://www.zyxware.com/articles/4027/how-to-delete-files-permanently-from-your-local-and-remote-git-repositories

CD a su carpeta de trabajo local y ejecute el siguiente comando:

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all

reemplace FOLDERNAME con el archivo o carpeta que desea eliminar del repositorio de git dado.

Una vez hecho esto, ejecute los siguientes comandos para limpiar el repositorio local:

rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now

Ahora empuje todos los cambios al repositorio remoto:

git push --all --force

Esto limpiará el repositorio remoto.


Estos comandos funcionaron en mi caso:

git filter-branch --force --index-filter ''git rm --cached -r --ignore-unmatch oops.iso'' --prune-empty --tag-name-filter cat -- --all rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now

Es un poco diferente de las versiones anteriores.

Para aquellos que necesitan enviar esto a github / bitbucket (solo probé esto con bitbucket):

# WARNING!!! # this will rewrite completely your bitbucket refs # will delete all branches that you didn''t have in your local git push --all --prune --force # Once you pushed, all your teammates need to clone repository again # git pull will not work


Lo que quieres hacer es altamente perjudicial si has publicado el historial para otros desarrolladores. Consulte “Recuperación de Rebase de Upstream” en la documentación de git rebase para conocer los pasos necesarios después de reparar su historial.

Tiene al menos dos opciones: git filter-branch y una rebase interactiva, ambas explicadas a continuación.

Usando git filter-branch

Tuve un problema similar con los datos de prueba binarios voluminosos de una importación de Subversion y escribí sobre la eliminación de datos de un repositorio git .

Digamos que tu historial de git es:

$ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html

Tenga en cuenta que git lola es un alias no estándar pero muy útil. Con el interruptor --name-status , podemos ver modificaciones de árbol asociadas con cada confirmación.

En la confirmación "Sin cuidado" (cuyo nombre de objeto SHA1 es ce36c98) el archivo oops.iso es el DVD-rip agregado por accidente y eliminado en la próxima confirmación, cb14efd. Usando la técnica descrita en la publicación de blog mencionada anteriormente, el comando a ejecutar es:

git filter-branch --prune-empty -d /dev/shm/scratch / --index-filter "git rm --cached -f --ignore-unmatch oops.iso" / --tag-name-filter cat -- --all

Opciones:

  • --prune-empty elimina las confirmaciones que se vuelven vacías ( es decir , no cambian el árbol) como resultado de la operación de filtrado. En el caso típico, esta opción produce un historial más limpio.
  • -d nombra un directorio temporal que aún no existe para usar para construir el historial filtrado. Si está ejecutando en una distribución moderna de Linux, especificar un árbol en /dev/shm resultará en una ejecución más rápida .
  • --index-filter es el evento principal y se ejecuta contra el índice en cada paso del historial. Desea eliminar oops.iso donde se encuentre, pero no está presente en todos los confirmaciones. El comando git rm --cached -f --ignore-unmatch oops.iso elimina el DVD-rip cuando está presente y, de lo contrario, no falla.
  • --tag-name-filter describe cómo reescribir los nombres de etiquetas. Un filtro de cat es la operación de identidad. Es posible que su repositorio, como el ejemplo anterior, no tenga ninguna etiqueta, pero incluí esta opción para una generalidad completa.
  • -- Especifica el final de las opciones para git filter-branch
  • --all siguientes -- es una abreviatura de todas las referencias. Su repositorio, como el ejemplo anterior, puede tener solo un ref (maestro), pero incluí esta opción para generalidad completa.

Después de algunos batidos, la historia es ahora:

$ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html | * f772d66 (refs/original/refs/heads/master) Login page | | A login.html | * cb14efd Remove DVD-rip | | D oops.iso | * ce36c98 Careless |/ | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html

Tenga en cuenta que la nueva confirmación "Sin other.html " agrega solo other.html y que la other.html "Eliminar DVD-rip" ya no está en la rama principal. La rama etiquetada refs/original/refs/heads/master contiene sus confirmaciones originales en caso de que haya cometido un error. Para eliminarlo, siga los pasos en "Lista de verificación para reducir un repositorio".

$ git update-ref -d refs/original/refs/heads/master $ git reflog expire --expire=now --all $ git gc --prune=now

Para una alternativa más simple, clone el repositorio para descartar los bits no deseados.

$ cd ~/src $ mv repo repo.old $ git clone file:///home/user/src/repo.old repo

Al usar un file:///... URL clonada copia los objetos en lugar de crear solo enlaces físicos.

Ahora tu historia es:

$ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html

Los nombres de objeto SHA1 para las dos primeras confirmaciones ("Índice" y "Página de administración") permanecieron iguales porque la operación de filtro no modificó esas confirmaciones. oops.iso "descuidado" y "página de inicio de sesión" consiguieron un nuevo padre, por lo que sus SHA1 cambiaron.

Rebase interactiva

Con una historia de:

$ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html

desea eliminar oops.iso de "No tener oops.iso " como si nunca lo hubiera agregado, y luego "Eliminar DVD-rip" es inútil para usted. Por lo tanto, nuestro plan de entrar en una reorganización interactiva es mantener la "Página de administración", editar "Sin cuidado" y descartar "Eliminar DVD-rip".

Al ejecutar $ git rebase -i 5af4522 inicia un editor con los siguientes contenidos.

pick ce36c98 Careless pick cb14efd Remove DVD-rip pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit''s log message # x, exec = run command (the rest of the line) using shell # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. #

Ejecutando nuestro plan, lo modificamos para

edit ce36c98 Careless pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # ...

Es decir, eliminamos la línea con "Eliminar DVD-rip" y cambiamos la operación en "Sin cuidado" para edit lugar de pick .

Guardar-salir del editor nos deja en un símbolo del sistema con el siguiente mensaje.

Stopped at ce36c98... Careless You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue

Como el mensaje nos dice, estamos en la confirmación "Sin cuidado" que queremos editar, por lo que ejecutamos dos comandos.

$ git rm --cached oops.iso $ git commit --amend -C HEAD $ git rebase --continue

El primero elimina el archivo ofensivo del índice. El segundo modifica o modifica "Descuido" para que sea el índice actualizado y -C HEAD indica a git que reutilice el mensaje de confirmación anterior. Finalmente, git rebase --continue continúa con el resto de la operación de rebase.

Esto da una historia de:

$ git lola --name-status * 93174be (HEAD, master) Login page | A login.html * a570198 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html

que es lo que quieres


Me encontré con esto con una cuenta de bitbucket, donde accidentalmente había almacenado grandes copias de seguridad * .jpa de mi sitio.

git filter-branch --prune-empty --index-filter ''git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE'' --tag-name-filter cat -- --all

Relpace MY-BIG-DIRECTORY con la carpeta en cuestión para volver a escribir completamente su historial ( incluidas las etiquetas ).

fuente: http://naleid.com/blog/2012/01/17/finding-and-purging-big-files-from-git-history


Puedes hacer esto usando el comando de branch filter :

git filter-branch --tree-filter ''rm -rf path/to/your/file'' HEAD


Si sabe que su confirmación fue reciente, en lugar de recorrer todo el árbol, haga lo siguiente: git filter-branch --tree-filter ''rm LARGE_FILE.zip'' HEAD~10..HEAD


Solo tenga en cuenta que estos comandos pueden ser muy destructivos. Si hay más personas trabajando en el repositorio, todos tendrán que tirar del nuevo árbol. Los tres comandos intermedios no son necesarios si su objetivo NO es reducir el tamaño. Debido a que la rama del filtro crea una copia de seguridad del archivo eliminado y puede permanecer allí durante mucho tiempo.

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD $ rm -rf .git/refs/original/ $ git reflog expire --all $ git gc --aggressive --prune $ git push origin master --force


Usa Git Extensions , es una herramienta de interfaz de usuario. Tiene un complemento llamado "Buscar archivos grandes" que encuentra los archivos lage en los repositorios y permite eliminarlos de forma permanente.

No use ''git filter-branch'' antes de usar esta herramienta, ya que no podrá encontrar los archivos eliminados por ''filter-branch'' (A pesar de que ''high-filter-branch'' no elimina los archivos completamente de los archivos del paquete de repositorio) .


Use BFG Repo-Cleaner , una alternativa más simple y rápida a git-filter-branch diseñada específicamente para eliminar archivos no deseados del historial de Git.

Siga cuidadosamente las instrucciones de uso , la parte central es solo esto:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

Cualquier archivo de más de 100 MB de tamaño (que no esté en su última confirmación) se eliminará del historial de su repositorio Git. Luego puedes usar git gc para limpiar los datos muertos:

$ git gc --prune=now --aggressive

El BFG suele ser al menos 10-50x más rápido que ejecutar git-filter-branch y, en general, es más fácil de usar.

Revelación completa: soy el autor de BFG Repo-Cleaner.