¿Cuál es el mecanismo de almacenamiento detrás de Git Large File Storage?

Github recientemente introdujo una extensión a git para almacenar files grandes de una manera diferente. ¿Qué significan exactamente por extensión los files grandes reemplazados por pointers de text dentro de Git ?

Puede ver en las fonts de git-lfs cómo se define un "puntero de text" :

 type Pointer struct { Version string Oid string Size int64 OidType string } 

La mancha y las fonts limpias significan que git-lfs puede usar un controller de filter de contenido para:

  • descarga los files reales en el pago
  • almacenarlos en su fuente externa en commit.

Ver las especificaciones del puntero :

La idea central de GIT LFS es que en lugar de escribir grandes blobs en un repository de Git, solo se escribe un file de puntero .

 version https://git-lfs.github.com/spec/v1 oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 (ending \n) 

Git LFS necesita un punto final de URL para hablar con un server remoto.
Un repository Git puede tener diferentes extremos GIT LFS para diferentes controles remotos.

El file real se carga o descarga de un server que respeta la API de GIT-LFS .

Esto es confirmado por la página man de git-lfs , que menciona:

El file real se envía a una API de GIT LFS

Necesita un server Git que implemente esa API para admitir la carga y descarga de contenido binary.


Con respecto al controller de filter de contenido (que existe en Git durante mucho time, mucho antes de lfs, y aquí lo utiliza lfs para agregar esta característica de "administración de files grandes"), aquí es donde sucede la mayor parte del trabajo:

El filter de borrones se ejecuta mientras los files se guardan desde el repository de Git hasta el directory de trabajo.
Git envía el contenido del blob de Git como STDIN y espera que el contenido escriba en el directory de trabajo como STDOUT.

Lee 100 bytes.

  • Si el contenido es ASCII y coincide con el formatting del file de puntero:
    Busque el file en .git / lfs / objects / {OID}.

  • Si no está allí, descárguelo del server.
    Lea sus contenidos a STDOUT

  • De lo contrario, simplemente pase el STDIN a través de STDOUT.

El filter limpio se ejecuta cuando los files se agregan a los repositorys.
Git envía el contenido del file que se agrega como STDIN y espera que el contenido escriba en Git como STDOUT.

  • Transmita contenido binary desde STDIN a un file temporal, mientras calcula su firma SHA-256.
  • Verifique el file en .git/lfs/objects/{OID} .
  • Si no existe:
    • Ponga en queue el OID que se cargará.
    • Mueva el file temporal a .git/lfs/objects/{OID} .
  • Eliminar el file temporal.
  • Escriba el file del puntero en STDOUT.

Git 2.11 (noviembre de 2016) tiene un compromiso que detalla aún más cómo funciona esto: cometer edcc858 , ayudado por Martin-Louis Bright y firmado por: Lars Schneider.

convert : agregar filter.<driver>.process option

El mecanismo de borrado / borrado de Git invoca un process de filter externo para cada burbuja que se ve afectada por un filter. Si Git filtra un montón de blobs, el time de inicio de los processs de filter externo puede convertirse en una parte importante del time total de ejecución de Git.

En una testing de performance preliminar, este desarrollador usó un filter de borrado / borrado escrito en golang para filtrar 12,000 files. Este process tomó 364 segundos con el mecanismo de filter existente y 5 segundos con el nuevo mecanismo. Vea los detalles aquí: git-lfs / git-lfs # 1382

Este parche agrega la opción de filter.<driver>.process string que, si se usa, mantiene el process de filter externo en ejecución y procesa todos los blobs con el protocolo basado en formatting de package ( pkt-line ) sobre la input estándar y salida estándar .
El protocolo completo se explica en detalle en Documentation/gitattributes.txt .

Algunas decisiones key:

  • El process de filter de larga ejecución se denomina protocolo de filter versión 2 porque la invocación de filter de disparo único existente se considera versión 1.
  • Git envía un post de bienvenida y espera una respuesta justo después de que el process de filter externo haya comenzado. Esto asegura que Git no se bloqueará si un filter de la versión 1 se usa incorrectamente con el filter.<driver>.process opción para filters de la versión 2. Además, Git puede detectar este tipo de error y advertir al usuario.
  • El estado de una operación de filter (por ejemplo, "éxito" o "error") se establece antes de la respuesta real y (si es necesario) se restablece después de la respuesta. La ventaja de esta respuesta de estado de dos pasos es que si el filter detecta un error temprano, entonces el filter puede comunicar esto y Git ni siquiera necesita crear estructuras para leer la respuesta.
  • Todas las respuestas de estado son lists de líneas pkt terminadas con un package de descarga. Esto nos permite enviar otros campos de estado con el mismo protocolo en el futuro.

Esto tiene como consecuencia una advertencia establecida en Git 2.12 (Q1 2017)

Consulte la statement 7eeda8b (18 de diciembre de 2016) y c6b0831 (03 de diciembre de 2016) por Lars Schneider ( larsxschneider ) .
(Fusionada por Junio ​​C Hamano – gitster – in commit 08721a0 , 27 de diciembre de 2016)

docs : advertir sobre posibles ' = ' en valores de process de filter de limpieza / borrado

Un valor de nombre de ruta en un par " key=value " del process de limpieza / borrado puede contener el carácter ' = ' (introducido en edcc858 ).
Haga que el usuario tenga conocimiento de este problema en los documentos, agregue un caso de testing correspondiente y solucione el problema en el analizador del valor del process de filtrado de la implementación de ejemplo en contrib .