ver tipos tag remove modificados log etiquetas crear archivos git git-svn uniqueidentifier git-commit

tipos - git ver archivos modificados



¿Qué es un ID de confirmación de Git? (2)

¿Cómo se generan los ID de confirmación de Git para identificar de forma única las confirmaciones?

Ejemplo: 521747298a3790fde1710f3aa2d03b55020575aa

¿Como funciona? ¿Son únicos para cada proyecto? ¿O para los repositorios de Git a nivel mundial?


Puede ver exactamente lo que implica crear un ID de compromiso ejecutando

git cat-file commit HEAD

Te dará algo como

tree 07e239f2f3d8adc12566eaf66e0ad670f36202b5 parent 543a4849f7201da7bed297b279b7b1e9a086a255 author Justin Howard <[email protected]> 1426631449 -0700 committer Justin Howard <[email protected]> 1426631471 -0700 My commit message

Te lo dá:

  1. Una suma de comprobación de los contenidos del árbol.
  2. El ID de confirmación de los padres (si se trata de una combinación, habrá más padres)
  3. El autor del commit con timestamp.
  4. El committer del commit con timestamp.
  5. El mensaje de compromiso

Git toma todo esto y hace un hash de eso. Puede reproducir el ID de confirmación ejecutando

(printf "commit %s/0" $(git cat-file commit HEAD | wc -c); git cat-file commit HEAD) | sha1sum

Esto comienza imprimiendo la commit cadena seguida por un espacio y el recuento de bytes del blob de texto del cat-file . Luego agrega el blob del cat-file al seguido de un byte nulo. Todo eso luego se ejecuta a través de sha1sum .

Como puede ver, no hay nada que identifique el proyecto o el repositorio en esta información. La razón por la que esto no causa problemas es porque es astronómicamente improbable que dos hashes de confirmación diferentes colisionen.


Un ID de confirmación de Git es un hash SHA-1 de cada cosa importante sobre la confirmación. No los voy a enumerar todos, pero aquí están los más importantes ...

  • El contenido, todo, no solo el dif.
  • Fecha de cometer.
  • Nombre del comitente y dirección de correo electrónico.
  • Mensaje de registro
  • El ID de los comités anteriores.

Cambiar cualquiera de eso y los cambios de ID de confirmación. Y sí, la misma confirmación con las mismas propiedades tendrá la misma ID en una máquina diferente. Esto tiene tres propósitos. Primero, significa que el sistema puede saber si un compromiso ha sido manipulado. Está directamente en la arquitectura.

En segundo lugar, uno puede comparar los compromisos rápidamente con solo mirar sus ID. Esto hace que los protocolos de red de Git sean muy eficientes. ¿Quieres comparar dos confirmaciones para ver si son iguales? No es necesario que envíes todo el diff, solo envía las identificaciones.

Tercero, y este es el genio, dos confirmaciones con las mismas ID tienen el mismo historial . Es por eso que la ID de las confirmaciones anteriores son parte del hash. Si el contenido de un compromiso es el mismo pero los padres son diferentes, el ID de compromiso debe ser diferente. Eso significa que cuando se comparan los repositorios (como en un push o pull) una vez que Git encuentra un commit en común entre los dos repositorios, puede dejar de verificar. Esto hace que empujar y tirar sea extremadamente eficiente. Por ejemplo...

origin A - B - C - D - E [master] A - B [origin/master]

La conversación de red para git fetch origin es algo como esto ...

  • Hey local origen, ¿qué ramas tienes?
  • origin tengo maestro en E.
  • local no tengo E, tengo tu maestro en B.
  • origin B que dices? Tengo B y es un antepasado de E. Eso se comprueba. Déjame enviarte C, D y E.

Esta es también la razón por la que cuando reescribes un commit con rebase, todo después de que tenga que cambiar. Aquí hay un ejemplo.

A - B - C - D - E - F - G [master]

Digamos que reescribes D, solo para cambiar un poco el mensaje de registro. Ahora D ya no puede ser D, tiene que ser copiado a una nueva confirmación que llamaremos D1.

A - B - C - D - E - F - G [master] / D1

Mientras que D1 puede tener C como su padre (C no se ve afectado, los compromisos no conocen a sus hijos) está desconectado de E, F y G. Si cambiamos el padre de E a D1, E ya no puede ser E. Tiene que ser copiado a un nuevo commit E1.

A - B - C - D - E - F - G [master] / D1 - E1

Y así sucesivamente con F a F1 y G a G1.

A - B - C - D - E - F - G / D1 - E1 - F1 - G1 [master]

Todos tienen el mismo código, solo padres diferentes (o en el caso de D1, un mensaje de confirmación diferente).