2010-02-12 14 views
16

aquí está el problema:¿Es posible mantener un archivo sin versión en un repositorio git

creé repositorio git desnuda en mi casa socio de hosting, que utilizo como repositorio de referencia de todas las ubicaciones/ordenadores mantengo mi proyecto desde.

Lo que pasa es que mi proyecto está usando un archivo sqlite db, que sigue creciendo regularmente (es de unos 150MB por ahora). Como pasa el tiempo, mi carpeta .git es cada vez más grande (últimamente alrededor de 1GB). Y mi espacio de alojamiento es limitado.

Necesito que el repositorio desnudo contenga la versión HEAD de este archivo db, pero realmente no necesito mantener su historial de versiones.

Por lo tanto, para ganar algo de espacio, de vez en cuando, elimino el archivo db del historial, limpio el repositorio y vuelvo a crear la versión vacía. Esto funciona, pero es bastante doloroso.

¿Hay alguna manera de decirle a git que guarde solo la última versión de un archivo y elimine su historial?

+1

pregunta relacionada: http://stackoverflow.com/questions/540535/managing-large-binary-files-with-git – jfs

+0

esto puede no ser una solución directa, pero ¿por qué no mantener el archivo de base de datos sin seguimiento y hacer un script que sincroniza tu archivo con el archivo en el repositorio principal? –

+0

¿Por qué necesita este archivo db para guardar una copia del esquema o los datos? ¿O ambos? –

Respuesta

5

Respuesta corta: no.

Respuesta más útil: Git no rastrea los archivos individualmente, por lo que pedirle que descarte el historial de un solo archivo significaría que tendría que reescribir todo su historial completamente en cada confirmación, y eso lleva a todos tipos de problemas feos.

Puede almacenar un archivo en una etiqueta anotada, pero eso no es muy conveniente. Básicamente, es la siguiente:

ID=`git hash-object -w yourfile.sqlite` 
git tag -a -m "Tag database file" mytag $ID 

de ninguna manera que convenientemente actualizar (o incluso crear) el archivo de base de datos en el árbol de trabajo para usted ... que tendría que utilizar scripts gancho para emular eso.

Descripción completa: No estoy del todo seguro de si es realmente posible presionar blobs etiquetados que no están cubiertos por el historial normal. Sospecho que no es así, en cuyo caso esta receta sería mucho menos que útil.

3

Siempre se puede usar el archivo de configuración .gitignore para esto - desde el principio.

Y ... (de this thread: felicitaciones por Björn Steinbrink)

Uso filtro de la rama a la caída de los padres en el primer comprometerse desea mantener, y luego dejar caer la vieja costra.

Digamos $drop es el hash de la última confirmación que desea soltar. Para mantener las cosas en su sano juicio y simple, asegúrese de el primer compromiso que desea mantener, es decir. el hijo de $drop, no es una fusión commit. A continuación, puede utilizar:

git filter-branch --parent-filter "sed -e 's/-p $drop//'" \ 
    --tag-name-filter cat -- \ 
    --all ^$drop 

Lo anterior vuelve a escribir los padres de todos los se compromete a que vienen "después de" $drop.

Revise los resultados con gitk.

Luego, para limpiar todo el viejo cruft.

En primer lugar, las referencias de copia de seguridad de filter-branch:

git for-each-ref --format='%(refname)'refs/original | \ 
    while read ref 
    do 
      git update-ref -d "$ref" 
    done 

luego limpiar sus reflogs:

git reflog expire --expire=0 --all 

Y, por último, vuelva a embalar y soltar todos los viejos objetos inalcanzables: git RePack -ad git prune # Para objetos que repack -ad podría haber quedado alrededor de

En ese momento, cada Lo que conduce a e incluyendo $ drop debe ser ido.

+0

Estoy buscando una solución que * conserve * una copia de la base de datos en el repositorio –

+0

Luego puede crear una secuencia de comandos que elimine el historial después de cada confirmación. –

4

Parece que está buscando la solución al problema equivocado.

Los archivos binarios grandes a menudo necesitan almacenarse en repositorios, pero no creo que una base de datos SQLite sea algo que realmente necesite almacenar en su forma binaria en un repositorio.

Más bien, debe mantener el esquema en control de versión, y si también necesita conservar los datos, serialícelo (a XML, JSON, YAML ...) y también a la versión. Un script de compilación puede crear la base de datos y deserializar los datos cuando sea necesario.

Debido a que Git puede realizar un seguimiento eficiente de un formato de serialización basado en texto, no tendrá que preocuparse por el espacio que le queda de mantener las versiones anteriores, incluso si no cree que necesita acceder a ellas.

+0

hacerlo permitiría a git aplicar sus técnicas habituales de compresión y difuminación haciendo que esto sea mucho menos doloroso. Lo único que se debe cuidar sería crear un formato de serialización correctamente ordenado que minimice el tamaño de la diferencia. –

+0

No estoy de acuerdo. Si miras el formato de slite, no es ese binario. Git es perfectamente capaz de generar algunos diffs utilizables con él. El único beneficio sería que las diferencias serían más fáciles de leer en caso de conflicto. Tener que manejar una capa de serialización de texto es demasiado trabajo si me preguntas –

+0

Esta es una buena idea ... ¿Existe un script favorito que tengas para hacer una serialización basada en texto? – AlexMA

0

Si entiendo su pregunta, creo que tengo una solución simple.

  1. primera copia de seguridad del archivo en alguna parte,
  2. eliminarla de la dir/árbol de trabajo. No es así, solo rm.
  3. Hacer una confirmación.
  4. Asegúrate de que el archivo se haya agregado a .gitignore.

En confirmaciones posteriores, GIT ya no intentará agregar ese archivo. Tenga en cuenta que aún tendrá el archivo almacenado en confirmaciones anteriores. Es solo que no lo agregarás a cada compromiso que hagas en el futuro. Para eliminarlo de confirmaciones anteriores, necesitarás el consejo de alguien con más experiencia de GIT que yo.

0

Agregue sqlite.db a su .gitignore.

Para el registro de entrada en el PP actual de (potencial) empujando con la rama actual:

branch="$(sed 's,.*refs/heads/,,' "$(git rev-parse --git-dir)"/HEAD)" 
objectname=$(git hash_object -w "$(git rev-parse --show-toplevel)/sqlite.db") 
git tag -f db_heads/$branch $objectname 

al empujar una rama:

git push origin $branch +db_heads/$branch 

Cuando ir a buscar una rama:

git fetch origin $branch tags/db_heads/$branch:tags/db_heads/$branch 

al retirar una sucursal:

git checkout $branch 
git cat-file -p db_heads/$branch >"$(git rev-parse --show_toplevel)/sqlite.db" 

Y eso debería hacerlo, creo.

Cuestiones relacionadas