2009-05-30 17 views
20

Tengo un archivo grande de 33 MB en el que quiero eliminar de forma permanente las revisiones más antiguas de ese archivo, por lo que solo guardo las últimas X revisiones. ¿Cómo hacerlo?git eliminar las revisiones más antiguas de un archivo

Mi repositorio desnudo ha crecido enormemente debido a ello.

He intentado el siguiente .. pero elimina el archivo completo

git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' HEAD 

Para identificar los archivos de gran tamaño en mi repositorio que utilizo git-large-blob by Aristotle Pagaltzis.

+0

Creo que ayudaría si proporcionas más información sobre este archivo y lo que intentas hacer. ¿Va a ser un evento único o planea purgar el archivo y reescribir el historial del repositorio regularmente? ¿Por qué estás rastreando el archivo en git si no necesitas mantener su historial? ¿Qué tan grande es su repositorio desnudo y realmente es un problema si es grande? –

+0

es un manual para mi programa, estoy escribiendo usando páginas de Apple (procesador de textos) e incluye muchas imágenes. Lo almaceno en GIT principalmente para poder compartirlo entre mi computadora estacionaria y mi computadora portátil, así que lo deshago en caso de que algo salga mal. El repositorio es actualmente de 450 MB. Dudo en trabajar con el archivo porque sé que el tamaño del repositorio aumenta. En lugar de replantear mi solución de respaldo, pensé que sería mejor deshacerse de las revisiones más antiguas. Tomo diariamente una instantánea completa del repositorio y lo cargo, pero la cuota del disco es de 3 gb. – neoneye

+0

sí, estoy esperando que esto sea posible de vez en cuando. – neoneye

Respuesta

16

Creo que está en el camino correcto con el comando git filter-branch que probó. El problema es que no le has dicho que guarde el archivo en ningún commit, por lo que se elimina de todos ellos. Ahora, no creo que haya una forma de directamente decir git-filter-branch para omitir cualquier confirmación. Sin embargo, dado que los comandos se ejecutan en un contexto de shell, no debería ser demasiado difícil utilizar el shell para eliminar todo menos el último número de revisiones X. Algo como esto:

KEEP=10 I=0 NUM_COMMITS=$(git rev-list master | wc -l) \ 
git filter-branch --index-filter \ 
'if [[ ${I} -lt $((NUM_COMMITS - KEEP)) ]]; then 
    git rm --cached --ignore-unmatch big_manual.txt; 
fi; 
I=$((I + 1))' 

que mantendría big_manual.txt en los últimos 10 confirmaciones.

Dicho esto, como ha mencionado Charles, no estoy seguro de que este sea el mejor enfoque, ya que de hecho se está deshaciendo de VCS al eliminar versiones antiguas.

¿Ya ha intentado optimizar el repositorio de git con git-gc y/o git-repack? Si no, podría valer la pena intentarlo.

+1

¡esta es la solución! Revisó las 312 revisiones y descartó las revisiones más antiguas, perfectas. Esto fue muy educativo. Para bucles, rev-list ... y llamar a filter-branch sin ningún id. De commit que parezca no intuitivo (tendrá que investigar cómo funciona esa magia), pero funcionó. Gracias por eso. A veces uso git-gc y fsck, pero aún no es algo que haya automatizado. No hablemos de mi opinión sobre VCS :-) – neoneye

+1

>> No hablemos de mi opinión sobre VCS :-) Bastante :) Me alegra que esto haya funcionado para usted. En cuanto a la magia de no especificar una revisión, git-filter-branch llama internamente a git-rev-list para obtener la lista de confirmaciones para reescribir. Pasará "HEAD" a git-rev-list como una referencia predeterminada si no especifica uno. Entonces, no especificar nada es lo mismo que especificar "HEAD" (como lo hiciste en tu ejemplo). –

+0

Gracias por el guión. Lo hice en un archivo de script bash y encontré que necesitaba ajustarlo ligeramente ' #!/bin/bash KEEP = 10 I = 0 NUM_COMMITS = $ (git rev-list master | wc -l) \ git filter-branch --index-filter \ 'if [$ {I} -lt $ ((NUM_COMMITS - KEEP))]; luego git rm --cached --ignore-unmatch file-to-delete.tar; fi; I = $ ((I + 1)) ' ' –

15

Nota: esta respuesta se trata de acortar la historia de todo un proyecto, en lugar de eliminar solo archivo de la historia más antigua cuál era la pregunta acerca!


La forma más sencilla para acortar la historia de un todo el proyecto utilizando git filter-branch sería utilizar injertos mecanismo de (ver repository layout documentación) para acortar la historia:

$ echo "$commit_id" >> .git/info/grafts 

donde $commit_id es una confirmación que desea que sea una raíz (primera confirmación) de un nuevo repositorio. Consulte usando "git log" o visor gráfico de historial, como gitk, que el historial se parece a lo que desea, y ejecute "git filter-branch --all"; el uso de injertos se describe en la documentación de git-filter-branch.

O puede usar clon superficial utilizando la opción --depth <depth> de git clone.



Puede hacer uso de injertos para eliminar la historia parte de un único archivo (lo que se solicitó originalmente) utilizando pasos describen a continuación. Esta solución consta de más pasos que solution proposed by Dan Moulding, pero cada uno de los pasos es más simple, y puede verificar los pasos intermedios usando "git log" o visor de historial gráfico.

  1. Primero seleccione el punto, en el que quieren tener el archivo eliminado, y marcar esas confirmaciones mediante la creación de sucursales en esos puntos. Por ejemplo, si usted quiere tener el archivo aparece por primera vez en comprometerse f020285b y se lo retiren en todo lo que antepasados, marcarlo ancestro (suponiendo que esto es normal, no de combinación de cometer) usando

    $ git branch cleanup f020285b^ 
    
  2. En segundo lugar, retire el archivo de la historia que comienza con cleanup (es decir f020285b^) usando git-filter-branch, como se muestra en la sección "Ejemplos" de git-filter-branch página de manual:

    $ git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' cleanup 
    

    Si desea eliminar también todos los envíos que se había cambiado sólo para archivo eliminado también puede usar --prune-empty opción para git-filter-branch.

  3. A continuación, una parte de la historia reescrita con el resto de la historia usando el mecanismo de injertos:

    $ echo $(git-rev-parse f020285b) $(git rev-parse cleanup) >> .git/info/grafts 
    

    A continuación, se puede examinar histry para comprobar si se une correctamente.

  4. pasado, hacer injertos permanente (esto haría que todos los injertos permanente, pero supongamos que aquí no se utiliza injertos de otra manera) usando git-filter-branch,

    $ git filter-branch cleanup..HEAD 
    

    y eliminar los injertos (como se que no se necesitan más), y la rama cleanup

    $ rm .git/info/grafts 
    $ git branch -d cleanup 
    

nota final: si se quita parte de la historia de algún archivo, es mejor asegurarse de que este proyecto sin archivo tiene sentido (y, por ejemplo, compila correctamente).

+0

interesante. intentará. – neoneye

+0

Sí, el mecanismo de los injertos parece ser la forma prevista de hacerlo. Gracias por informarme de esto. Lamentablemente, no tengo tiempo para experimentarlo hoy. – neoneye

+0

El método de injertos debería funcionar en algunos casos, pero eliminará el historial de todos los archivos. En este caso, neoneye solo quiere eliminar el historial de * algunos * archivos. Entonces no estoy seguro de que los injertos sean una solución adecuada. Y el clon superficial está fuera de discusión porque los repositorios poco profundos están lisiados (ver los documentos de git-clone para una descripción de sus limitaciones). –

3

Es posible que desee considerar el uso de git submodules. De esta forma, puede conservar las imágenes y otros archivos grandes en otro repositorio git, y el repositorio que tiene los códigos fuente puede referirse a una revisión particular de ese otro repositorio.

Esto le ayudará a mantener sincronizadas las revisiones del repositorio, ya que el repositorio principal contiene un enlace a una revisión de un repositorio en particular. También le permitirá eliminar/volver a establecer las viejas revisiones en el repositorio secundario, sin afectar el repositorio principal donde está su código fuente - las eliminaciones de revisiones anteriores en un repositorio secundario no arruinarán el historial del repositorio principal, porque usted acaba de actualizar a qué revisión apunta el enlace del repositorio secundario en el repositorio principal.

+0

buen punto. No sabía sobre los submódulos de Git. – neoneye

Cuestiones relacionadas