Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions book/10-git-internals/sections/objects.asc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
Git -- контентно-адресуемая файловая система.
Здорово.
Что это означает?
А означает это, по сути, что Git -- простое хранилище ключ-значение.
Можно добавить туда любые данные, в ответ будет выдан ключ по которому их можно извлечь обратно.
А означает это, по сути, что Git -- простое хранилище «ключ-значение».
Можно добавить туда любые данные, в ответ будет выдан ключ, по которому их можно извлечь обратно.

В качестве примера, воспользуемся служебной командой `git hash-object`, которая берёт некоторые данные, сохраняет их в виде объекта в каталоге `.git/objects` (_база данных объектов_) и возвращает уникальный ключ, который является ссылкой на созданный объект.
В качестве примера воспользуемся служебной командой `git hash-object`, которая берёт некоторые данные, сохраняет их в виде объекта в каталоге `.git/objects` (_база данных объектов_) и возвращает уникальный ключ, который является ссылкой на созданный объект.

Для начала создадим новый Git-репозиторий и убедимся, что каталог `objects` пуст:

Expand All @@ -34,11 +34,11 @@ d670460b4b4aece5915caf5c68d12f560a9fe3e4

В простейшем случае `git hash-object` берёт переданный контент и возвращает уникальный ключ, который будет использоваться для хранения данных в базе Git.
Параметр `-w` указывает команде `git hash-object` не просто вернуть ключ, а ещё и сохранить объект в базе данных.
Последний параметр `--stdin` указывает, что `git hash-object` должна использовать данные, переданные на стандартный потока ввода; в противном случае команда ожидает путь к файлу в качестве аргумента.
Последний параметр `--stdin` указывает, что `git hash-object` должна использовать данные, переданные на стандартный поток ввода; в противном случае команда ожидает путь к файлу в качестве аргумента.

Результат выполнения команды -- 40-символьная контрольная сумма.
Это SHA-1 хеш -- контрольная сумма содержимого и заголовка, который будет рассмотрен позднее.
Теперь можно посмотреть как Git хранит ваши данные:
Это SHA-1-хеш -- контрольная сумма содержимого и заголовка, который будет рассмотрен позднее.
Теперь можно посмотреть, как Git хранит ваши данные:

[source,console]
----
Expand All @@ -63,7 +63,7 @@ test content
Теперь вы умеете добавлять данные в Git и извлекать их обратно.
То же самое можно делать и с файлами.
Например, можно проверсионировать один файл.
Для начала, создадим новый файл и сохраним его в базе данных Git:
Для начала создадим новый файл и сохраним его в базе данных Git:

[source,console]
----
Expand Down Expand Up @@ -110,8 +110,8 @@ version 2
----

Однако запоминать хеш для каждой версии неудобно, к тому же теряется имя файла, сохраняется лишь содержимое.
Объекты такого типа называют блобами (англ. blob -- binary large object).
Имея SHA-1 объекта, можно попросить Git показать нам его тип с помощью команды `cat-file -t`:
Объекты такого типа называют блобами (англ. _blob_ -- binary large object).
Имея SHA-1-хеш объекта, можно попросить Git показать нам его тип с помощью команды `cat-file -t`:

[source,console]
----
Expand All @@ -122,10 +122,10 @@ blob
[[r_tree_objects]]
==== Деревья

Следующий тип объектов, который мы рассмотрим, -- деревья -- решают проблему хранения имён файлов, а также позволяют хранить группы файлов вместе.
Следующий тип объектов, который мы рассмотрим -- деревья, -- решают проблему хранения имён файлов, а также позволяют хранить группы файлов вместе.
Git хранит данные сходным с файловыми системами UNIX способом, но в немного упрощённом виде.
Содержимое хранится в деревьях и блобах, где дерево соответствует каталогу на файловой системе, а блоб более или менее соответствует индексу узла (inode) или содержимому файла.
Дерево может содержать одну или более записей, содержащих SHA-1 хеш, соответствующий блобу или поддереву, права доступа к файлу, тип и имя файла.
Дерево может содержать одну или более записей, содержащих SHA-1-хеш, соответствующий блобу или поддереву, права доступа к файлу, тип и имя файла.
Например, дерево последнего коммита в проекте может выглядеть следующим образом:

[source,console]
Expand All @@ -150,7 +150,7 @@ $ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
Вы можете столкнуться с различными ошибками при использовании синтаксиса `master^{tree}` в зависимости от того, какую оболочку используете.

В Windows CMD символ `^` используется для экранирования, поэтому для исключения ошибок следует использовать двойной символ: `git cat-file -p master^^{tree}`.
В PowerShell параметры, использующие символы {}, должны быть заключены в кавычки: `git cat-file -p 'master^{tree}'`.
В PowerShell параметры, использующие символы `{}`, должны быть заключены в кавычки: `git cat-file -p 'master^{tree}'`.

В ZSH символ `^` используется для подстановки, поэтому выражение следует помещать в кавычки: `git cat-file -p "master^{tree}"`.
====
Expand All @@ -161,7 +161,7 @@ $ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
image::images/data-model-1.png["Упрощённая модель данных Git"]

Можно создать дерево самому.
Обычно, Git создаёт дерево путём создания набора объектов из состояния области подготовленных файлов или индекса.
Обычно Git создаёт дерево путём создания набора объектов из состояния области подготовленных файлов или индекса.
Поэтому для создания дерева необходимо проиндексировать какие-нибудь файлы.
Для создания индекса из одной записи -- первой версии файла `test.txt` -- воспользуемся низкоуровневой командой `git update-index`.
Данная команда может искусственно добавить более раннюю версию `test.txt` в новый индекс.
Expand Down Expand Up @@ -219,8 +219,8 @@ $ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
----

Обратите внимание, что в данном дереве находятся записи для обоих файлов, а также, что хеш файла `test.txt` это хеш «второй версии» этого файла (`1f7a7a`).
Для интереса, добавим первое дерево как подкаталог текущего.
Обратите внимание, что в данном дереве находятся записи для обоих файлов, а также что хеш файла `test.txt` -- это хеш «второй версии» этого файла (`1f7a7a`).
Для интереса добавим первое дерево как подкаталог текущего.
Добавлять деревья в область подготовленных файлов можно с помощью команды `git read-tree`.
В нашем случае, чтобы включить уже существующее дерево в индекс и сделать его поддеревом, необходимо использовать опцию `--prefix`:

Expand Down Expand Up @@ -248,7 +248,7 @@ image::images/data-model-2.png["Структура данных Git для те
К тому же у нас нет никакой информации о том, кто, когда и почему сохранил их.
Такие данные -- основная информация, хранимая в объекте коммита.

Для создания коммита необходимо вызвать команду `commit-tree` и задать SHA-1 нужного дерева и, если необходимо, родительские коммиты.
Для создания коммита необходимо вызвать команду `commit-tree`, задать SHA-1 нужного дерева и, если необходимо, родительские коммиты.
Начнём с создания коммита для самого первого дерева:

[source,console]
Expand Down Expand Up @@ -284,7 +284,7 @@ $ echo 'Third commit' | git commit-tree 3c4e9c -p cac0cab
----

Каждый из созданных объектов коммитов указывает на одно из созданных ранее деревьев состояния проекта.
Вы не поверите, но теперь у нас есть полноценная Git история, которую можно посмотреть командой `git log`, указав хеш последнего коммита:
Вы не поверите, но теперь у нас есть полноценная Git-история, которую можно посмотреть командой `git log`, указав хеш последнего коммита:

[source,console]
----
Expand Down Expand Up @@ -319,7 +319,7 @@ Date: Fri May 22 18:09:34 2009 -0700
----

Здорово, правда?
Мы только что выполнили несколько низкоуровневых операций и получили Git репозиторий с историей без единой высокоуровневой команды.
Мы только что выполнили несколько низкоуровневых операций и получили Git-репозиторий с историей без единой высокоуровневой команды.
Именно так и работает Git, когда выполняются команды `git add` и `git commit` -- сохраняет блобы для изменённых файлов, обновляет индекс, создаёт деревья и фиксирует изменения в объекте коммита, ссылающемся на дерево верхнего уровня и предшествующие коммиты.
Эти три основных вида объектов Git -- блоб, дерево и коммит -- сохраняются в виде отдельных файлов в каталоге `.git/objects`.
Вот как сейчас выглядит список объектов в этом каталоге, в комментарии указано чему соответствует каждый из них:
Expand Down Expand Up @@ -348,7 +348,7 @@ image::images/data-model-3.png["Все объекты в каталоге Git"]

Ранее мы упоминали, что вместе с содержимым объекта сохраняется дополнительный заголовок.
Давайте посмотрим, как Git хранит объекты на диске.
Мы рассмотрим как происходит сохранение блоб объекта -- в данном случае это будет строка «what is up, doc?» -- в интерактивном режиме на языке Ruby.
Мы рассмотрим как происходит сохранение блоб-объекта -- в данном случае это будет строка «what is up, doc?» -- в интерактивном режиме на языке Ruby.

Для запуска интерактивного интерпретатора воспользуйтесь командой `irb`:

Expand All @@ -359,7 +359,7 @@ $ irb
=> "what is up, doc?"
----

Git создаёт заголовок, начинающийся с типа объекта, в данном случае это блоб.
Git создаёт заголовок, начинающийся с типа объекта -- в данном случае это блоб.
Далее идут пробел, размер содержимого в байтах и в конце нулевой байт:

[source,console]
Expand All @@ -368,7 +368,7 @@ Git создаёт заголовок, начинающийся с типа об
=> "blob 16\u0000"
----

Git объединяет заголовок и оригинальный контент, а затем вычисляет SHA-1 сумму от полученного результата.
Git объединяет заголовок и оригинальный контент, а затем вычисляет SHA-1-сумму от полученного результата.
В Ruby значение SHA-1 для строки можно получить, подключив соответствующую библиотеку командой `require` и затем вызвав `Digest::SHA1.hexdigest()`:

[source,console]
Expand Down
Loading