каковы разные версии формата репозитория (для параметра core.repositoryFormatVersion) в git?

Я заметил параметр по умолчанию в git core.repositoryFormatVersion, который по умолчанию равен 0, но что такое «версии формата репозитория» и какую функциональную разницу они имеют?


person Alexander Bird    schedule 03.03.2011    source источник
comment
Четыре с половиной года спустя Git 2.7 (ноябрь 2015 г.) наконец документирует core.repositoryFormatVersion, и это... довольно интересно. См. мой ответ ниже   -  person VonC    schedule 01.11.2015


Ответы (2)


git 2.7 (ноябрь 2015 г.) добавляет гораздо больше информации в новый Documentation/technical/repository-version.txt.
См. commit 067fbd4, коммит 00a09d5 (23 июня 2015 г.) от Джефф Кинг (peff).
(объединено Хунио С. Хамано -- gitster -- в коммит fa46579 , 26 октября 2015 г.)

Теперь вы можете определять расширения и использовать core.repositoryformatversion в качестве маркера, чтобы сигнализировать о существовании указанных расширений, вместо того, чтобы увеличивать сам номер версии Git:

Если бы мы повышали версию репозитория для каждого такого изменения, то любая реализация, понимающая версию X, также должна была бы понимать X-1, X-2 и т. д., даже если несовместимости могут быть в ортогональных частях системы, а в противном случае Причина, по которой мы не можем реализовать одно без другого (или, что более важно, пользователь не может использовать одну функцию без другой, взвешивая компромисс совместимости только для этой конкретной функции).

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

Выдержки из документа:

Каждый репозиторий git отмечен числовой версией в ключе core.repositoryformatversion его файла config. Эта версия определяет правила работы с данными репозитория на диске.

Обратите внимание, что это относится только к прямому доступу к содержимому диска репозитория.
Старый клиент, который понимает только формат 0, может по-прежнему подключаться через git:// к репозиторию, используя формат 1, если серверный процесс понимает формат 1.

Версия 0

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

Версия 1

Этот формат идентичен версии 0 со следующими исключениями:

  1. При чтении переменной core.repositoryformatversion реализация git, поддерживающая версию 1, ДОЛЖНА также читать любые ключи конфигурации, найденные в разделе extensions файла конфигурации.
  1. Если в репозитории версии 1 указаны какие-либо ключи extensions.*, которые не были реализованы работающим git, операция НЕ ДОЛЖНА выполняться. Точно так же, если реализация не понимает значение любого известного ключа, операция НЕ ДОЛЖНА продолжаться.

Это можно использовать, например:

  • чтобы сообщить git, что объекты не следует обрезать только на основе достижимости подсказок ref (например, потому что у него есть clone --shared дочерние элементы)
  • что ссылки хранятся в формате, отличном от обычных каталогов ссылок и упакованных ссылок

Это действительно оригинальный подход ко всей политике номеров версий и ее независимая политика.

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

Например, если пользователь решит использовать хранилище базы данных для ссылок, он может установить конфигурацию extensions.refbackend в db.
Старые версии git не будут понимать формат 1 и залог.
Версии git, которые понимают 1, но не знающие о refbackend, или которые знают о refbackend, но не знают о бэкенде db, откажутся запускаться.
Это, конечно, раздражает, но намного лучше, чем альтернатива заявлениям об отсутствии рефов в репозиторий или запись в место, которое другие реализации не будут читать.

Обратите внимание, что здесь мы определяем правила только для формата 1.
Мы никогда не пишем формат 1 сами; это инструмент, предназначенный для использования пользователями и будущими расширениями для обеспечения безопасности старых реализаций.


В качестве первого расширения у вас будет git 2.7 preciousObjects:

Если это расширение используется в репозитории, то не должны выполняться никакие операции, которые могут удалить объекты из хранилища объектов. Это может быть полезно, если вы делитесь этим хранилищем с другими репозиториями, чьи ссылки вы не видите.

В документе упоминается:

Когда для ключа конфигурации extensions.preciousObjects установлено значение true, объекты в репозитории НЕ ДОЛЖНЫ удаляться (например, с помощью git-prune или git repack -d).

То есть:

Например, если вы делаете:

$ git clone -s parent child
$ git -C parent config extensions.preciousObjects true
$ git -C parent config core.repositoryformatversion 1

теперь у вас есть дополнительная безопасность при запуске git в родительском репозитории.
Prunes и repacks будут выведены с ошибкой, а git gc пропустит эти операции (продолжит паковать ссылки и выполнять другие операции, не связанные с объектами).
Старые версии git при запуске в репозитории будут давать сбои при каждой операции.

Обратите внимание, что мы не устанавливаем расширение preciousObjects по умолчанию при выполнении clone -s, так как это нарушает обратную совместимость. Это решение, которое пользователь должен принять явно.


Обратите внимание, что этот core.repositoryformatversion бизнес устарел. Действительно старый. commit ab9cb76, ноябрь 2005 г., Git 0.99.9l.
Это было сделано изначально для версии db:

Это делает версию репозитория init-db доступной.

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


Git 2.22 (второй квартал 2019 г.) позволит избежать утечек вокруг структуры repository_format.

См. commit e8805af (28 февраля 2019 г.) и commit 1301997 (22 января 2019 г.), автор Мартин Огрен (``).
(Объединено Юнио С Хамано - - gitster -- в commit 6b5688b, 20 марта 2019 г.)

setup: исправить утечку памяти с помощью struct repository_format

После того, как мы настроили struct repository_format, ему принадлежат различные части выделенной памяти. Затем мы либо используем эти элементы, потому что решили, что хотим использовать формат репозитория-кандидата, либо отбрасываем кандидата/рабочее пространство.
В первом случае мы передаем право собственности на память нескольким глобальным переменным. В последнем случае мы просто молча удаляем структуру и в конечном итоге получаем утечку памяти.

Введите макрос инициализации REPOSITORY_FORMAT_INIT и функцию clear_repository_format(), которые будут использоваться на каждой стороне read_repository_format(). Чтобы иметь четкое и простое владение памятью, разрешите всем пользователям struct repository_format дублировать строки, которые они берут из него, а не красть указатели.

Вызовите clear_...() в начале read_...() вместо того, чтобы просто обнулить структуру, поскольку иногда мы входим в функцию несколько раз.
Таким образом, важно инициализировать структуру перед вызовом read_...(), поэтому задокументируйте это.
Это также важно, потому что мы можем даже не вызывать read_...() до вызова clear_...(), см., например, builtin/init-db.c.

Научите read_...() очищать структуру при ошибке, чтобы она возвращалась в безопасное состояние, и задокументируйте это. (В setup_git_directory_gently() мы смотрим на repo_fmt.hash_algo, даже если repo_fmt.version равно -1, чего мы на самом деле не должны были делать в соответствии с API. После этой фиксации это нормально.)


В Git 2.28 (3 квартал 2020 г.) сама среда выполнения может автоматически обновлять версию формата репозитория, например, при неполной выборке.

См. коммит 14c7fa2, коммит 98564d8, Синь Ли (livid).
(объединено Хунио C Хамано -- gitster -- в коммит 1033b98, 29 июня 2020 г.)

fetch: разрешить добавление фильтра после первоначального клонирования

Подписано: Синь Ли

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

Без этого патча пользователи могут сделать частичный клон, отредактировав конфигурацию репозитория, чтобы преобразовать удаленное устройство в промисор, например:

git config core.repositoryFormatVersion 1
git config extensions.partialClone origin   
git fetch --unshallow --filter=blob:none origin

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

Обратите внимание, что это изменение не изменяет существующее поведение Git, которое распознает параметр extensions.partialClone без изменения repositoryFormatVersion.


Предупреждение: в 2.28-rc0 мы исправили ошибку, из-за которой некоторые расширения репозитория по ошибке учитывались даже в репозиториях версии 0 (эти переменные конфигурации в пространстве имен extensions.* должны были иметь особое значение в репозиториях, номера версий которых равны 1 или выше), но это было слишком большое изменение.

См. коммит 62f2eca, коммит 1166419 (15 июля 2020 г.), автор Джонатан Нидер (artagnon).
(Объединено Junio ​​C Hamano -- gitster -- в commit d13b7f2, 16 июля 2020 г.)

Revert "check_repository_format_gently(): отказаться от расширений для старых репозиториев.

Отчет: Йоханнес Шинделин
Подпись: Джонатан Нидер

Это возвращает фиксацию 14c7fa269e42df4133edd9ae7763b678ed6594cd.

Поле core.repositoryFormatVersion было введено в ab9cb76f661 (проверка версии формата репозитория., 2005-11- 25, Git v0.99.9l -- слияние), предоставляя долгожданный шаг вперед совместимость, благодаря долгожданному анализу Мартина Атукунды.

Семантика проста: репозиторий с core.repositoryFormatVersion равным 0 должен быть понятен для всех активно используемых реализаций Git; и реализации Git должны выдавать ошибки раньше, чем пытаться воздействовать на репозитории Git с более высокими значениями core.repositoryFormatVersion, представляющими новые форматы, которые они не понимают.

Новый формат репозитория не нужно было определять до 00a09d57eb8 (введите форму расширений core.repositoryformatversion , 2015-06-23).

Это предоставило более тонкий механизм расширения для репозиториев Git.

В репозитории со значением core.repositoryFormatVersion, равным 1, реализации Git могут работать с параметрами extensions.*, которые изменяют интерпретацию репозитория.

В формате репозитория версии 1 нераспознанные настройки расширений приводят к ошибке Git.

Что произойдет, если пользователь установит параметр расширения, но забудет увеличить версию формата репозитория до 1?
В этом случае параметры расширения все равно распознаются; Хуже того, нераспознанные настройки расширений не вызывают ошибку Git.

Таким образом, объединение версии 0 формата репозитория с настройками расширений в некотором смысле дает худшее из обоих миров.

Чтобы исправить эту ситуацию, начиная с 14c7fa269e4 (check_repository_format_gently(): отказ от расширений для старых репозиториев, 2020-06 -05) Вместо этого Git игнорирует расширения в режиме v0. Таким образом, репозитории v0 получают историческое (до 2015 года) поведение и поддерживают совместимость с реализациями Git, которые не знают о формате v1.

К сожалению, пользователи уже использовали такую ​​конфигурацию, и такое изменение поведения стало для многих неожиданностью:

  • пользователи git config --worktree, которые последовали его совету по включению extensions.worktreeConfig (без увеличения версии формата репозитория), обнаружат, что их конфигурация рабочего дерева больше не действует.
  • такие инструменты, как copybara[*], которые установили extensions.partialClone в существующих репозиториях (без увеличения версии формата репозитория), обнаружат, что этот параметр больше не действует.

Поведение, представленное в 14c7fa269e4, могло бы быть хорошим поведением, если бы мы путешествовали в прошлое к 2015, но мы слишком поздно.

Я почему-то думал, что это то, что было реализовано изначально, и что оно регрессировало.

Приносим извинения за то, что не провели исследование, когда 14c7fa269e4 находился в разработке.

Вернемся к поведению, которое у нас было с 2015 года: всегда действовать с настройками extensions.*, независимо от версии формата репозитория.

Пока мы здесь, включите несколько тестов, чтобы описать влияние на путь кода версии репозитория обновления.

[*] https://github.com/google/copybara/commit/ca76c0b1e13c4e36448d12c2aba4a5d6e98fa5d6e97>

person VonC    schedule 01.11.2015

Это для будущей совместимости — если разработчики git когда-нибудь сочтут необходимым изменить способ хранения репозиториев на диске, чтобы включить какую-то новую функцию, то они могут сделать обновленные репозитории core.repositoryformatversion из 1. Затем более новые версии git, которые знают об этом новом формате, запускают код для работы с ним, а более старые версии git, которые этого не делают, изящно выдают ошибку "Expected git repo version <= 0, found 1. Please upgrade Git".

На данный момент единственная определенная или признанная версия формата репо — это 0, что означает формат, который использовался в каждой общедоступной версии git.

person hobbs    schedule 03.03.2011
comment
Обратите внимание, что Git 2.7 (ноябрь 2015 г., четыре с половиной года спустя) наконец документирует core.repositoryFormatVersion. См. мой ответ ниже - person VonC; 01.11.2015