Как git хранит файлы?

225

Я только начал изучать git и для этого я начал читать Git Community Book , и в этой книге говорится, что SVN и CVS хранят разницу между файлами, а git хранит снимок всех файлов.

Но я не совсем понял, что они имеют в виду под снимком. Действительно ли git делает копию всех файлов в каждом коммите, потому что это то, что я понял из их объяснения.

PS: Если у кого-то есть лучший источник для изучения git, я был бы признателен.

mteffaha
источник
20
Вот блестящий пост, который подробно объясняет, как работает git. То, что вы ищете, это, вероятно, § об объектной базе данных.
greg0ire
Отличная статья, которая содержит ссылки на другие замечательные ресурсы. Я развлекался с ними пару часов.
Михай
2
Я нашел эту действительно хорошую статью, описывающую git изнутри: maryrosecook.com/blog/post/git-from-the-inside-out
Sumudu

Ответы:

275

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

Таким образом, моментальный снимок - это в основном коммит, ссылающийся на содержимое структуры каталогов.

Некоторые хорошие ссылки:

Вы говорите Git, что хотите сохранить снимок вашего проекта с помощью команды git commit, и она в основном записывает манифест того, как все файлы в вашем проекте выглядят в этот момент.

Лабораторная работа 12 иллюстрирует, как получить предыдущие снимки


Книга Progit содержит более полное описание снимка:

Основное различие между Git и любой другой VCS (включая Subversion и друзей) заключается в том, как Git думает о своих данных.
Концептуально большинство других систем хранят информацию в виде списка файловых изменений. Эти системы (CVS, Subversion, Perforce, Bazaar и т. Д.) Воспринимают информацию, которую они хранят, как набор файлов и изменения, внесенные в каждый файл с течением времени.

VCS на основе дельты

Git не думает и не хранит свои данные таким образом. Вместо этого Git думает о своих данных скорее как набор снимков мини файловой системы.
Каждый раз, когда вы фиксируете или сохраняете состояние вашего проекта в Git, он в основном делает снимок того, как все ваши файлы выглядят в данный момент, и сохраняет ссылку на этот снимок.
Чтобы быть эффективными, если файлы не изменились, Git больше не сохраняет файл - просто ссылка на предыдущий идентичный файл, который он уже сохранил.
Git думает о своих данных, как показано ниже:

VCS на основе снимков

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


Ян Худек добавляет этот важный комментарий :

Хотя это верно и важно на концептуальном уровне, это НЕ верно на уровне хранилища.
Git использует дельты для хранения .
Мало того, но он более эффективен, чем любая другая система. Потому что он не хранит историю файлов, когда он хочет сделать дельта-сжатие, он берет каждый BLOB-объект, выбирает некоторые BLOB-объекты, которые могут быть похожими (используя эвристику, которая включает в себя наиболее близкое приближение предыдущей версии и некоторые другие), пытается создать дельты и выбирает наименьший. Таким образом, он может (часто зависит от эвристики) использовать преимущества других похожих файлов или более старых версий, которые более похожи на предыдущие. Параметр «окно пакета» позволяет торговать производительность для качества дельта-сжатия. Значение по умолчанию (10) обычно дает приличные результаты, но когда пространство ограничено или для ускорения передачи по сети, git gc --aggressiveиспользуется значение 250, что делает его очень медленным, но обеспечивает дополнительное сжатие для данных истории.

VonC
источник
4
@JanHudec хороший момент. Я включил ваш комментарий в ответ для большей наглядности.
VonC
1
Кто-нибудь знает компьютерный термин для обозначения Git-подобного шаблона хранения, известного как хэш-хранилище значений? (или что-то подобное)
Joannes Vermorel
34
В контексте актуального вопроса ФП первый абзац кажется действительно вводящим в заблуждение. Это пока вы не дойдете до последнего пункта , что мы узнаем , что, ах , да, то , Git делает «магазин [...] различие между файлами. На самом деле хочет , что информация была помечена до вершины и не похоронила так глубоко. Тем не менее, спасибо на хотя бы включая реальную историю где-то в вашем ответе;)
Джош О'Брайен
1
@NickVolynkin Отлично! Я рад, что эти ответы находят большую аудиторию.
VonC
1
Еще одна хорошая книга: Git From the Bottom Up: ftp.newartisans.com/pub/git.from.bottom.up.pdf
Джонас Берлин,
46

Git логически сохраняет каждый файл под своим SHA1. Это означает, что если у вас есть два файла с одинаковым содержимым в хранилище (или если вы переименуете файл), сохраняется только одна копия.

Но это также означает, что когда вы изменяете небольшую часть файла и фиксируете, сохраняется другая копия файла. Git решает эту проблему, используя файлы пакета. Время от времени все «свободные» файлы (на самом деле, не только файлы, но и объекты, содержащие информацию о коммитах и ​​каталогах) из репозитория собираются и сжимаются в пакетный файл. Файл пакета сжимается с использованием zlib. И подобные файлы также дельта-сжаты.

Этот же формат также используется при извлечении или нажатии (по крайней мере, с некоторыми протоколами), поэтому эти файлы не нужно повторно сжимать.

Результатом этого является то, что репозиторий git, содержащий всю несжатую рабочую копию, несжатые последние файлы и сжатые старые файлы, как правило, относительно мал, в два раза меньше, чем размер рабочей копии. А это значит, что он меньше, чем репозиторий SVN с теми же файлами, хотя SVN не хранит историю локально.

svick
источник
1
ах так ртуть более эффективна в космосе
Бен