Данные Git's blob и другая информация
Насколько я знаю, BLOB-объект Git имеет хэш SHA1 в качестве имени файла, чтобы не дублировать файл в хранилище.
Например, если файл A имеет содержимое "abc" и имеет хэш SHA1 как "12345", при условии, что содержимое не изменяется, коммиты / ветви могут указывать на один и тот же SHA1.
Но что произойдет, если файл A будет изменен на "def", чтобы иметь хэш SHA "23456"? Сохраняет ли Git файл A и измененный файл A (не только разницу, но и весь файл)?
- Если так, то почему? Не лучше ли хранить информацию о разнице?
- Если нет, то как diff отслеживает изменения в файле?
- Как насчет других систем VCS - CVS / SVN / Perforce...?
ADDED
Следующее из 'Git Community Book' отвечает на большинство моих вопросов.
Важно отметить, что это сильно отличается от большинства систем SCM, с которыми вы, возможно, знакомы. Subversion, CVS, Perforce, Mercurial и другие используют системы Delta Storage - они хранят различия между одним коммитом и следующим. Git не делает этого - он сохраняет снимок того, как все файлы в вашем проекте выглядят в этой древовидной структуре каждый раз, когда вы фиксируете. Это очень важная концепция для понимания при использовании Git.
2 ответа
git хранит файлы по содержимому, а не по diff, поэтому в вашем примере обе версии A ("abc" и "def") будут храниться в объектной базе данных.
Лучше хранить целые объекты, потому что очень легко увидеть, совпадают ли две версии файла, или нет, просто сравнивая их SHA. Загляните в git-book, чтобы узнать, как хранятся объекты. Это работает лучше, потому что, если файлы отслеживались с помощью diff, вам понадобилась бы вся история файла, чтобы восстановить его. Это легко сделать в централизованной системе, но не в распределенной системе, где в файле может быть много разных изменений.
Git выполняет сравнения непосредственно с объектами.
Одна из целей Git - скорость. Подумайте о том, чтобы хранить объекты в git как дельты, а не как уникальные объекты.
Если вы храните каждый уникальный BLOB-объект с помощью хэша SHA1, для извлечения содержимого из этого хэша SHA1 требуются только фиксированные вычисления. Если вы начнете хранить дельты, вам придется реконструировать объект, и вычисления больше не будут фиксированными и могут увеличиваться без ограничений в зависимости от реализации.
Хороший способ понять дизайн - это посмотреть на реальный репозиторий (примечание: электронные письма):
$ git cat-file commit HEAD
tree 21f9601e608cf62360fca43cd7f0bf05bb65bd23
parent 11507e17a7c823c379202ae344aa59fe5370a4fd
author John Doe <[email protected]> 1273816361 -0400
committer John Doe <[email protected]> 1273816361 -0400
Important Work
$ git ls-tree HEAD
100644 blob 2f6d9912344c299670551c9e9684a7cae800ec5d .gitignore
...
100644 blob a3ddeb9dd0541b80981f2f78bbc500579a13459a COPYING
040000 tree f1ac0acae2a4ab31c2a79b71f08ebd651136d706 contrib
...
Из этих двух команд видно, что коммит - это просто метаданные, один или несколько родителей и дерево. Дерево содержит одну или несколько капель и деревьев.
Зная это, вы можете начать рассматривать сложность различных операций с репозиторием. Кончик ветви - это просто указатель на хеш коммита. Итак, начиная с этого, перечисление истории просто вопрос обхода родителей. Распечатка содержимого дерева просто означает обход дерева и всех поддеревьев. Получение содержимого файла, как указано выше.
Конечно, всегда есть компромисс, и эта модель довольно неэффективна, хотя она и обеспечивает автоматическую дедупликацию на уровне файлов, поскольку каждый уникальный файл должен храниться только один раз. Это эффективно смягчается с помощью packfile. Дельта-хранилище (используется в svn и т. Д.) Экономит пространство без сжатия, но в конечном итоге git сохраняет более эффективно.
Для сравнения изменений вы можете начать со сравнения хэшей дерева, а затем, если они не совпадают, вы обойдете дерево и сравните его сгустки и деревья и т. Д. Поскольку модель разработана на основе атомарных фиксаций, различие в файлах обходится дороже, но не безосновательно.