¿Cómo determina Git qué objects deben enviarse entre repositorys?

He buscado aquí pero no pude entender las cosas que me preguntaba: ¿cómo hace git push o git pull descubrir qué objects de compromiso faltan en el otro lado?

Digamos que tenemos un repository con los siguientes commits: (las letras representan los ID de SHA-1, d es refs/heads/master )

 a -> b -> c -> d 

El control remoto, en cambio, tiene estos:

 a -> e -> f -> g 

De acuerdo con el documento de git, el control remoto nos dice que su refs/heads/master está en g , pero dado que no conocemos esa confirmación, eso en realidad no nos dice nada. ¿Cómo es eso suficiente para descubrir los datos faltantes?


En la otra dirección, el documento dice:

En este punto, el process fetch-pack analiza qué objects tiene y responde con los objects que necesita enviando "want" y luego el SHA-1 que desea. Envía todos los objects que ya tiene con "tener" y luego el SHA-1. Al final de esta list, escribe "hecho" para iniciar el process de carga de package para comenzar a enviar el file de package de los datos que necesita:

esto explica cómo el control remoto determinaría qué datos enviar, pero ¿no afectaría esto el performance en repositorys con muchos objects? De lo contrario, ¿qué significa realmente en el text?


Aparentemente, el modo de transferencia de datos es muy diferente dependiendo de la dirección (empuje contra tirón). ¿Qué y cómo se enfrentan los desafíos con esta elección de layout, y cómo puedo entender sus descripciones en el documento?

La magia está en los ID. Un ID de confirmación está compuesto de muchas cosas, pero básicamente es un hash SHA-1 de esto.

  • Contenido (todo, no solo el diff)
  • Autor
  • Fecha
  • Mensaje de logging
  • ID de padres

Cambia cualquiera de estos y necesitas crear un nuevo commit con una nueva ID. Tenga en count que las ID principales están incluidas.

¿Qué significa esto para Git? Significa que si te digo que he cometido "ABC123" y has confirmado "ABC123", sabemos que tenemos el mismo compromiso con el mismo contenido, el mismo autor, la misma date, el mismo post y los mismos padres . Esos padres tienen la misma identificación, por lo que tienen el mismo contenido, el mismo autor, la misma date, el mismo post y los mismos padres . Y así. Si los ID coinciden, deben tener el mismo historial , no es necesario verificar más adelante en la línea. Esta es una de las grandes fortalezas de Git, está profundamente entrelazada en su layout, y no puedes entender a Git sin ella.

Un tirón es una búsqueda más una fusión. git pull origin master es el git fetch origin más el git merge master origin/master (o la base de rebase con --rebase ). Una búsqueda se parece a esto …

 remote @ http://example.com/project.git F - G [bugfix] / A - B - C - D - E - J [master] \ H - I [feature] local origin = http://example.com/project.git F - G [origin/bugfix] / A - B - C - D - E [origin/master] [master] 
  • [local] Hey control remoto, ¿qué twigs tienes?
  • [remote] Tengo corrección de errores en G.
  • [local] ¡También tengo corrección de errores en G! Hecho. ¿Qué más?
  • [remote] Tengo una function en I.
  • [local] No tengo function ni yo. ¿Cuáles son los padres de I?
  • [remoto] Soy padre es H.
  • [local] No tengo H, ¿qué son los padres de H?
  • [remoto] El padre de H es J.
  • [local] No tengo J. ¿Qué son los padres de J?
  • [remoto] El padre de J es E.
  • [local] ¡Tengo E! Envíame J, H y yo por favor.
  • [remoto] Bien, aquí vienen.
  • [local] agrega J, H e I al repository y pone origen / function en I Ok, ¿qué más tienes?
  • [remote] Tengo master en J.
  • [local] Tengo master en E, ya me has enviado J. mueve origen / master a J. ¿Qué más?
  • [remoto] ¡Eso es!
  • [local] Kthxbi

Y ahora local se ve así …

 local origin = http://example.com/project.git F - G [origin/bugfix] / A - B - C - D - E [master] - J [origin/master] \ H - I [origin/feature] 

Luego hará git merge master origin/master para terminar el pull, que avanzará rápidamente a J.

Un empuje es similar, excepto que el process va en reversa (el envío local se compromete con el control remoto) y solo avanzará rápidamente.

Esto es a lo que Pro Git se refiere como "el protocolo tonto" y se usa cuando su control remoto es un server HTTP simple. El protocolo inteligente es el que se usa con más frecuencia, es mucho less hablador y tiene muchas optimizaciones. Pero puedes ver cómo cualquiera de ellos puede ser terriblemente eficiente. No hay necesidad de comunicar toda la historia, solo necesitan enviar keys de hash de 20 bytes hasta que encuentren un ancestro común.

Aquí hay algunas fonts y lecturas adicionales.

  • Pro Git – Protocolos de transferencia de Git
  • ejemplo libgit2 fetch