Как git фиксировать идентификаторы, сгенерированные для однозначной идентификации коммитов?
Пример:
521747298a3790fde1710f3aa2d03b55020575aa
Как это работает? Являются ли они уникальными только для каждого проекта? или для хранилищ git глобально?
Как git фиксировать идентификаторы, сгенерированные для однозначной идентификации коммитов?
Пример:
521747298a3790fde1710f3aa2d03b55020575aa
Как это работает? Являются ли они уникальными только для каждого проекта? или для хранилищ git глобально?
A Git идентификатор фиксации - это SHA-1 хеш о каждой важной вещи о фиксации. Я не буду перечислять их всех, но здесь важные...
Измените это и измените идентификатор фиксации. И да, одна и та же фиксация с теми же свойствами будет иметь тот же идентификатор на другой машине. Это служит трем целям. Во-первых, это означает, что система может определить, была ли изменена фиксация. Он испекла прямо в архитектуру.
Во-вторых, можно быстро сравнивать, просто просматривая их идентификаторы. Это делает сетевые протоколы Git очень эффективными. Хотите сравнить две коммиты, чтобы убедиться, что они одинаковые? Не нужно отправлять весь diff, просто отправьте идентификаторы.
В-третьих, и это гений, две коммиты с одинаковыми идентификаторами имеют одинаковую историю. Поэтому идентификатор предыдущих коммитов является частью хеша. Если содержание фиксации одно и то же, но родители разные, идентификатор фиксации должен быть другим. Это означает, что при сравнении репозиториев (например, в push или pull) один раз 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
к следующему нулевому байту. Все это затем запускается через sha1sum
.
Как вы можете видеть, нет ничего, что идентифицировало бы проект или репозиторий в этой информации. Причина, по которой это не вызывает проблем, заключается в том, что астрономически маловероятно, чтобы два разных хеши фиксации столкнулись.