понедельник, 29 марта 2010 г.

Git. part 7

Взято здесь

Ветки в git - как ветки деревьев, постоянно обновляются и растут. Одно и то же символьное имя ветки (refs/heads/foo) может указывать на разные коммиты в разные моменты времени. В отличие от веток, теги (tags) - специально созданы для неизменяющихся по времени ссылок.



Символьные имена для тегов лежат в .git/refs/tags. Каждому имени тега может соответствовать один объект в базе git. Это может быть любой из ранее перечисленных типов объектов - блобы, деревья, коммиты.
Символьное имя, указывающее на блоб, дерево или коммит, в терминологии git называется легковесным (lightweight) тегом. Легковесный он потому что кроме SHA1-имени, никакой другой информации не записывается.

Такие легковесные теги можно создавать путем записи SHA1-имени объекта в файл в директории .git/refs/tags/<имя тега>.

Настоящие теги - тяжеловесные или аннотированные (annotated), состоят из двух частей. Первая часть - это объект базы git специального типа (tag). В этот объект записываются следующие данные:

  • SHA1 объекта, на который указывает аннотированный тег.
  • Тип этого объекта (blob, tree, commit или tag) (да, бывают теги указывающие на теги!)
  • Символьное имя тега
  • Дата и время создания тега
  • Имя и e-mail создателя тега (в таком же формате как имя автора коммита)
  • Кусок произвольных данных на усмотрение создателя тега

После чего объект-тег записывается в базу git, и в .git/refs/tags/<имя тега> пишется SHA1 объекта-тега.

В тот самый кусок произвольных данных могут быть записано сообщение тега (по смыслу аналогичное сообщению коммита), а также в него можно внедрить GPG-подпись объекта. Такой тег будет называться подписанным (tag).

Вот тут и проявляется магия git - создавая подписанный тег на определенный коммит, на самом деле подписывается и сам коммит, и вся его история, и все деревья, составляющие историю, и все блобы, "висящие на ветках этих деревьев". То есть все, на что можно "дотянуться" по ссылкам от коммита.

Ладно, хватит теории, давайте перейдем к практике.

Обычные, легковесные теги, как я уже говорил раньше, можно создавать просто записывая SHA1-имя объекта в файл в директории refs/tags/.

Однако правильней создавать их через утилиту git-tag <имя тега> [<имя объекта>]

Если имя объекта не указывать, то по умолчанию тег будет указывать на тот же коммит, на который указывает ссылка HEAD.

Сначала создадим объект на который будет указывать тег. Для иллюстрации я создаю простейший blob, хотя обычно теги указывают на объекты-коммиты.

$ mkdir ~/tmp/gitguts7
$ cd ~/tmp/gitguts7
$ git-init
$ export GIT_AUTHOR_NAME="Git Guts"
$ export GIT_AUTHOR_EMAIL="gitguts@localhost"
$ export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
$ export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
$ echo "Testing blobs" > blobtest
$ git-hash-object -w blobtest
717c935c292fee3dca4c2e5f335f27b657895368


Теперь создаем легковесный тег

$ git-tag lighttag 717c935c292fee3dca4c2e5f335f27b657895368
$ cat .git/refs/tags/lighttag
717c935c292fee3dca4c2e5f335f27b657895368

Как видно, по содержанию легковесные теги ничем не отличаются от бранчей - это обычные файлы с SHA1 объекта внутри.
Кстати, команда git-tag без параметров (или git-tag -l) выведет список тегов.

Теперь создадим аннотированный тег (с помощью git-tag -a). Для создания аннотированного тега необходимо указывать практически то же, что и для создания коммита - то есть имя автора тега, дату создания и сообщение. Ну и чтобы получилось одно и то же время, я опять воспользуюсь программой faketime. В отличие от git-commit-tree, команда git-tag более высокоуровневая, и сообщение для тега можно задавать прямо в командной строке, используя параметр -m.

$ faketime -t 200001010000 git-tag -m 'Test annotated tag' -a annotated_tag lighttag


Заметьте, вместо использования SHA1 blob-а, я использовал ранее заданное имя lighttag, которое указывало на этот blob. В этом и весь смысл тегов - давать символьные имена объектам из базы.

Теперь давайте посмотрим, что же получилось в итоге

$ git-rev-parse annotated_tag
40f93cdf3db19ab20109c81f113a7ccb8b921827
$ git-cat-file tag annotated_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag annotated_tag
tagger Git Guts 946674000 +0300

Test annotated tag


Первая команда (git-rev-parse), позволяет посмотреть, каков SHA1 самого объекта-тега. Вторая команда распечатывает содержимое объекта-тега. В нем можно увидеть SHA1 блоба (первая строчка), тип объекта (вторая строчка), символьное имя (третья строчка), информация об авторе и времени создания тега (четвертая строчка), а ниже - сообщение тега.

Команда создания подписанного тега очень похожа на команду создания обычного тега, просто вместо параметра -a надо передать параметр -s. К сожалению именно эта часть не будет воспроизводиться у читателей, так как у каждого должен быть свой собственный GPG-ключ для подписи. Приведу лишь результаты выполнения команды:

$ faketime -t 200001010000 git-tag -m 'Test annotated tag' -s signed_tag lighttag
$ git-cat-file tag signed_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag signed_tag
tagger Git Guts 946674000 +0300

Test annotated tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEABECAAYFAkf47VMACgkQ8SRmhxtswwQ53wCdHIGaU1ulxud4cUxWVp2pjU1d
358AnAu0Xlti6ZhCSfp9/YToFd//ipcS
=BQ9s
-----END PGP SIGNATURE-----


Как видно, тут к сообщению добавилась подпись, созданная при помощи моего ключа.

Проверить, каким ключом был подписан коммит, можно с помощью git-tag -v

$ git-tag -v signed_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag signed_tag
tagger Git Guts 946674000 +0300

Test annotated tag
gpg: Подпись создана Вск 06 Апр 2008 19:33:39 MSD ключом DSA с ID 1B6CC304
gpg: Действительная подпись от "Damir Shayhutdinov "


Вот так!

Удалять теги можно с помощью git-tag -d

Комментариев нет:

Отправить комментарий