Данные 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 сохраняет более эффективно.

Для сравнения изменений вы можете начать со сравнения хэшей дерева, а затем, если они не совпадают, вы обойдете дерево и сравните его сгустки и деревья и т. Д. Поскольку модель разработана на основе атомарных фиксаций, различие в файлах обходится дороже, но не безосновательно.

Другие вопросы по тегам