Git знак коммит где-то в истории
В некоторых частях Интернета (например, здесь) подразумевается, что коммиты git должны быть подписаны, когда они сделаны, или никогда.
Тем не менее, технически подпись на коммите является ничем иным, как подписью на объекте фиксации (как показано здесь), который состоит из хеша файла "дерево" (то есть списка хешей объектов git), хеша родителя и некоторые метаданные.
Как следствие, кажется, что нет ничего, что мешает подписать коммит апостериори, не переписывая всю историю.
Это действительно возможно? Есть ли рекомендуемый способ сделать это? Будет ли такая загадочная подпись работать хорошо с толчками и потянущимися?
2 ответа
Я не верю, что вы можете сделать это без переписывания истории. Я просто дважды клонировал один и тот же репозиторий, чтобы провести тест. Я сделал одно и то же изменение в обоих репозиториях, затем зафиксировал одно и то же сообщение журнала ("foobar"), с той лишь разницей, что один был подписан, а другой - нет.
# unsigned test
parent 50c6dd65f1d7a240cf6b5c9585ce363ef4708d1e
new b3ff731922f80a417b84ed492537c1f7ba74715e
# signed test
parent 50c6dd65f1d7a240cf6b5c9585ce363ef4708d1e
new 688b3be2e55558c45b00b6a6c02086a03768e02d
Как видите, начиная с одного и того же родителя (50c6dd65), в результате получается два разных хэша коммита. Таким образом, для невыполненных коммитов это ничем не отличается от любого другого переписывания истории (и, следовательно, оно несет те же обязательства).
В ответ на ваш комментарий с вопросом, изменился ли хэш только из-за разницы во временных метках, я не верю в это. Если вы проверяете с помощью cat-file
:
$ git cat-file -p 688b3be2e55558c45b00b6a6c02086a03768e02d
tree 074e53e54670dea3502229e9494f3d571f5dcc16
parent 50c6dd65f1d7a240cf6b5c9585ce363ef4708d1e
author Dan Lowe <dan@XXXXXXXX.com> 1448768563 -0500
committer Dan Lowe <dan@XXXXXXXX.com> 1448768563 -0500
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEVAwUAVlp0N1rGfrtJ2k+kAQIbYQf7BLx3/jqU/vwvoJOcbq5MPK0ok7B8mOaF
VWhNCbAeOBMzXdrn8IQxY2xYcPsy+d6pNx6ZOF70L3VZm6rWFxNzZQRrjS4ByOAM
VyoL8bXceMcrb/sQUHM5yTCaDcfoYx40K0q91XsGew2EIzNKcOraK1Ee4hEtPg1D
ojyPVjiWz2qMJJ0YYAATSvWwlKFO2ShTC6tGZDHrx0e6BAEN5QS4KdGhNech/vpU
IPFDjIKWtGPTbYY8Z95vKLAMYWPZDJ8j/x1gRytN8PDjRufRtpRnZMccB6JQoXNZ
5L23WQFfUFeXRdWf0MtkrbrSwzuaaIF8l1oGYnEtYT6nOIktPT47Fw==
=/U9b
-----END PGP SIGNATURE-----
foobar
Насколько я понимаю, все эти метаданные являются частью входных данных алгоритма хеширования, приводящих к идентификатору фиксации. Если это так, то присутствие gpgsig
Данные здесь означают, что они всегда дадут вам другой хеш, чем беззнаковая версия коммита.
Каждый объект git идентифицируется собственным хешем SHA-1. Так что они все неизменны.
Если вы подписываете коммит, который вы сделали ранее, вы фактически дублируете этот коммит, но подписанным способом. Таким образом, оригинальный коммит все еще там - вы можете даже git show
это, если вы помните, что это хеш или какой-либо указатель на него указывает. Что бы вы сделали, это создать новый коммит с эквивалентными изменениями и метаданными, но с добавленной подписью, и сделать ссылку, на которой вы находитесь в данный момент - т. Е. Текущую ветвь, - на нее.
Дерево коммита и все остальные объекты будут одинаковыми. Но поскольку сам коммит изменился, вы получаете новый объект коммита - поэтому вы переписываете историю.