Как git хранит файлы?
Я только начал изучать git и для этого начал читать Git Community Book, и в этой книге говорится, что SVN и CVS хранят разницу между файлами, а git хранит снимок всех файлов.
Но я не совсем понял, что они имеют в виду под снимком. Действительно ли git делает копию всех файлов в каждом коммите, потому что это то, что я понял из их объяснения.
PS: Если у кого-нибудь есть лучший источник для изучения git, я был бы признателен.
4 ответа
Git включает для каждого коммита полную копию всех файлов, за исключением того, что для контента, уже присутствующего в репозитории Git, снимок будет просто указывать на указанный контент, а не дублировать его.
Это также означает, что несколько файлов с одинаковым содержимым хранятся только один раз.
Таким образом, снимок - это в основном коммит, ссылающийся на содержимое структуры каталогов.
Некоторые хорошие ссылки:
Вы говорите Git, что хотите сохранить снимок вашего проекта с помощью команды git commit, и он в основном записывает манифест того, как все файлы в вашем проекте выглядят в этот момент.
Лабораторная работа 12 иллюстрирует, как получить предыдущие снимки
Книга Progit содержит более полное описание снимка:
Основное различие между Git и любой другой VCS (включая Subversion и друзей) заключается в том, как Git думает о своих данных.
Концептуально большинство других систем хранят информацию в виде списка изменений на основе файлов. Эти системы (CVS, Subversion, Perforce, Bazaar и т. Д.) Воспринимают информацию, которую они хранят, как набор файлов и изменения, вносимые в каждый файл с течением времени.
Git не думает и не хранит свои данные таким образом. Вместо этого Git думает о своих данных больше как набор снимков мини файловой системы.
Каждый раз, когда вы фиксируете или сохраняете состояние вашего проекта в Git, он в основном делает снимок того, как все ваши файлы выглядят в данный момент, и сохраняет ссылку на этот снимок.
Чтобы быть эффективными, если файлы не изменились, Git не хранит файл снова - просто ссылка на предыдущий идентичный файл, который он уже сохранил.
Git думает о своих данных, как показано ниже:
Это важное различие между Git и почти всеми другими VCS. Это заставляет Git пересматривать практически все аспекты контроля версий, которые большинство других систем скопировали из предыдущего поколения. Это делает Git больше похожим на мини-файловую систему с несколькими невероятно мощными инструментами, построенными на ее основе, а не просто на VCS.
Jan Hudec добавляет этот важный комментарий:
Хотя это верно и важно на концептуальном уровне, это НЕ верно на уровне хранилища.
Git использует дельты для хранения.
Мало того, но он более эффективен, чем любая другая система. Поскольку он не хранит историю для каждого файла, когда он хочет выполнить дельта-сжатие, он берет каждый BLOB-объект, выбирает некоторые BLOB-объекты, которые могут быть похожими (используя эвристику, которая включает в себя самое близкое приближение предыдущей версии и некоторые другие), пытается генерировать дельты и выбирает самые маленькие. Таким образом, он может (часто зависит от эвристики) использовать преимущества других похожих файлов или более старых версий, которые более похожи на предыдущие. Параметр "окно пакета" позволяет торговать производительность для качества дельта-сжатия. Значение по умолчанию (10) обычно дает приличные результаты, но когда пространство ограничено или для ускорения передачи по сети,git gc --aggressive
использует значение 250, что делает его очень медленным, но обеспечивает дополнительное сжатие для данных истории.
Git логически сохраняет каждый файл под своим SHA1. Это означает, что если у вас есть два файла с одинаковым содержимым в хранилище (или если вы переименуете файл), сохраняется только одна копия.
Но это также означает, что когда вы изменяете небольшую часть файла и фиксируете, сохраняется другая копия файла. Git решает эту проблему, используя файлы пакета. Время от времени все "свободные" файлы (на самом деле, не только файлы, но и объекты, содержащие информацию о коммитах и каталогах) из репозитория собираются и сжимаются в пакетный файл. Файл пакета сжимается с помощью zlib. И подобные файлы также дельта-сжаты.
Этот же формат также используется при извлечении или отправке (по крайней мере, с некоторыми протоколами), поэтому эти файлы не нужно повторно сжимать.
Результатом этого является то, что репозиторий git, содержащий всю несжатую рабочую копию, несжатые последние файлы и сжатые старые файлы, как правило, относительно мал, меньше, чем в два раза размер рабочей копии. А это значит, что он меньше, чем репозиторий SVN с теми же файлами, хотя SVN не хранит историю локально.
ОП: Что означает моментальный снимок в Git? Верно ли, что Git делает копию всех файлов при каждом коммите?
Что означает моментальный снимок в Git?
В Git все коммиты — это неизменяемые снимки вашего проекта (за исключением игнорируемых файлов) в определенный момент времени. Это означает, что каждая фиксация содержит уникальное представление всего вашего проекта, а не только измененные или добавленные файлы (дельты) во время фиксации. Помимо ссылок на фактические файлы, каждая фиксация также наполнена соответствующими метаданными, такими как сообщение фиксации, автор (включая отметку времени), коммиттер (включая отметку времени) и ссылки на родительские фиксации; все они неизменны!
Поскольку коммит (или объект коммита, как его формально называют) полностью неизменяем, попытка изменить какое-либо его содержимое невозможна. Коммиты никогда не могут быть подделаны или изменены после их создания!
Как Git хранит файлы внутри
Из книги Pro Git мы узнаем, что:
Git — это файловая система с адресацией по содержимому. Большой. Что это значит? Это означает, что в основе Git лежит простое хранилище данных типа «ключ-значение». Это означает, что вы можете вставлять любой контент в репозиторий Git, для чего Git вернет вам уникальный ключ, который вы сможете использовать позже для извлечения этого контента.
Итак, давайте посмотрим на иллюстрацию ниже, чтобы понять, что на самом деле означает приведенное выше утверждение и как Git хранит данные (и особенно файлы) внутри.
Простая история коммитов, содержащая три коммита, включая обзор того, как фактические данные (файлы и каталоги) хранятся внутри Git. С левой стороны отображается фактический моментальный снимок с «дельта-изменением» по сравнению с предыдущим коммитом, выделенным зеленым цветом. В крайнем правом углу находятся внутренние объекты, используемые для хранения.
Git использует три основных объекта во внутренней памяти:
- Объект фиксации (контейнер моментальных снимков высокого уровня)
- Объект дерева (низкоуровневый контейнер имени файла/каталога)
- Объект Blob (контейнер файлового содержимого низкого уровня)
Для хранения файла внутри Git в общем смысле (например, содержимое + имя файла/каталог) необходим один большой двоичный объект и дерево ; большой двоичный объект для хранения только содержимого файла и дерево для хранения имени файла/каталога, ссылающегося на большой двоичный объект. Для создания вложенных каталогов используются несколько деревьев; следовательно, дерево может ссылаться как на капли, так и на деревья. С точки зрения высокого уровня вам не нужно беспокоиться о больших двоичных объектах и деревьях , поскольку Git создает их автоматически как часть процесса фиксации.
Примечание. Git вычисляет все хэши (ключи) снизу вверх, начиная с больших двоичных объектов, перемещаясь по любым поддеревьям и в конечном итоге достигая корневого дерева, передавая ключи в качестве входных данных своим прямым родителям. Этот процесс создает визуализируемую выше структуру, известную в математике и информатике как направленный ациклический граф (DAG), например, все ссылки перемещаются только в одном направлении без каких-либо циклических зависимостей.
Анализ визуализированного примера немного дальше
Внимательно изучив вышеприведенную историю, мы видим, что для начальной фиксации C0 были добавлены два пустых файла, и — но был создан только один большой двоичный объект ! Это потому, что Git хранит только уникальный контент, и поскольку содержимое двух пустых файлов, очевидно, приводит к одному и тому же хешу:
Продолжая движение вверх ко второму коммиту C1 , мы видим, что только файл был обновлен, создав новый большой двоичный объект (
В финальном C2 фиксируют только
В итоге
Каждый раз, когда создается новая фиксация, снимок всего вашего проекта записывается и сохраняется во внутренней базе данных в соответствии со структурой данных DAG. Всякий раз, когда фиксация извлекается, ваше рабочее дерево реконструируется, чтобы отражать то же состояние, на которое базовый снимок ссылается через корневое дерево.
Источник: приведенный выше отрывок взят из этого полного поста на тему:Неизменяемые моментальные снимки — одна из основных концепций Git.
Ответы выше довольно просты, но я хотел бы добавить еще одну маленькую крошечную концепцию, известную как дельта-кодирование. Эффективность сохраняется до тех пор, пока не будет записан файл пакета. Свободные объекты записываются в сжатом, но не дельта-формате во время каждой фиксации.