Слово tree довольно перегружено в Git (ну, и, в общем, в вычислениях).
Рабочее дерево или Рабочее дерево (или другие варианты этого написания) относится к месту, в котором вы выполняете свою работу. Здесь файлы имеют свою обычную повседневную форму, доступны для чтения и записи с ОС. (В системе Unix, если вы chmod -w
ваши файлы, вы не сможете их записать. Однако это не вина Git.)
A объект дерева в Git - это внутренняя структура данных, которая записывает дерево каталогов или поддерево. Он содержит одну запись для каждого файла или подкаталога (или, для подмодулей, запись gitlink для этого подмодуля). В каждой записи указан бит режима исполняемого файла, в виде флага «да» или «нет», который странным образом кодируется, 1 плюс имя файла и идентификатор хэша BLOB-объекта. Для поддерева в записи перечислены имя каталога и идентификатор хеша объекта поддерева. Затем Git может рекурсивно работать с объектом поддерева, чтобы найти больше файлов и еще больше поддеревьев по мере необходимости. Каждая запись в файле дает хэш-идентификатор для внутреннего blob объекта Git, который представляет собой замороженную (только для чтения) сжатую копию данных файла.
Каждый коммит сохраняет один (1) внутренний хэш-идентификатор объекта дерева Git. Этот объект дерева содержит снимок, который содержит коммит, поэтому снимок коммита действительно является одним из этих деревьев, которое содержит записи для файлов и поддеревьев. Поскольку каждый коммит имеет ровно одно дерево, Git может преобразовать спецификатор коммита в объект дерева:
$ git rev-parse master
3c31a203fbeedb4d746889dc77cbafc395fc6e92
$ git rev-parse master^{tree}
5c4b695f5d5606976f5b72e1a901ed17db30a359
В этом случае коммит , обозначенный master
, является первым большим уродливым хешем, но внутренний объект tree , который этот коммит использует для хранения файлов, является вторым один.
Следовательно, рабочее дерево содержит реальные файлы с реальными данными, а объект дерева Git позволяет Git находить все замороженные файлы коммита, при условии, что вы дадите дерево объект, который соответствует некоторому коммиту. Команда git diff
должна сравнивать две вещи. Эти две вещи могут быть либо двумя отдельными файлами - это своего рода вырожденный случай - либо двумя деревьями файлов . При сравнении двух деревьев, независимо от того, являются ли они объектами дерева или рабочим деревом, полным файлов, git diff
будет:
- Сравните файл Имена в каждом дереве.
- Если они совпадают, Git предполагает, что это «один и тот же файл», и сравнивает содержимое файлов.
- Если у них нет совпадающих имен, при необходимости попытайтесь сопоставить файлы по содержимому.
- Если ничего не помогает, скажите, что некоторые файлы были удалены, а некоторые файлы добавлены. Содержимое удаленного файла все удаляются; содержимое добавленного файла полностью новое.
Это все еще только обзор, потому что git diff
может сделать больше, чем просто эти вещи, но это основы.
Есть еще одна очень важная морщина: git diff
может проверить индекс и рассматривать его как дерево. Индекс содержит копии файлов, взятых откуда-то. Это где-то изначально является тем, что вы делаете git checkout
. Однако вы можете git add
файлы из рабочего дерева, чтобы скопировать их в индекс, заменив версию, которая была там из фиксации. Вы можете git add
файлы из рабочего дерева, которые никогда не были в коммите, и, таким образом, являются новыми для индекса. И вы можете git rm
файлов, с или без --cached
, взять файлы из индекса.
Поскольку Git создаст новый коммит из того, что находится в индексе во время выполнения git commit
, сравнивая содержимое индекса с чем-либо - замороженным деревом из коммита или рабочим деревом - это действительно очень полезная вещь.
1 Фактические записи дерева хранилища (режим, путь, хэш) троек. mode
- это строка: 100755
для исполняемого файла, 100644
для неисполняемого файла, 40000
для поддерева, 120000
для символической ссылки и 160000
для gitlink. Изначально это были поля stat
st_mode
в Linux, и Git допустил, например, 100664
для rw-rw-r--
, но это оказалось ошибкой, поэтому в обычном дереве используется только одно из ограниченного подмножества. Git по-прежнему поддерживает 100664
, поскольку могут существовать некоторые репозитории Git, у которых все еще есть такие записи, но если вы не найдете действительно старый репозиторий, вы не найдете 100664. Хеш всегда представляет собой хэш BLOB-объекта , за исключением для записей gitlink, где хеш-код - это требуемый хеш коммита в подмодуле.