# Снимки против дельт _Основы Git · GitLab Knowledge Base_ **TL;DR:** Главное идейное отличие Git от SVN/CVS/Perforce. Старые VCS хранят каждую версию как разницу с предыдущей. Git хранит каждую версию как полный снимок проекта, с дедупликацией одинаковых файлов через SHA. В системах вроде SVN, CVS, Perforce каждая версия файла хранится как разница (delta) от предыдущей. Чтобы получить файл недельной давности, система начинает с одной из версий и накатывает дельты в нужную сторону. ``` SVN / CVS / Perforce - модель дельт: v1: полный файл v2: дельта (3 строки изменены) v3: дельта (1 строка добавлена) v4: дельта (5 строк удалено) ↑ чтобы восстановить v4, нужно применить дельты v1+v2+v3+v4 ``` Git устроен иначе. Каждый коммит хранит полный *снимок* всего проекта через [tree](/courses/git/kb/tree.md)-объект. Не разницу - фотографию. ``` Git - модель снимков: коммит 1: snapshot 1 коммит 2: snapshot 2 коммит 3: snapshot 3 ↑ чтобы посмотреть коммит 3, просто берём snapshot 3 ``` ## Откуда экономия места Кажется расточительным хранить весь проект на каждом коммите. Так и есть, и Git использует две хитрости: **Дедупликация по содержимому.** Файл хранится через [blob](/courses/git/kb/blob.md), адресуемый по SHA содержимого. Если файл не менялся между коммитами - у него тот же SHA, и Git переиспользует один и тот же blob. Реально на диске лежит «снимок дерева директорий с указателями на файлы», а не «снимок проекта целиком». **Дельты внутри [packfile](/courses/git/kb/packfile.md).** При `git gc` или `git push` накопленные объекты упаковываются в один файл, внутри которого *похожие объекты* кодируются как дельты. Это оптимизация хранения, не модель данных. ## Почему это важно Разница между моделями - фундамент того, как Git работает. - Ветка - это указатель на снимок, а не запись «отделилось в такой-то момент». Создание ветки = 40 байт. Переключение - мгновенное. - `git log` идёт по цепочке `parent` коммитов, читая готовые снимки. Не нужно реконструировать историю. - `git diff` показывает разницу между двумя снимками - вычисляется на лету. Это **вид**, не **способ хранения**. Частая путаница. ## Команды ```bash git cat-file -p HEAD^{tree} ``` Содержимое снимка последнего коммита ```bash git cat-file -t ``` Тип объекта (snapshot обращается через tree) ```bash git diff ``` Diff между двумя снимками - вычисляется в момент запроса ## См. также - [Blob](/courses/git/kb/blob.md) - [Tree](/courses/git/kb/tree.md) - [Commit](/courses/git/kb/commit.md) - [Packfile](/courses/git/kb/packfile.md) - [Распределённая система контроля версий](/courses/git/kb/distributed-vcs.md) - [Система контроля версий](/courses/git/kb/vcs.md)