Как Git хранит объекты

Эта глава более подробно описывает как Git физически хранит объекты.

Все объекты хранятся в сжатом виде по имени их sha значения. Они содержат тип объекта, размер и содержимое в формате gzipped.

Существуют два формата в которых Git хранит объекты - свободные и сжатые.

Свободные Objects

Свободные объекты это простейший формат. Это просто сжатые данные сохраненные в файл на диске. Каждый объект записывается в отдельный файл.

Если sha значение вашего объекта ab04d884140f7b0cf8bbf86d6883869f16a46f65, то файл будет храниться по след. пути:

GIT_DIR/objects/ab/04d884140f7b0cf8bbf86d6883869f16a46f65

Git отсекает два первых символа и использует их как поддиректорию, таким образом никогда не бывает очень много объектов в одной директории. Имя файла в действительности состоит из оставшихся 38 символов.

Простейший способ описать в точности как хранятся данные, это показать реализацию на Ruby хранилища объекта:

def put_raw_object(content, type)
  size = content.length.to_s

  header = "#{type} #{size}\0" # type(space)size(null byte)
  store = header + content

  sha1 = Digest::SHA1.hexdigest(store)
  path = @git_dir + '/' + sha1[0...2] + '/' + sha1[2..40]

  if !File.exists?(path)
    content = Zlib::Deflate.deflate(store)

    FileUtils.mkdir_p(@directory+'/'+sha1[0...2])
    File.open(path, 'w') do |f|
      f.write content
    end
  end
  return sha1
end

Сжатые объекты

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

Чтобы сохранить это пространство, Git использует пакфайлы. Это формат, в котором Git сохранит только измененную часть второго файла, и указатель на первый оригинальный файл.

Когда объекты записываются на диск, чаще это свободный формат, так как этот формат менее затратный. Тем не менее, со временем вам потребуется сохранить дисковое простанство упаковывая объекты - это выполняется командой git gc. Эта команда использует специальный алгоритм чтобы определить какие файлы похожи в наибольшей степени. Могут существовать и составные пакфайлы, они могут быть перепакованы если это необходимо (git repack) или легко распакованы обратно в свободный формат (git unpack-objects).

Git также запишет индекс файл для каждого пакфайла который значительно меньше и содержит смещения в пакфайле, чтобы можно было еще быстрее найти определенные объекты по их sha значению.

Подробности реализации пакофайлов могут быть найдены в главе Пакфайлы которая будет несколько позже.



github logo