Что такое идентификатор коммита Git?

Как генерируются идентификаторы коммитов Git для уникальной идентификации коммитов?

Пример: 521747298a3790fde1710f3aa2d03b55020575aa

Как это работает? Они уникальны только для каждого проекта? Или для репозиториев Git по всему миру?


person Ankur Loriya    schedule 17.03.2015    source источник
comment
См. git-scm.com/book /ru/v2/   -  person jub0bs    schedule 17.03.2015


Ответы (2)


Идентификатор коммита Git — это хэш SHA-1 каждой важной вещи. о фиксации. Я не буду перечислять их все, но вот самые важные...

  • Контент, все это, а не только diff.
  • Дата совершения.
  • Имя и адрес электронной почты комитента.
  • Сообщение журнала.
  • ID предыдущих коммитов.

Измените что-либо из этого, и идентификатор фиксации изменится. И да, один и тот же коммит с теми же свойствами будет иметь тот же идентификатор на другом компьютере. Это служит трем целям. Во-первых, это означает, что система может определить, была ли подделана фиксация. Это встроено прямо в архитектуру.

Во-вторых, можно быстро сравнить коммиты, просто взглянув на их идентификаторы. Это делает сетевые протоколы 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, другое сообщение коммита).

person Schwern    schedule 17.03.2015
comment
ID последних коммитов. Git похож на цепочку блоков.???? - person g10guang; 04.11.2018
comment
Мне нравится это графическое объяснение, и идеальной второй его частью является ответ @JustinHoward, ниже которого показаны точные шаги для воспроизведения хэша, так что теперь вы знаете все, цель и детали! - person Eureka; 07.08.2019

Вы можете точно увидеть, что входит в создание идентификатора коммита, запустив

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

Это дает вам:

  1. Контрольная сумма содержимого дерева
  2. Идентификатор родительского коммита (если это слияние, родителей будет больше)
  3. Автор коммита с отметкой времени
  4. Коммиттер коммита с меткой времени
  5. Сообщение фиксации

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.

Как видите, в этой информации нет ничего, что идентифицировало бы проект или репозиторий. Причина, по которой это не вызывает проблем, заключается в том, что совпадение двух разных хэшей коммитов астрономически маловероятно.

person Justin Howard    schedule 17.03.2015
comment
Это очень хорошо дополняет выбранный ответ, я проверил его, сценарий оболочки действительно работает, я думаю, это скопировано из реального кода, верно? - person Jean Vincent; 11.06.2017
comment
@JeanVincent: это не совсем из кода. Я предполагаю, что это написано на C. Но он точно воспроизводит алгоритм (на данный момент, но участники работают над заменой SHA1). - person Justin Howard; 12.06.2017