Объектная модель Git
SHA
Все данные проекта хранятся в файлах, имеющих 40-символьные имена вот такого вида:
Такие названия используются во всей внутренней структуре. Для каждого файла название получается вычислением хеша содержимого при помощи алгоритма SHA1. SHA1 (Secure Hash Algorithm 1) — это алгоритм криптографического хеширования. Для нас это означает, что практически невозможно найти два обекта с одинаковым содержанием и различающимися именами. Это дает нам некоторые преимущества, среди которых можно выделить:
- Git может быстро определить схожесть двух объектов, сравнив лишь их названия
- Названия объектов вычисляются одним и тем же способом в каждом репозитории, это означает что объекты с одинаковым содержанием в различных репозиториях будут иметь одинаковые имена
- Git имеет возможность обнаруживать ошибки во время чтения, проверяя целостность данных, проверкой того, что именем объекта по прежнему является хеш содержимого
Объекты
Каждый объект состоит из трех вещей – типа, размера и содержания. Размер является простым размером содержания, а содержание зависит от типа объекта, четырех видов «blob», «tree», «commit», и «tag».
- Тип «blob» используется для хранения содержимого файлов, можно сказать что это и есть файлы
- Для типа «tree» можно провести аналогию с директорией, это связанные ссылки на другие объекты типа «blob» и/или «tree» (по аналогии файлы и вложенные директории)
- Тип «commit» указывает на объект типа «tree», отмечая как проект выглядел в определённый момент времени. Так же содержит мета-данные о времени и авторе изменений с момента последнего «коммита», указатель на предыдущий «коммит» и пр.
- Тип «tag» – это способ добавить особую отметку к «коммиту». Обычно используется для пометок определенных моментов разработки (к примеру релизы) и пр. в таком духе.
Практически вся работа с Git заключается в манипулировании с этими четыремя типами объектов. Это разновидность небольшой собственной файловой системы, которая располагается поверх файловой системы Вашего компьютера.
Отличия от SVN
Важным моментом является сильное отличие Git от большинства, возможно уже знакомых Вам SCM (Source Code Management — системы контроля версий). Subversion, CVS, Perforce, Mercurial используют систему сохранения изменений – хранят только произведенные изменения между «коммитами». Git устроен иначе, он делает «снимок» всех данных в текущей «ветке» ( «tree» ) структуры проекта каждый «коммит» ( «commit» ). Это очень важный момент, для понимания основных принципов, при работе с Git.
Объекты типа blob
В целом, объекты типа blob хранят содержимое файла.

Для просмотра содержимого объекта типа blob можно воспользоваться командой git-show. Если нам известен SHA хеш для объекта, то мы можем просмотреть его содержимое следующим образом:
Note that the only valid version of the GPL as far as this project
is concerned is _this_ particular version of the license (ie v2, not
v2.2 or v3.x or whatever), unless explicitly otherwise stated.
...
Объект «blob» это не что иное как участок памяти бинарных данных, не связанных ни с чем или имеющих какие либо свойства, в том числе и имя файла.
Тип «blob» полностью определяется своим содержимым. Если у двух различных файлах в структуре дерева (объекте типа «tree») или же даже в других версиях репозитория будет одинаковое содержание, то они будут ссылаться на один и тот же объект типа «blob». Таким образом объект получается абсолютно независим от своего расположения в структуре дерева и даже переименование файла не изменит объект, с которым связан файл.
Объекты типа «tree» (деревья)
Дерево, это набор связанных указателей на объекты типа «blob» и другие деревья, по аналогии с директорией с файлами и вложенными другими директориями.

Универсальная комманда git show может быть так же исползована для получения информации о деревьях (объектах типа «tree»), но команда git ls-tree предоставляет больше дополнительной информации.
Имея имя дерева (SHA хэш), , то мы можем просмотреть его содержимое следующим образом:
100644 blob 63c918c667fa005ff12ad89437f2fdc80926e21c .gitignore
100644 blob 5529b198e8d14decbe4ad99db3f7fb632de0439d .mailmap
100644 blob 6ff87c4664981e4397625791c8ea3bbb5f2279a3 COPYING
040000 tree 2fb783e477100ce076f6bf57e4a6f026013dc745 Documentation
100755 blob 3c0032cec592a765692234f1cba47dfdcc3a9200 GIT-VERSION-GEN
100644 blob 289b046a443c0647624607d471289b2c7dcd470b INSTALL
100644 blob 4eb463797adc693dc168b926b6932ff53f17d0b1 Makefile
100644 blob 548142c327a6790ff8821d67c2ee1eff7a656b52 README
...
Как видим дерево содержит список записей, каждая из которых содержит права, тип объекта, SHA1 имя и оригинальное имя, отсортированный по оригинальным именам. Это представляет собой содержимое одной директории.
Объекты на которые ссылаются деревья могут быть типа «blob» (обычными файлами) или другими деревьями, представляющими собой подкаталоги. Поскольку деревья и файлы (объекты типа «blob») именуются по SHA1 хешу их содержимого, два дерева могут иметь одинаковое название (SHA1 хеш) только в том случае, если их содержимое идентично (включая рекурсивное содержание вложенных деревьев). Эта особенность позволяет Git быстро определить различия между двумя взаимосвязанными деревьями, поскольку может игнорировать и не сравнивать объекты с одинаковыми именами.
(Примечание: при наличии дополнительных модулей, деревья могут также содержать в себе «коммиты» (объекты типа «commit»). Для дополнительной информации следует обратиться к разделу дополнительные модули).
Обратите внимание, что все файлы имеют права 644 или 755: Git фактически обращает внимание лишь на исполняемый бит.
Коммиты (объекты типа «commit»)
Коммиты связывают физическое состояние дерева с описание кто и зачем его совершил.
Можно использовать параметр --pretty=raw c коммандами git show или git log для просмотра информации о выбранном коммите.
commit 2be7fcb4764f2dbcee52635b91fedb1b3dcf7ab4
tree fb3a8bdd0ceddd019615af4d57a53f43d8cee2bf
parent 257a84d9d02e90447b149af58b271c19405edb6a
author Dave Watson 1187576872 -0400
committer Junio C Hamano 1187591163 -0700
Fix misspelling of 'suppress' in docs
Signed-off-by: Junio C Hamano
Как видно, коммит определяется следующими вещами:
- Дерево (объект типа «tree»): SHA1 хеш имя объекта, представлющего собой содержимое директории в определенный момент времени
- Родитель (или несколько родителей): SHA1 хеш имя некоторого числа родительских коммитов, идущих непосредственно перед текущим в истории проекта. В примере выше один родительский коммит, однако при коммитах со слиянием может быть несколько родителей. Коммит который не имеет родителей, называется корневым ( «root» ) и представляет собой первоначальную инициализацию проекта. У каждого проекта должен быть по крайней мере один корень, хотя может быть и несколько, но такая реализация встречается не часто.
- Автор: имя человека, сделавшего изменения, отображается вместе с датой
- Коммитер: имя человека, который создал данный комит, отображается так же с датой коммита. Коммитер может отличаться от автора, если, к примеру, если автор создал пачт и отправил его по почте другому человеку, который используя данный патч и создал комит.
- Комментарий: описание для данного коммита
Необходимо заметить, что коммит сам по себе не содержит информации о внесенных изменениях; изменения получаются путем сравнения дерева из текущей ветки коммита с деревьями из родительского коммита. В частности Git не пытается записать переименованный файл, хотя в некоторых случаях он может обнаружить файл со схожим содержанием, но по другому адресу и предложить переименовать. (Для примера посмотрите на ключ -M комманды git diff).
Коммит, как правило, создается коммандой git commit, родителем становится текущая последняя ревизия (HEAD) и деревом становится текущий каталог, из которого выполнена комманда.
Объектная модель
Теперь, когда мы рассмотрели 3 основных типа объектов (blob, tree и commit) настало время сделать небольшой обзор о том, как они сочетаются.
Допустим у нас простой небольшой проект со следующей структурой:
.
|-- README
`-- lib
|-- inc
| `-- tricks.rb
`-- mylib.rb
2 директории, 3 файла
И мы создали коммит в репозиторий Git, он будет выглядеть следующим образом:
Здесь видно, что мы получили объект типа дерево для каждой директории (включая корневую) и объект типа blob для каждого файла. Затем создался объект коммит с указанием на корневое дерево, таким образом мы можем отследить как выглядел наш проект, когда был закоммичен.
Объекты типа tag (тэг)
Тэги содержат имя объекта (называемый просто ‘объект’), тип объекта, имя тэга, имя автора, создавшего данный тэг ( «tagger») и сообщение, которое может содержать подписи, которые можно увидеть воспользовавшись коммандой git cat-file:
object 437b1b20df4b356c9342dac8d38849f24ef44f27
type commit
tag v1.5.0
tagger Junio C Hamano 1171411200 +0000
GIT 1.5.0
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQBF0lGqwMbZpPMRm5oRAuRiAJ9ohBLd7s2kqjkKlq1qqC57SbnmzQCdG4ui
nLE/L9aUXdWeTFPron96DLA=
=2E+0
-----END PGP SIGNATURE-----
Посмотрите описание комманды git tag, что бы узнать как создавать и контролировать объекты типа тэг. (Заметим, так же, что git tag может использоваться для создания «легких тэгов», которые не являются объектами типа тэг вовсе, а простыми ссылками, имена которых начинаются с «refs/tags/»).
Перевод, оригинал статьи: http://book.git-scm.com/1_the_git_object_model.html

