Eliminar una carpeta del historial de un repository de git no hace que el repo sea más pequeño

Leí muchas preguntas vinculadas, pero tengo el siguiente problema.

En este repository , había files grandes en media/1 Juno-Trumpet (en confirmaciones anteriores), así que seguí exactamente la respuesta aquí para eliminar estos files:

 git clone https://github.com/alexmacrae/SamplerBox.git git count-objects -vH 

Tamaño total del file: 54MB

 git filter-branch --tree-filter 'rm -rf "media/1 Juno-Trumpet"' --prune-empty HEAD git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d echo "media/1 Juno-Trumpet/" >> .gitignore git add .gitignore git commit -m 'Removing a folder from git history' git gc git count-objects -vH 

Tamaño total del file: 54MB

Pregunta: ¿Por qué no ha cambiado el tamaño del repository? ¿Cómo hacer que el tamaño del repository sea más pequeño después de dicha limpieza?

Ejecutando git filter-branch realidad copy cada commit que se filtra. El repository resultante nunca es más pequeño, bueno, todavía no, y generalmente es más grande . Si tiene suerte o es inteligente, la mayoría de las copys reutilizan la mayoría de los objects originales, de modo que el repository resultante es solo un poco más grande que el original.

Es razonable preguntar: "Entonces, ¿por qué deberíamos filtrar un repository?" Y, de hecho, la mayoría de las veces no debería: es un gran dolor de cabeza (al less, por lo less) para todos los que usan el repository, ya que todos tienen que cambiar al nuevo repository filtrado. Pero la verdadera respuesta es que después del filtrado, puede eliminar las references a los objects originales (pre-copy) o clonar el repository en un nuevo clon nuevo.

Las references de los objects originales se guardan en refs/original/ y en reflogs (en particular, el reflog HEAD generalmente los tendrá). Consulte las instrucciones al final de la documentation de git filter-branch para saber cómo eliminarlas, si elige (por alguna razón absurda) no simplemente volver a clonar el repository filtrado.

los commits antiguos, que aún contienen el subdirectory, todavía forman parte del repository, aunque no se puede acceder desde ninguna twig.

para limpiarlos podrías hacer

 git reflog expire --expire=now --all && git gc --prune=now --aggressive 

sin embargo, esto vaciará tu reflog. eso es necesario porque las confirmaciones a las que hace reference su reflog no serán recogidas de basura

Solo una versión completa list para usar, basada en la respuesta aceptada de @ lucanLepus.

Digamos que soy userA , y quiero eliminar totalmente la carpeta de history media/1 Juno-Trumpet/ (que ya no está presente en las últimas confirmaciones, sino en commits muy lejanos) del repository en Github.

NB: este repository en particular tiene las twigs originales master , sfz , y wifi , y la label v1.0 . Para evitar tener que saber esto, utilizo un clon de espejo aquí (que hace un repository desnudo, lo cual está bien ya que usaré un filter de índice). Entonces, como este es GitHub, arrojo todos los refs/pull/ refs primero.

Como resultado, los files también se denominan media/Juno-Trumpet/ y media/Juno/ , por lo que debemos eliminar los tres nombres de ruta.

 git clone --mirror https://github.com/alexmacrae/SamplerBox.git cd SamplerBox.git git for-each-ref --format="git update-ref -d %(refname)" refs/pull | sh git for-each-ref # to check that we have only wanted refs left git count-objects -vH # size-pack: 54.40 MiB git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch "media/1 Juno-Trumpet" media/Juno-Trumpet media/Juno' --prune-empty --tag-name-filter cat -- --all 

El paso de twig de filter tarda un poco y termina con:

 Ref 'refs/heads/master' was rewritten Ref 'refs/heads/sfz' was rewritten Ref 'refs/heads/wifi' was rewritten WARNING: Ref 'refs/tags/v1.0' is unchanged v1.0 -> v1.0 (7ec3254d08b65fd3ca8a048cef60b5b2c75f7e11 -> 7ec3254d08b65fd3ca8a048cef60b5b2c75f7e11) 

(Esta última línea indica que la label en el repository viene antes que cualquiera de las confirmaciones reescritas, es decir, no necesitamos --tag-name-filter cat después de todo).

Ahora debemos eliminar los refs/original/ names. Dado que se trata de un clon nuevo, no hay ningún reflog para caducar, pero lo haremos de todos modos, y luego volver a empaquetarlo con git gc :

 git for-each-ref --format="git update-ref -d %(refname)" refs/original | sh git reflog expire --expire=now --all git gc --prune=now --aggressive git count-objects -vH # size-pack: 1.41 MiB 

No he hecho este último paso:

 git push origin '+refs/*:refs/*' 

(y si está realmente seguro de querer que todos los files multimedia se hayan ido por completo, es posible que también quiera eliminar todas las requestes de extracción, ya que de lo contrario las retendrán por un time).


Incidentalmente, encontré los files bajo los tres nombres usando:

 git cat-file --batch-all-objects --batch-check | sort +2 -rn | head 

para encontrar files relativamente grandes, seguidos de:

 git rev-list --all | while read ref; do git ls-tree -r $ref | grep 477145c7d0190f4e0aeea0f7bfb9accbf2c1ba48; done | sort -u 

( 477145c7d0190f4e0aeea0f7bfb9accbf2c1ba48 es uno de los files .wav grandes. No verifiqué si todos los files eliminados son files .wav y si quedan otros files .wav ).