large - Gestionando grandes archivos binarios con Git.
git for files (11)
Estoy buscando opiniones sobre cómo manejar grandes archivos binarios de los que depende mi código fuente (aplicación web). Actualmente estamos discutiendo varias alternativas:
- Copia los archivos binarios a mano.
- Pro: No estoy seguro.
- Contra: Estoy totalmente en contra de esto, ya que aumenta la probabilidad de errores al configurar un nuevo sitio / migrar el anterior. Construye otro obstáculo para tomar.
- Manejalos todos con Git .
- Pro: elimina la posibilidad de ''olvidar'' para copiar un archivo importante
- Contra: Infla el repositorio y disminuye la flexibilidad para administrar el código base y los registros, clones, etc. Tomará bastante tiempo.
- Repositorios separados.
- Pro: la verificación / clonación del código fuente es más rápida que nunca, y las imágenes se archivan correctamente en su propio repositorio.
- Contra: Elimina la simplicidad de tener el único y único repositorio Git en el proyecto. Seguramente introduce algunas otras cosas que no he pensado.
¿Cuáles son sus experiencias / pensamientos con respecto a esto?
Además: ¿Alguien tiene experiencia con varios repositorios Git y los administra en un proyecto?
Los archivos son imágenes para un programa que genera archivos PDF con esos archivos. Los archivos no cambiarán muy a menudo (como en años), pero son muy relevantes para un programa. El programa no funcionará sin los archivos.
Estoy buscando opiniones sobre cómo manejar grandes archivos binarios de los que depende mi código fuente (aplicación web). ¿Cuáles son sus experiencias / pensamientos con respecto a esto?
Personalmente, me he topado con fallas de sincronización con Git con algunos de mis hosts en la nube una vez que mis aplicaciones web han obtenido datos binarios sobre la marca de 3 GB . Consideré BFT Repo Cleaner en ese momento, pero me sentí como un hack. Desde entonces, empecé a mantener los archivos fuera del ámbito de Git, en lugar de eso, aproveché herramientas diseñadas específicamente como Amazon S3 para administrar archivos, versiones y copias de seguridad.
¿Alguien tiene experiencia con múltiples repositorios Git y la gestión de ellos en un proyecto?
Sí. Los temas de Hugo se manejan principalmente de esta manera. Es un poco torpe, pero hace el trabajo.
Mi sugerencia es elegir la herramienta adecuada para el trabajo . Si es para una empresa y usted está administrando su línea de código en GitHub, pague el dinero y use Git-LFS. De lo contrario, podría explorar más opciones creativas, como el almacenamiento de archivos cifrado y descentralizado utilizando blockchain .
Las opciones adicionales a considerar incluyen Minio y s3cmd .
Descubrí git-annex recientemente que me parece increíble. Fue diseñado para gestionar archivos grandes de manera eficiente. Lo uso para mis colecciones de fotos / música (etc.). El desarrollo de git-annex es muy activo. El contenido de los archivos se puede eliminar del repositorio de Git, solo Git rastrea la jerarquía de árbol (a través de enlaces simbólicos). Sin embargo, para obtener el contenido del archivo, es necesario un segundo paso después de tirar / empujar, por ejemplo:
$ git annex add mybigfile
$ git commit -m''add mybigfile''
$ git push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile
Hay muchos comandos disponibles, y hay una gran documentación en el sitio web. Un paquete está disponible en Debian .
Echa un vistazo a camlistore . No está realmente basado en Git, pero me parece más apropiado para lo que tienes que hacer.
Eche un vistazo a git bup, que es una extensión de Git para almacenar de forma inteligente grandes binarios en un repositorio de Git.
Usted querría tenerlo como un submódulo, pero no tendrá que preocuparse por que el repositorio sea difícil de manejar. Uno de sus casos de uso de muestra es el almacenamiento de imágenes de máquinas virtuales en Git.
Realmente no he visto mejores tasas de compresión, pero mis repositorios no tienen archivos binarios realmente grandes en ellos.
Su experiencia puede ser diferente.
En mi opinión, si es probable que modifiques esos archivos grandes con frecuencia, o si pretendes hacer muchos git clone
de git clone
o git checkout
, deberías considerar seriamente usar otro repositorio de Git (o tal vez otra forma de acceder a esos archivos) .
Pero si trabaja como nosotros, y si sus archivos binarios no se modifican a menudo, entonces el primer clon / checkout será largo, pero luego debería ser tan rápido como lo desee (considerando que sus usuarios siguen utilizando el primer repositorio clonado). tenía).
La solución que me gustaría proponer se basa en ramas huérfanas y un ligero abuso del mecanismo de etiquetas, a partir de ahora referido como * Etiquetas huérfanas de almacenamiento binario (OTABS)
TL; DR 12-01-2017 Si puede usar el LFS de github o algún otro tercero, por supuesto que debería. Si no puedes, sigue leyendo. Tenga cuidado, esta solución es un hack y debe tratarse como tal.
Propiedades deseables de OTABS
- es una solución pura de git y git solo - hace el trabajo sin ningún software de terceros (como git-annex) o infraestructura de terceros (como el LFS de github).
- almacena los archivos binarios de manera eficiente , es decir, no infla el historial de su repositorio.
-
git pull
ygit fetch
, incluyendogit fetch --all
son eficientes en ancho de banda , es decir, no todos los binarios grandes se extraen del control remoto de forma predeterminada. - funciona en Windows .
- almacena todo en un solo repositorio git .
- permite la eliminación de archivos binarios desactualizados (a diferencia de bup).
Propiedades indeseables de OTABS
- hace que
git clone
potencialmente ineficiente (pero no necesariamente, dependiendo de su uso). Si implementa esta solución, es posible quegit clone -b master --single-branch <url>
recomendar a sus colegas que usengit clone -b master --single-branch <url>
lugar degit clone
. Esto se debe a que, por defecto, git clone clona todo el repositorio, incluidas las cosas en las que normalmente no desearía desperdiciar su ancho de banda, como las confirmaciones no referenciadas. Tomado de SO 4811434 . - hace que
git fetch <remote> --tags
ancho de banda ineficiente, pero no necesariamente ineficiente de almacenamiento. Siempre puedes aconsejar a tus colegas que no lo usen. - Tendrás que usar periódicamente un truco de
git gc
para limpiar tu repositorio de cualquier archivo que ya no quieras. - no es tan eficiente como bup o git-bigfiles . Pero, respectivamente, es más adecuado para lo que estás tratando de hacer y más disponible. Es probable que tenga problemas con cientos de miles de archivos pequeños o con archivos dentro del rango de gigabytes, pero siga leyendo para encontrar soluciones.
Añadiendo los archivos binarios
Antes de comenzar, asegúrese de haber confirmado todos sus cambios, su árbol de trabajo está actualizado y su índice no contiene cambios no confirmados. Podría ser una buena idea llevar todas las sucursales locales a su control remoto (github, etc.) en caso de que ocurra un desastre.
- Crea una nueva rama huérfana.
git checkout --orphan binaryStuff
hará el truco. Esto produce una rama que está completamente desconectada de cualquier otra rama, y la primera confirmación que realizará en esta rama no tendrá padre, lo que la convertirá en una confirmación raíz. - Limpie su índice usando
git rm --cached * .gitignore
. - Respire hondo y elimine todo el árbol de trabajo utilizando
rm -fr * .gitignore
. El directorio.git
interno permanecerá intacto, porque el comodín*
no coincide. - Copie en su VeryBigBinary.exe, o en su VeryHeavyDirectory /.
- Añádelo y preséntalo.
- Ahora se vuelve complicado: si lo empujas en el control remoto como una rama, todos los desarrolladores lo descargarán la próxima vez que invocen
git fetch
obstruyendo su conexión. Puedes evitar esto presionando una etiqueta en lugar de una rama. Esto todavía puede afectar el ancho de banda y el almacenamiento del sistema de archivos de su colega si tienen la costumbre de escribirgit fetch <remote> --tags
, perogit fetch <remote> --tags
leyendo para encontrar una solución. Adelante ygit tag 1.0.0bin
- Empuje su etiqueta huérfana
git push <remote> 1.0.0bin
. - Para que nunca empuje su rama binaria por accidente, puede eliminarla
git branch -D binaryStuff
. Su confirmación no se marcará para la recolección de basura, porque una etiqueta huérfana que apunta a ella1.0.0bin
es suficiente para mantenerla con vida.
Revisando el archivo binario
- ¿Cómo puedo (o mis colegas) obtener el VeryBigBinary.exe verificado en el árbol de trabajo actual? Si su rama de trabajo actual es, por ejemplo, maestro, puede simplemente obtener
git checkout 1.0.0bin -- VeryBigBinary.exe
. - Esto fallará si no tienes la etiqueta huérfana
1.0.0bin
descargada, en cuyo caso tendrás quegit fetch <remote> 1.0.0bin
agit fetch <remote> 1.0.0bin
antemano. - Puede agregar el
VeryBigBinary.exe
en elVeryBigBinary.exe
su maestro, para que nadie en su equipo contamine la historia principal del proyecto con el binario por accidente.
Eliminar completamente el archivo binario
Si decide purgar completamente VeryBigBinary.exe de su repositorio local, su repositorio remoto y los repositorios de sus colegas, simplemente puede:
- Elimine la etiqueta huérfana en el
git push <remote> :refs/tags/1.0.0bin
- Eliminar la etiqueta huérfana localmente (elimina todas las demás etiquetas no referenciadas) etiqueta
git tag -l | xargs git tag -d && git fetch --tags
git tag -l | xargs git tag -d && git fetch --tags
. Tomado de SO 1841341 con ligera modificación. - Use un truco de git gc para eliminar su confirmación ahora sin referencia localmente.
git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"
. También eliminará todas las demás confirmaciones sin referencia. Tomado de SO 1904860 - Si es posible, repita el truco de git gc en el control remoto. Es posible si está alojando automáticamente su repositorio y es posible que no sea posible con algunos proveedores de git, como github o en algunos entornos corporativos. Si está hospedando con un proveedor que no le da acceso ssh al control remoto, simplemente déjelo. Es posible que la infraestructura de su proveedor limpie su compromiso no referenciado en su propio momento. Si se encuentra en un entorno corporativo, puede recomendar a su TI que ejecute una basura de trabajo cron que recolecta su control remoto una vez por semana aproximadamente. Si lo hacen o no, no tendrán ningún impacto en su equipo en términos de ancho de banda y almacenamiento, siempre y cuando recomiende a sus colegas que siempre
git clone -b master --single-branch <url>
lugar degit clone
. - Todos los colegas que desean deshacerse de las etiquetas huérfanas obsoletas solo deben aplicar los pasos 2-3.
- Luego puede repetir los pasos 1-8 de Agregar los archivos binarios para crear una nueva etiqueta huérfana
2.0.0bin
. Si te preocupa que tus colegasgit fetch <remote> --tags
, puedes nombrarlo de nuevo1.0.0bin
. Esto asegurará que la próxima vez que obtengan todas las etiquetas, la antigua1.0.0bin
no se referenciará y se marcará para la recolección de basura posterior (usando el paso 3). Cuando intenta sobrescribir una etiqueta en el control remoto, tiene que usar-f
así:git push -f <remote> <tagname>
Epílogo
OTABS no toca su maestro ni ningún otro código fuente / ramas de desarrollo. Los hashes de confirmación, todo el historial y el pequeño tamaño de estas ramas no se ven afectados. Si ya ha hinchado su historial de código fuente con archivos binarios, tendrá que limpiarlo como un trabajo separado. Este script puede ser útil.
Confirmado para trabajar en Windows con git-bash.
Es una buena idea aplicar un conjunto de trics estándar para hacer que el almacenamiento de archivos binarios sea más eficiente. La ejecución frecuente de
git gc
(sin ningún argumento adicional) hace que git optimice el almacenamiento subyacente de sus archivos utilizando deltas binarios. Sin embargo, si es poco probable que sus archivos se mantengan similares desde el compromiso hasta el compromiso, puede desactivar por completo los deltas binarios. Además, como no tiene sentido comprimir archivos ya comprimidos o encriptados, como .zip, .jpg o .crypt, git le permite desactivar la compresión del almacenamiento subyacente. Desafortunadamente, es una configuración de todo o nada que también afecta a su código fuente.Es posible que desee crear secuencias de comandos de OTABS para permitir un uso más rápido. En particular, las secuencias de comandos de los pasos 2 y 3 de Eliminación completa de archivos binarios en un gancho de
update
git podrían dar una semántica convincente, pero quizás peligrosa, a git fetch ("buscar y eliminar todo lo que está desactualizado").Es posible que desee omitir el paso 4 de Eliminación completa de archivos binarios para mantener un historial completo de todos los cambios binarios en el control remoto al costo de la expansión del repositorio central. Los repositorios locales se mantendrán magros con el tiempo.
En el mundo Java, es posible combinar esta solución con
maven --offline
para crear una compilación sin conexión reproducible almacenada completamente en su control de versión (es más fácil con maven que con gradle). En el mundo de Golang es posible desarrollar esta solución para administrar su GOPATH en lugar dego get
. En el mundo de Python, es posible combinar esto con virtualenv para producir un entorno de desarrollo autónomo sin depender de los servidores PyPi para cada compilación desde cero.Si sus archivos binarios cambian muy a menudo, como artefactos de compilación, puede ser una buena idea escribir una solución que almacene las 5 versiones más recientes de los artefactos en las etiquetas huérfanas
monday_bin
,tuesday_bin
, ...,friday_bin
, y también una etiqueta huérfana para cada versión1.7.8bin
2.0.0bin
, etc. Puede rotar elweekday_bin
y eliminar los binarios antiguos diariamente. De esta manera obtendrá lo mejor de dos mundos: conservará todo el historial de su código fuente, pero solo el historial relevante de sus dependencias binarias. También es muy fácil obtener los archivos binarios para una etiqueta determinada sin obtener el código fuente completo con todo su historial:git init && git remote add <name> <url> && git fetch <name> <tag>
debería hacerlo por usted .
Otra solución, desde abril de 2015 es Git Large File Storage (LFS) (por GitHub).
Utiliza git-lfs (ver git-lfs.github.com ) y probado con un servidor que lo soporta: lfs-test-server :
Puede almacenar metadatos solo en el repositorio de git, y el archivo grande en otro lugar.
SVN parece manejar los deltas binarios más eficientemente que Git.
Tuve que decidir sobre un sistema de versiones para la documentación (archivos JPEG, archivos PDF y archivos .odt). Acabo de probar agregar un archivo JPEG y rotarlo 90 grados cuatro veces (para comprobar la efectividad de los deltas binarios). El repositorio de Git creció un 400%. El repositorio de SVN creció solo un 11%.
Así que parece que SVN es mucho más eficiente con archivos binarios.
Así que mi elección es Git para el código fuente y SVN para archivos binarios como documentación.
Si el programa no funciona sin los archivos, parece que dividirlos en un repositorio separado es una mala idea. Tenemos grandes suites de prueba que dividimos en un repositorio separado, pero esos son archivos verdaderamente "auxiliares".
Sin embargo, es posible que pueda administrar los archivos en un repositorio por separado y luego usar git-submodule
para incluirlos en su proyecto de una manera sana. Entonces, todavía tendrías el historial completo de todas tus fuentes pero, según tengo entendido, solo tendrías la única revisión relevante de tu submódulo de imágenes. La función git-submodule
debería ayudarlo a mantener la versión correcta del código en línea con la versión correcta de las imágenes.
Aquí hay una buena introducción a los submódulos de Git Book.
También puedes usar git-fat . Me gusta que solo depende del stock de Python y rsync
. También admite el flujo de trabajo habitual de Git, con los siguientes comandos autoexplicativos:
git fat init
git fat push
git fat pull
Además, debe registrar un archivo .gitfat en su repositorio y modificar sus atributos .gitat para especificar las extensiones de archivo que desea que git fat
administre.
Agregue un binario utilizando el git add
normal, que a su vez invoca a git fat
según sus reglas de atributos de gitat.
Finalmente, tiene la ventaja de que la ubicación donde realmente se almacenan los binarios se puede compartir entre los repositorios y los usuarios, y es compatible con todo lo que hace rsync
.
ACTUALIZACIÓN: No use git-fat si está usando un puente Git-SVN. Terminará eliminando los archivos binarios de su repositorio de Subversion. Sin embargo, si está utilizando un repositorio de Git puro, funciona a la perfección.
Yo usaría submódulos (como Pat Notz) o dos repositorios distintos. Si modificas tus archivos binarios con demasiada frecuencia, entonces intentaría minimizar el impacto del enorme repositorio que limpia el historial:
Hace varios meses tuve un problema muy similar: ~ 21 GB de archivos MP3, sin clasificar (nombres incorrectos, id3 incorrectos, no sé si me gusta ese archivo MP3 o no ...), y replicado en tres computadoras.
Usé una unidad de disco duro externa con el repositorio principal de Git, y la cloné en cada computadora. Luego, comencé a clasificarlos de la manera habitual (empujar, jalar, fusionar ... eliminar y renombrar muchas veces).
Al final, solo tenía ~ 6 GB de archivos MP3 y ~ 83 GB en el directorio .git. git-write-tree
y git-commit-tree
para crear un nuevo commit, sin ancestros de commit, y comencé una nueva rama apuntando a ese commit. El "registro de git" para esa rama solo mostraba una confirmación.
Luego, eliminé la rama anterior, mantuve solo la nueva rama, eliminé los registros de ref y ejecuté "git prune": después de eso, mis carpetas .git pesaron solo ~ 6 GB ...
Podrías "purgar" el enorme depósito de vez en cuando de la misma manera: tu "clon de git" será más rápido.