¿Cómo eliminar / eliminar un archivo grande del historial de confirmación en el repositorio de Git?

708

De vez en cuando soltaba un DVD-rip en un proyecto de sitio web, luego descuidadamente git commit -a -m ..., y, zap, el repositorio estaba lleno de 2,2 conciertos. La próxima vez que hice algunas ediciones, eliminé el archivo de video y lo comprometí todo, pero el archivo comprimido todavía está allí en el repositorio, en el historial.

Sé que puedo iniciar ramas de esos commits y volver a crear una rama en otra. Pero, ¿qué debo hacer para fusionar los 2 commits para que el archivo grande no se muestre en el historial y se limpie en el procedimiento de recolección de basura?

culebrón
fuente
99
Este artículo debería ayudarlo help.github.com/removing-sensitive-data
MBO
1
Tenga en cuenta que si su archivo grande está en una subdirección, deberá especificar la ruta relativa completa.
Johan
1
También relacionado help.github.com/en/articles/…
frederj
Muchas respuestas a continuación consideran que BFG es más fácil que git filter-branch, pero encontré que lo contrario es cierto.
2540625

Respuestas:

605

Use el BFG Repo-Cleaner , una alternativa más simple y más rápida a la git-filter-branchdiseñ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 de Git. Luego puede usar git gcpara limpiar los datos muertos:

$ git gc --prune=now --aggressive

El BFG suele ser al menos 10-50 veces más rápido que corrergit-filter-branch , y generalmente es más fácil de usar.

Divulgación completa: soy el autor del BFG Repo-Cleaner.

Roberto Tyley
fuente
44
@tony Vale la pena repetir todo el procedimiento de clonación y borrado para ver si el mensaje que le solicita que vuelva a aparecer, pero es casi seguro porque su servidor remoto está configurado para rechazar actualizaciones que no son de avance rápido (es decir, está configurado para detenerlo de perder la historia, que es exactamente lo que quieres hacer). Debe cambiar esa configuración en el control remoto o, en su defecto, llevar el historial de repositorios actualizado a un nuevo repositorio en blanco.
Roberto Tyley
1
@RobertoTyley Gracias. Lo he intentado 3 veces diferentes y todo resultó con el mismo mensaje. Por lo tanto, también creo que tiene razón acerca de que el servidor remoto está configurado para rechazar las actualizaciones que no son de avance rápido. Consideraré simplemente empujar el repositorio actualizado a un nuevo repositorio. ¡Gracias!
Tony
77
@RobertoTyley Perfecto, me ahorras tiempo, muchas gracias. Por cierto, tal vez debería hacerlo git push --forcedespués de sus pasos, de lo contrario, el repositorio remoto aún no ha cambiado.
li2
3
1 a añadir git push --force. También vale la pena señalar: es posible que el control remoto no permita los empujes forzados (gitlab.com no lo hace, por defecto. Tuvo que "desproteger" la rama).
MatrixManAtYrService
25
Creo que la jerga de Trump que genera la herramienta es un poco demasiado.
Chris
564

Lo que desea hacer es altamente perjudicial si ha publicado el historial a otros desarrolladores. Consulte "Recuperación de la base de datos ascendente" en la git rebasedocumentación para conocer los pasos necesarios después de reparar su historial.

Tiene al menos dos opciones: git filter-branchy un rebase interactivo, ambos explicados a continuación.

Utilizando 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 lolaes un alias no estándar pero muy útil. Con el --name-statusinterruptor, podemos ver las modificaciones del árbol asociadas con cada confirmación.

En el commit "Descuidado" (cuyo nombre de objeto SHA1 es ce36c98) el archivo oops.isoes el DVD-rip agregado por accidente y eliminado en el siguiente commit, cb14efd. Usando la técnica descrita en la publicación de blog mencionada anteriormente, el comando para 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-emptyelimina las confirmaciones que se vuelven vacías ( es decir , no cambian el árbol) como resultado de la operación de filtro. En el caso típico, esta opción produce un historial más limpio.
  • -dnombra 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, la especificación de un árbol /dev/shmdará como resultado una ejecución más rápida .
  • --index-filteres el evento principal y se ejecuta contra el índice en cada paso de la historia. Desea eliminar oops.isodonde se encuentre, pero no está presente en todas las confirmaciones. El comando git rm --cached -f --ignore-unmatch oops.isoelimina el DVD-rip cuando está presente y no falla de lo contrario.
  • --tag-name-filterdescribe cómo reescribir nombres de etiquetas. Un filtro de cates la operación de identidad. Es posible que su repositorio, como el ejemplo anterior, no tenga etiquetas, pero incluí esta opción para una generalidad completa.
  • -- especifica el final de las opciones para git filter-branch
  • --allLo siguiente --es una abreviatura para todas las referencias. Su repositorio, como el ejemplo anterior, puede tener solo una referencia (maestra), pero incluí esta opción para una generalidad completa.

Después de algunos cambios, 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 "Descuidado" solo agrega other.htmly que la confirmación "Eliminar DVD-rip" ya no está en la rama maestra. La rama etiquetada refs/original/refs/heads/mastercontiene 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

El uso de una file:///...URL de clonación copia objetos en lugar de crear solo enlaces duros.

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. “Descuidado” perdido oops.isoy “página de inicio de sesión” consiguieron un nuevo padre, por lo que sus SHA1s hicieron el cambio.

Rebase interactivo

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.isode "Descuidado" como si nunca lo hubiera agregado, y luego "Eliminar DVD-rip" es inútil para usted. Por lo tanto, nuestro plan para crear una nueva versión interactiva es mantener la "Página de administración", editar "Descuidado" y descartar "Eliminar DVD-rip".

La ejecución $ git rebase -i 5af4522inicia 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.
#

Al ejecutar nuestro plan, lo modificamos a

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 "Descuidado" para que sea en editlugar de pick.

Guardar-salir del editor nos deja en el 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 nos dice el mensaje, estamos en el compromiso "Descuidado" 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 "Descuidado" para que sea el índice actualizado e -C HEADindica a git que reutilice el antiguo mensaje de confirmación. Finalmente, git rebase --continuecontinú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

Greg Bacon
fuente
44
¿Por qué no puedo presionar cuando uso git filter-branch? No pude insertar algunas referencias en '[email protected]: product / myproject.git'. cambia antes de presionar nuevamente.
Agung Prasetyo
11
Agregue la opción -f(o --force) a su git pushcomando: “Por lo general, el comando se niega a actualizar una referencia remota que no sea un antecesor de la referencia local utilizada para sobrescribirla. Esta bandera deshabilita el cheque. Esto puede hacer que el repositorio remoto pierda confirmaciones; úsalo con cuidado ".
Greg Bacon
55
Esta es una respuesta maravillosamente exhaustiva que explica el uso de git-filter-branch para eliminar archivos grandes no deseados del historial, pero vale la pena señalar que desde que Greg escribió su respuesta, se lanzó el BFG Repo-Cleaner, que a menudo es más rápido y fácil de usar. uso - vea mi respuesta para más detalles.
Roberto Tyley
1
Después de realizar cualquiera de los procedimientos anteriores, el repositorio remoto (en GitHub) NO elimina el archivo grande. Solo lo hace el local. Forzo empujar y nada. ¿Qué me estoy perdiendo?
azatar
1
Esto también funciona en directorios. ... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop
198

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

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

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

Si sabe qué commit introdujo el archivo enorme (digamos 35dsa2), puede reemplazar HEAD con 35dsa2..HEAD para evitar reescribir demasiado historial, evitando así las confirmaciones divergentes si aún no ha presionado. Este comentario cortesía de @ alpha_989 parece demasiado importante para dejarlo aquí.

Ver este enlace .

Gary Gauh
fuente
3
¡Esta es una buena solución! He creado un gist que tiene un script de python para enumerar los archivos y el cmd de git que eliminará el archivo que desea limpiar gist.github.com/ariv3ra/16fd94e46345e62cfcbf
punkdata
55
Mucho mejor que bfg. No pude limpiar el archivo de un git con bfg, pero este comando ayudó
podarok
44
Esto es genial. Solo una nota para los demás que tendrá que hacer esto por rama si el archivo grande está en varias ramas.
James
2
En Windows obtuve fatal: bad revision 'rm', lo que solucioné usando en "lugar de '. Comando general:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
marcotama
2
Si sabe commitdónde coloca el archivo (digamos 35dsa2), puede reemplazarlo HEADpor 35dsa2..HEAD. tree-filteres mucho más lento que de index-filteresa manera, no intentará verificar todas las confirmaciones y reescribirlas. si usa HEAD, intentará hacerlo.
alpha_989
86

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

🚀 Una carcasa 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 repositorio de muestra, se ejecutó aproximadamente 100 veces más rápido que los otros que se encuentran aquí.
En mi confiable sistema Athlon II X4, maneja el repositorio Kernel de Linux 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 buena salida legible para humanos 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 ay bde cada confirmación accesible HEAD, puede usar este comando:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD
Sridhar Sarnobat
fuente
3
Si tu repositorio tiene ninguna etiqueta, es probable que también desee agregar la opción --tag-name-filter catde re-etiqueta de la nueva confirmaciones correspondientes a medida que se vuelven a escribir, es decir, git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD(ver esta respuesta relacionada )
naitsirhc
3
Las instrucciones de Mac y alguna otra información aparecen en la publicación original vinculada
nruth
3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADorden de trabajo a la derecha del bate
eleijonmarck
mi respuesta favorita un ligero ajuste para usar en mac os (usando comandos gnu)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 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Florian Oswald
guión genial con la lista de revoluciones, pero no me funcionó como un alias, ¿alguna idea de cómo hacerlo?
Robin Manoli
47

Después de probar prácticamente todas las respuestas en SO, finalmente encontré esta gema que rápidamente eliminó y eliminó los archivos grandes en mi repositorio y me permitió sincronizar nuevamente: http://www.zyxware.com/articles/4027/how-to-delete -archivos-permanentemente-de-sus-repositorios-locales-y-remotos-git

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 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 envíe todos los cambios al repositorio remoto:

git push --all --force

Esto limpiará el repositorio remoto.

Justin
fuente
Funcionó como un encanto para mí.
Ramon Vasconcelos
3
Esto funcionó para mí también. Se deshace de una carpeta específica (en mi caso, una que contenía archivos demasiado grandes o un repositorio de Github) en el repositorio, pero la mantiene en el sistema de archivos local en caso de que exista.
skizzo
¡Trabajó para mi! sin antecedentes se deja que se podían provocar confusión (si alguien dónde clon ahora), asegúrese de que tiene un plan para actualizar los enlaces rotos, dependencias, etc.
Ruoho Sueco
38

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 llevar 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
Kostanos
fuente
44
¿En qué se diferencia de lo anterior, por qué es mejor?
Andy Hayden
1
Por alguna razón, la versión mkljun no reduce el espacio git en mi caso, ya había eliminado los archivos del índice mediante el uso git rm --cached files. La propuesta de Greg Bacon es más completa, y bastante similar a esta mina, pero se perdió el índice de fuerza para los casos en que está utilizando filter-branch varias veces, y escribió tanta información que mi versión es como un currículum de eso.
Kostanos
1
Esto realmente ayudó, pero necesitaba usar la -fopción no solo -rfaquí en git rm --cached -rf --ignore-unmatch oops.isolugar de git rm --cached -r --ignore-unmatch oops.isosegún @ lfender6445 a continuación
drstevok
10

Solo tenga en cuenta que estos comandos pueden ser muy destructivos. Si hay más personas trabajando en el repositorio, todos tendrán que sacar el 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
mkljun
fuente
11
NO ejecute estos comandos a menos que desee crear un inmenso dolor para usted. Eliminó muchos de mis archivos de código fuente original. Supuse que purgaría algunos archivos grandes de mi historial de confirmación en GIT (según la pregunta original), sin embargo, creo que este comando está diseñado para purgar permanentemente archivos de su árbol de código fuente original (¡gran diferencia!). Mi sistema: Windows, VS2012, Git Source Control Provider.
Contango
2
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
Usé
8

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

Soheil
fuente
7

Me encontré con esto con una cuenta de bitbucket, donde accidentalmente había almacenado copias de seguridad ginormous * .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-DIRECTORYcon la carpeta en cuestión para reescribir completamente su historial ( incluidas las etiquetas ).

fuente: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/

lfender6445
fuente
1
Esta respuesta me ayudó, excepto que el script en la respuesta tiene un pequeño problema y no busca en todas las ramas de mí. Pero el comando en el enlace lo hizo perfectamente.
Ali B
5

Esto lo eliminará de tu historial

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all
brillar
fuente
Esto funcionó para mí, gracias!
Sonja británica
Esto funciona en mi caso. Ejecuto esto en tu rama maestra.
S. Domeng
4

Básicamente hice lo que estaba en esta respuesta: https://stackoverflow.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 los treeobjetos que apuntan a ese archivo. 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 (the .git) cambió de 32 MB a 388 KB, que incluso la rama de filtro no podía limpiar.

Dolanor
fuente
4

git filter-branches un poderoso comando que puede usar para eliminar un archivo enorme del historial de confirmaciones. El archivo permanecerá por un tiempo y Git lo eliminará en la próxima recolección de basura. A continuación se muestra el proceso completo para eliminar archivos del historial de confirmación . Por seguridad, el siguiente proceso ejecuta los comandos en una nueva rama primero. Si el resultado es lo que necesitaba, vuelva a restablecerlo en la rama que realmente desea cambiar.

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master
zhangyu12
fuente
2

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

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

Nir
fuente
Este método es muuuy lento para repositorios grandes. Me llevó más de una hora enumerar los archivos grandes. Luego, cuando voy a eliminar archivos, después de una hora solo queda 1/3 del proceso para procesar el primer archivo que quiero eliminar.
kristianp
Sí, es lento, pero funciona ... ¿Sabes algo más rápido?
Nir
1
No lo he usado, pero BFG Repo-Cleaner, según otra respuesta en esta página.
Kristianp
2

Puedes hacer esto usando el branch filtercomando:

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

John Foley
fuente
2

Hay muy buenas respuestas en este hilo, pero mientras tanto, muchas de ellas están desactualizadas. El uso git-filter-branchya no se recomienda, porque es difícil de usar y muy lento en grandes repositorios.

git-filter-repo Es mucho más rápido y sencillo de usar.

git-filter-repoes un script de Python, disponible en github: https://github.com/newren/git-filter-repo .

Solo necesita un archivo: el script Python3 git-filter-repo. Cópielo en una ruta incluida en la variable PATH. En Windows puede que tenga que cambiar la primera línea de la secuencia de comandos (consulte INSTALL.md). Necesita instalar Python3 instalado en su sistema, pero esto no es gran cosa.

Primero puedes correr

git filter-repo --analyze

Esto le ayuda a determinar qué hacer a continuación.

Puede eliminar su archivo de extracción de DVD en todas partes:

 git filter-repo --invert-paths --path-match DVD-rip

Filter-repo es realmente rápido. Una tarea que tomó alrededor de 9 horas en mi computadora por filter-branch, se completó en 4 minutos por filter-repo. Puedes hacer muchas más cosas buenas con filter-repo. Consulte la documentación para eso.

Advertencia: haga esto en una copia de su repositorio. Muchas acciones de filter-repo no se pueden deshacer. ¡filter-repo cambiará los hashes de confirmación de todas las confirmaciones modificadas (por supuesto) y todos sus descendientes hasta las últimas confirmaciones!

Donat
fuente
1

Cuando se encuentre con este problema, git rmno 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, el rebase tampoco es fácil, porque cualquier referencia al blob evitará que el recolector de basura git limpie el espacio. Esto incluye referencias remotas y referencias de registro.

Creé git forget-blobun pequeño script que intenta eliminar todas estas referencias, y luego usa git filter-branch para reescribir cada commit en la rama.

Una vez que su blob esté completamente desreferenciado, git gclo eliminará

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/

Lo armé gracias a las respuestas de Stack Overflow y algunas entradas de blog. Créditos para ellos!

nachoparker
fuente
deberías tener esto en homebrew
Cameron E
0

Además de git filter-branch(solución git lenta pero pura) y BFG (más fácil y muy eficaz), también hay otra herramienta para filtrar con buen rendimiento:

https://github.com/xoofx/git-rocket-filter

De su descripción:

El propósito de git-rocket-filter es similar al comando git-filter-branchmientras proporciona las siguientes características únicas:

  • Reescritura rápida de commits y árboles (por un orden de x10 a x100).
  • Soporte incorporado tanto para la lista blanca con --keep (mantiene archivos o directorios) como para la lista negra con las opciones --remove.
  • Uso de .gitignore como patrón para el filtrado de árboles
  • Scripting C # rápido y fácil para el filtrado de confirmación y el filtrado de árbol
  • Soporte para secuencias de comandos en el filtrado de árboles por patrón de archivo / directorio
  • Pode automáticamente la confirmación vacía / sin cambios, incluidas las confirmaciones de fusión
Philippe
fuente