Как генерируются идентификаторы коммитов Git для уникальной идентификации коммитов?
Пример: 521747298a3790fde1710f3aa2d03b55020575aa
Как это работает? Они уникальны только для каждого проекта? Или для репозиториев Git по всему миру?
Как генерируются идентификаторы коммитов Git для уникальной идентификации коммитов?
Пример: 521747298a3790fde1710f3aa2d03b55020575aa
Как это работает? Они уникальны только для каждого проекта? Или для репозиториев Git по всему миру?
Идентификатор коммита Git — это хэш SHA-1 каждой важной вещи. о фиксации. Я не буду перечислять их все, но вот самые важные...
Измените что-либо из этого, и идентификатор фиксации изменится. И да, один и тот же коммит с теми же свойствами будет иметь тот же идентификатор на другом компьютере. Это служит трем целям. Во-первых, это означает, что система может определить, была ли подделана фиксация. Это встроено прямо в архитектуру.
Во-вторых, можно быстро сравнить коммиты, просто взглянув на их идентификаторы. Это делает сетевые протоколы Git очень эффективными. Хотите сравнить два коммита, чтобы увидеть, одинаковы ли они? Не нужно отправлять весь diff, просто отправьте идентификаторы.
В-третьих, и это гениально, два коммита с одинаковыми идентификаторами имеют одинаковую историю. Вот почему идентификатор предыдущих коммитов является частью хэша. Если содержимое фиксации такое же, но родители разные, идентификатор фиксации должен быть другим. Это означает, что при сравнении репозиториев (например, при отправке или извлечении), как только Git находит общую фиксацию между двумя репозиториями, он может прекратить проверку. Это делает толчки и тяги чрезвычайно эффективными. Например...
origin
A - B - C - D - E [master]
A - B [origin/master]
Сетевой разговор для git fetch origin
выглядит примерно так...
local
Эй, ориджин, какие у тебя есть ветки?origin
У меня есть мастер в E.local
У меня нет E, у меня есть ваш мастер на B.origin
В вы говорите? У меня есть B, и это предок E. Это подтверждается. Позвольте мне отправить вам C, D и E.Вот почему, когда вы переписываете коммит с помощью rebase, все после него должно измениться. Вот пример.
A - B - C - D - E - F - G [master]
Допустим, вы переписываете D, просто чтобы немного изменить сообщение журнала. Теперь D больше не может быть D, его нужно скопировать в новый коммит, который мы назовем D1.
A - B - C - D - E - F - G [master]
\
D1
В то время как D1 может иметь C в качестве своего родителя (C не затрагивается, коммиты не знают своих дочерних элементов), он отключен от E, F и G. Если мы изменим родителя E на D1, E больше не может быть E. Его нужно скопировать в новый коммит E1.
A - B - C - D - E - F - G [master]
\
D1 - E1
И так далее от F до F1 и от G до G1.
A - B - C - D - E - F - G
\
D1 - E1 - F1 - G1 [master]
Все они имеют один и тот же код, просто разные родители (или, в случае с D1, другое сообщение коммита).
Вы можете точно увидеть, что входит в создание идентификатора коммита, запустив
git cat-file commit HEAD
Это даст вам что-то вроде
tree 07e239f2f3d8adc12566eaf66e0ad670f36202b5
parent 543a4849f7201da7bed297b279b7b1e9a086a255
author Justin Howard <[email protected]> 1426631449 -0700
committer Justin Howard <[email protected]> 1426631471 -0700
My commit message
Это дает вам:
Git берет все это и делает из него хэш sha1. Вы можете воспроизвести идентификатор фиксации, запустив
(printf "commit %s\0" $(git cat-file commit HEAD | wc -c); git cat-file commit HEAD) | sha1sum
Это начинается с печати строки commit
, за которой следует пробел и количество байтов текстового BLOB-объекта cat-file
. Затем к нему добавляется большой двоичный объект cat-file
, за которым следует нулевой байт. Затем все это проходит через sha1sum
.
Как видите, в этой информации нет ничего, что идентифицировало бы проект или репозиторий. Причина, по которой это не вызывает проблем, заключается в том, что совпадение двух разных хэшей коммитов астрономически маловероятно.