Как в Git в организовано хранение файлов?

Ссылка скопирована
Git
1 ответ

Помогите пожалуйста разобраться:
1. Я сделал коммит файла. После этого изменил его 3 раза и сделал 3 коммита. Git сохраняет первоначальную копию файла и все 3 его измененных копии полностью (т. е. если я в файле изменил всего 1 % данных он 99% просто дублирует в следующую копию), или хранит первоначальную копию и отдельно 3 последующих изменения (т. е. только то, чего нет в изначальной копии)?
2. Когда я переключаюсь с ветки на ветку, Git копирует в рабочий каталог файлы из базы данных. Я правильно понимаю, что он также при этом копирует те же самые файлы в индекс, так как Git понимает, что нету измененных файлов, сравнивая рабочий каталог с индексом?
3. И тоже самое происходит, когда я клонирую репозиторий? Сначала копируется база данных из удаленного репозитория, потом данные копируются в рабочий каталог и индекс?

Дополнительно:

1. Это же легко проверить. Добавьте объемный текстовый файл и сделайте пару коммитов с изменениями в одной строке. Каждый раз измеряйте объем папки с репозиторием (.git)

Вообще-то как раз гит хранит целые копии файла.
Для каждого файла создается его хеш, и файл-объект хранится под именем с этим кешом.

If you again examine your objects directory, you can see that it now contains a file for that new content. This is how Git stores the content initially — as a single file per piece of content, named with the SHA-1 checksum of the content and its header. The subdirectory is named with the first 2 characters of the SHA-1, and the filename is the remaining 38 characters.

То есть любое изменение файла - создает еще один файл-объект.
Два одинаковых файла не будут занимать два места, даже если они хранятся под разными именами.

Каждый коммит - содержит список файлов и хеш для содержимого.
А ветка - это просто ссылка на конкретный коммит и немного метаданных.

Также файлы-объекты хранятся упакованными, а периодически файлы-объекты могут быть объеденены в отдельный пакет.

Чтобы посмотреть содержимое любого гит-объекта, юзай
git cat-file -p ID_объекта (где айди объекта это как раз его хеш)

И собственно именно эта фича - хранение каждого изменения файла отдельным объектом и позволило создать легковесные ветки, где переключение на любой коммит любой ветки - быстрая проверка и копирование файлов, в отличие от CVS и SVN, где любое переключение ветки - куча пересчетов диффов как назад так и вперед.

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

  • Спасибо большое, я разобрался как хранятся файлы в git. Спасибо Сергей Соловьев ссылку на источник, спасибо Saboteur за разъяснение.

    Поладнее, скажите пожалуйста, я правильно понимаю:
    1. Мы постоянно взаимодействуем с тремя областями, рабочий каталог, индекс и база данных, где хранится вся история. Я правильно понимаю, что, когда мы используем команду git status, git обнаруживает измененные файлы путем сравнения SHA-1 файлов в рабочем каталоге и SHA-1 файлов в индексе?
    2.Когда мы переключаемся на ветку, git переключается на указатель HEAD этой ветки, там он находит ссылку на дерево, откуда получает ссылки на все файлы в базе данных и копирует их в рабочий каталог. И самое главное, также он копирует эти данные также в индекс? Если я правильно понимаю, то он должен это сделать, чтобы команда git status показала, что измененных файлов нет, так как файлы в индексе идентичны файлам в рабочем каталоге.

  • Когда мы переключаемся на ветку, Git переключается на указатель HEAD этой ветки

    Вы не поняли что такое ветка. Нет, ветка в гите это уже указатель на некоторый коммит в цепочке коммитов.
    Указатель HEAD в репозитории один, и он показывает какое состояние в данный момент распаковано в рабочем каталоге. Соответственно у веток нет собственного указателя HEAD.

    Когда мы переключаемся на ветку

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

  • Сергей Кузнецов, что Вы понимаете под пустым индексом? Если я правильно понимаю, он технически не может быть пустым. Там всегда находятся файлы. Иначе как git понимает, что есть измененные файлы?
    Как я уже писал:

    Я правильно понимаю, что, когда мы используем команду git status, git обнаруживает измененные файлы путем сравнения SHA-1 файлов в рабочем каталоге и SHA-1 файлов в индексе?

    Может Вы имеете ввиду под пустым индексом то, что файлы в рабочем каталоге полностью идентичны файлам в индексе?

  • Семен,

    путем сравнения SHA-1 файлов в рабочем каталоге и SHA-1 файлов в индексе?

    На самом деле тут даже сравнивать не нужно. Каждый раз при попытке коммита, создается новый hash-объект, и сохраняется. Но так как имя состоит из этого SHA-1, то он или сохраняется как новый объект, или не сохраняется, так как объект уже есть.

    Если же сравнивать то, что в репозитории и то, что в рабочей директории - работает обычный дифф. Там microsoft подкатила не так давно много изменений для ускорения как раз именно работы с рабочей директорией, если в ней очень много файлов, так что как именно проверяется что было изменено, не подскажу. Ну а как найдены изменения, обычный diff

  • Семен, индекс это черновик коммита, поэтому он очень даже может быть пустым.
    Гит статус сравнивает файлы в рабочем каталоге с файлами в репозитории, чтобы узнать что изменилось.
  • Сергей Кузнецов, я прочитал в книге Раджу Ганди "Head First Git", что в некоторые моменты (когда все файлы находятся в состоянии "unmodified"), все файлы рабочего каталога имеют еще 2 копии: в индексе и базе данных. Т. е. 3 копии файлов. Git сравнивает копию в рабочем каталоге и индексе и тем самым понимает, что есть измененные файлы и сравнивает копию в индексе и базе данных и так он понимает, что есть файлы подготовленные для коммита. Скажите, может я не правильно понял, но тогда получается, индекс никогда не пуст, там всегда есть копии файлов рабочего каталога.
  • в рабочем каталоге файл хранится в единственном экземпляре.
    Только в том случае, когда ты делаешь git add, создается новый гит-объект для файлов, который хранится в "stage", еще до коммита.

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

    Ну и следует точнее оперировать терминами - что такое "база данных", что такое "индекс"?

    Есть репозиторий с git-objects. Все. В других местах файлы не лежат, только метаданные. Нет никакого индекса с файлами в нем.

  • Saboteur, я не говорил, что данные хранятся в рабочем каталоге в нескольких экземплярах. В рабочем каталоге 1 экземпляр, в индексе 1 экземпляр, в базе данных 1 экземпляр. Если я отредактировал файл, git и не должен ничего самостоятельно сравнивать. Но когда я вызывают команду git status, он сравнивает копию в рабочем каталоге и копией в индексе и тем самым помечает измененные файлы и сравнивает копию в индексе с копией в базе данных, тем самым помечает файлы, подготовленные для коммита.

    Не могли бы Вы прокоментировать в противном случает:

    Как в Git в организовано хранение файлов?

    Прошу прощения, что приходится отправлять выдержки из книги, просто я хочу окончательно разобраться.

  • Нет никакого "индекса", где лежат файлы.
    И вообще я бы рекомендовал читать англоязычную документацию, потому что своеобразный перевод терминов может немного страдать.

    В гите только одно хранилище гит-объектов (по вашему это хранилище файлов - база), все остальнео - метаданные, которые ссылаются на эти гит-объекты.

    У вас же тут даже прямо написано что "гит сохраняет свое содержимое в своей объектной базе".

    Разница только в том, что єти файлы еще не принадлежат никакому коммиту.

  • Saboteur, я правильно Вас понял, что этой книге не стоит "доверять"? Потому что там прямо написано, про 3 копии, в рабочем каталоге, индексе и базе (хранилище) и тут дело не в искаженном переводе.
  • Семен, я думаю что это искареженный перевод.

    Индекс, коммит, бренч - это все метаданные.
    Сами файлы хранятся непосредственно как гит-объекты в единой базе.
    Да просто возьмите и поковыряйте что лежит в .git, как оно там лежит. Найдите как хранятся коммиты, референсы. Все ж под рукой.

1. Гит в истории целые файлы, уже измененные, но сжатые (изменения хранит SVN, но у него другая модель работы)
2. Сравнение файлов происходит через сравнение хэша файла. История изменений хранится в виде графа, поэтому переключение - это по сути: 1. Найти общего предка 2. Откатиться до этого предка 3. Применить изменения до новой ветки. Дополнительно, если у тебя есть незакоммиченные текущие изменения, то гит тебе об этом скажет
3. Скачивается вся история изменений из удаленного репозитория и потом HEAD выставляется на ветку, которую клонировал (в основном это main/master)

Почитай как работает git

UPD: спасибо Saboteur за важное замечание

  • Вот только полностью наоборот.
    Это именно гит хранит копии, а SVN хранит диффы, о чем можно как раз почитать по вашей ссылке, а именно тут: https://git-scm.com/book/en/v2/Git-Internals-Git-O...

Ответы:

└─$ find .git                              .git .git/config .git/info .git/info/exclude .git/HEAD .git/refs .git/refs/tags .git/refs/heads .git/branches .git/hooks .git/hooks/pre-rebase.sample .git/hooks/post-update.sample .git/hooks/pre-commit.sample .git/hooks/pre-merge-commit.sample .git/hooks/update.sample .git/hooks/pre-receive.sample .git/hooks/commit-msg.sample .git/hooks/applypatch-msg.sample .git/hooks/pre-applypatch.sample .git/hooks/pre-push.sample .git/hooks/push-to-checkout.sample .git/hooks/prepare-commit-msg.sample .git/hooks/fsmonitor-watchman.sample .git/objects .git/objects/info .git/objects/pack .git/description

└─$ find .git .git .git/config .git/info .git/info/exclude .git/HEAD .git/refs .git/refs/tags .git/refs/heads .git/branches .git/hooks .git/hooks/pre-rebase.sample .git/hooks/post-update.sample .git/hooks/pre-commit.sample .git/hooks/pre-merge-commit.sample .git/hooks/update.sample .git/hooks/pre-receive.sample .git/hooks/commit-msg.sample .git/hooks/applypatch-msg.sample .git/hooks/pre-applypatch.sample .git/hooks/pre-push.sample .git/hooks/push-to-checkout.sample .git/hooks/prepare-commit-msg.sample .git/hooks/fsmonitor-watchman.sample .git/objects .git/objects/info .git/objects/pack .git/description

Git Repository Layout
https://git-scm.com/docs/gitrepository-layout

objects
Хранилище объектов, связанное с этим репозиторием. Обычно хранилище объектов самодостаточно (т. е. все объекты, на которые ссылается найденный в нем объект, также находятся в нем), но есть несколько способов его нарушить.
- Вы можете получить неполный, но пригодный для локального использования репозиторий, создав поверхностный клон.
- Вы можете использовать механизмы objects/info/alternates или $GIT_ALTERNATE_OBJECT_DIRECTORIES для заимствования объектов из других хранилищ объектов. Репозиторий с таким неполным хранилищем объектов не подходит для публикации для использования с тупыми транспортами, но в остальном все в порядке, если objects/info/alternates указывают на хранилища объектов, из которых он заимствован.
...

и так далее.

  • Дополнение к ответу выше.
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Артём Dev Ответ

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

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

Когда вы добавляете файлы в репозиторий Git, Git создает снимок (snapshot) текущего состояния файлов и сохраняет его в базе данных. При каждом коммите Git сохраняет новый снимок, а также информацию о том, какие файлы были изменены, добавлены или удалены.

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

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

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

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно