Как работает протокол передачи Git

Я работаю с Git больше года, и теперь я должен объяснить это другим в нашей группе. Вот почему мне нужно немного больше фона. Я прошел большую часть Книги Git в прошлом году, и недавно я продолжил с главой 10. В главе 10.6 я полностью застрял:

Давайте рассмотрим процесс http-fetch для библиотеки simplegit:

$ git clone http://server/simplegit-progit.git

Первое, что делает эта команда, это извлекает файл info / refs. Этот файл записывается командой update-server-info, поэтому вам нужно включить его в качестве перехвата после получения, чтобы транспорт HTTP работал правильно:

=> GET info/refs
ca82a6dff817ec66f44342007202690a93763949     refs/heads/master

У меня небольшой тестовый репо https://github.com/to_my/repo а также git clone работает хорошо. Но

  • Где находится папка info/refs? Я только нахожу /.git/info/exclude после clone...
  • Как я должен использовать update-server-info команда? Это как-то часть git clone?
  • Я совершенно потерян с "... именно поэтому вам нужно включить это как ловушку после получения", хотя я понимаю ловушки (я думал) и использую ловушку перед фиксацией для автоматического увеличения версии пакета.
  • Я не могу получить команду GET info/refs в работе git bash.

Извините, если вопросы глупые, но я просто не понимаю, как соединить эти части из документации.

5 ответов

Решение

Где находится папка info/refs? Я только нахожу /.git/info/exclude после клона...

Там нет такой папки (это не каталог), но это -.git/info/refs- где бы файл был, если бы там был файл.

Как мне использовать команду update-server-info? Это как-то часть git clone?

В общем, вы не должны использовать это: это только для "тупых" транспортов. "Умный" (двусторонний разговор) транспорт не нуждается в этом.

Я совершенно потерян с "... именно поэтому вам нужно включить это как ловушку после получения", хотя я понимаю ловушки (я думал) и использую ловушку перед фиксацией для автоматического увеличения версии пакета.

Если по какой-то причине вы хотите включить немые транспорты, вам нужно запустить что-то, чтобы создать или обновить несколько файлов каждый раз, когда они нуждаются в создании или обновлении. info/refs Файл должен обновляться всякий раз, когда меняются ссылки, поэтому хорошее место для запуска "чего-то" - это ловушка после получения. "Что-то" - это команда git update-server-info,

Обратите внимание, что если вы не запускаете "голое" хранилище "только для отправки" на сервере, необходимо запустить скрипт после получения git update-server-info недостаточно, поскольку коммиты и другие объекты могут быть добавлены другими способами (вручную git commitс например). В этом случае вы можете использовать, например, задание cron для создания или обновления информации о немом транспорте на основе тактовой синхронизации.

Я не могу получить команду GET info/refs в работе git bash.

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

Примечание: начиная с Git 2.18 (Q2 2018), протокол передачи git развивается с v2, который реализован.

Посмотрите коммит a4d78ce, зафиксируйте 0f1dc53, зафиксируйте 237ffed, зафиксируйте 884e586, зафиксируйте 8ff14ed, зафиксируйте 49e85e9, зафиксируйте f08a5d4, зафиксируйте f1f4d8a, зафиксируйте edc9caf, зафиксируйте 176e85c, зафиксируйте b1c2edf, закомментируйте 1aa8dde, закомментируйте 40f551e, зафиксируйте 5b872ff, коммит 230d7dd, коммит b4be741, коммит 1af8ae1 (15 марта 2018 г.) Брэндоном Уильямсом ( mbrandonw )
(Объединено Юнио С Хамано - gitster - в комитете 9bfa0f9 от 08 мая 2018 года)

Полная спецификация находится в Documentation/technical/protocol-v2.txt:

Протокол v2 улучшится по сравнению с v1 следующими способами:

  • Вместо нескольких имен служб, одна команда будет поддерживать несколько команд
  • Легко расширяемые, поскольку возможности перемещаются в их собственный раздел протокола, больше не скрываясь за NUL байт и ограничен размером pkt-line
  • Выделите другую информацию, спрятанную за NUL байты (например, строка агента в качестве возможности и symrefs могут быть запрошены с помощью 'ls-refs')
  • Ссылочная реклама будет опущена, если явно не запрошено
  • Команда ls-refs для явного запроса некоторых ссылок
  • Разработано с учетом http и stateless-rpc. С чистой семантикой сброса удаленный помощник http может просто выступать в качестве прокси

В протоколе v2 связь ориентирована на команды.
При первом обращении к серверу будет объявлен список возможностей. Некоторые из этих возможностей будут командами, которые клиент может запросить. Как только команда завершена, клиент может повторно использовать соединение и запросить выполнение других команд.

info/refs остается конечной точкой сервера для запроса клиентом, как описано в разделе HTTP Transport:

При использовании http:// или же https:// транспортный клиент делает "умным" info/refs запрос, как описано в http-protocol.txt и просит использовать v2, предоставив " version=2 " в Git-Protocol заголовок.

C: Git-Protocol: version=2
C:
C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0

Сервер v2 ответил бы:

   S: 200 OK
   S: <Some headers>
   S: ...
   S:
   S: 000eversion 2\n
   S: <capability-advertisement>

Последующие запросы затем направляются непосредственно в службу $GIT_URL/git-upload-pack, (Это работает так же для git-receive-pack).

Цель состоит в том, чтобы иметь больше возможностей:

Существует два разных типа возможностей:

  • обычные возможности, которые можно использовать для передачи информации или изменения поведения запроса, и
  • команды, которые являются основными действиями, которые хочет выполнить клиент (выборка, отправка и т. д.).

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

Клиенты НЕ ДОЛЖНЫ требовать управления состоянием на стороне сервера для правильной работы.
Это позволяет выполнять простую циклическую балансировку нагрузки на стороне сервера без необходимости беспокоиться об управлении состоянием.

В заключение:

ls-refs это команда, используемая для запроса ссылочной рекламы в v2.
В отличие от текущей справочной рекламы, ls-refs принимает аргументы, которые можно использовать для ограничения ссылок, отправляемых с сервера.

А также:

fetch это команда, используемая для получения файла пакета в версии 2
Это можно рассматривать как модифицированную версию выборки v1, в которой удалена реклама ref (так как ls-refs команда выполняет эту роль), а формат сообщения настраивается для устранения избыточности и легкого добавления будущих расширений.


После этой фиксации (10 мая) протокол V2 был официально анонсирован (28 мая) в сообщении в блоге Google " Представление протокола Git версии 2 " Брэндоном Уильямсом.

В обоих случаях:

Дополнительные функции, не поддерживаемые в базовой команде, будут объявлены в качестве значения команды в объявлении о возможностях в виде разделенного пробелами списка функций: " <command>=<feature 1> <feature 2> "


См. Также commit 5e3548e, commit ff47322, commit ecc3e53 (23 апреля 2018 г.) Брэндоном Уильямсом ( mbrandonw )
(Объединено Юнио С Хамано - gitster - в комм. 41267e9 от 23 мая 2018 г.)

serve: представить server-option возможность

Ввести " server-option "возможность протокола версии 2.
Это дает возможность будущим клиентам отправлять специфические параметры сервера в командных запросах при использовании протокола версии 2.

fetch: отправить параметры сервера при использовании протокола v2

Учат fetch опционально принять параметры сервера, указав их в командной строке через ' -o ' или же ' --server-option ".
Эти параметры сервера отправляются на удаленный конец при выполнении fetch общение с использованием протокола версии 2.

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

То же самое сделано для git ls-remote,


И протокол передачи v2 научился поддерживать частичный клон, увиденный в декабре 2017 года с Git 2.16.

Смотрите коммит ba95710, коммит 5459268 (3 мая 2018 г.) и коммит 7cc6ed2 (02 мая 2018 г.) Джонатана Тана ( jhowtan )
(Объединено Юнио С Хамано - gitster - в коммите 54db5c0, 30 мая 2018 года)

{fetch,upload}-pack: поддержка фильтра в протоколе v2

Протокол fetch-pack/upload-pack v2 был разработан независимо от параметра фильтра (используется в частичных выборках), поэтому он не включает его поддержку. Добавить поддержку для параметра фильтра.

Как и в устаревшем протоколе, сервер рекламирует и поддерживает filter " только если uploadpack.allowfilter настроен.

Как и в устаревшем протоколе, клиент продолжает с предупреждением, если " --filter"указано, но сервер не афиширует это.


Git 2.19 (Q3 2018) улучшает часть выборки протокола передачи git v2:

См. Коммит ec06283, коммит d093bc7, коммит d30fe89, коммит af1c90d, коммит 21bcf6e (14 июня 2018 г.) и коммит af00855, коммит 34c2903 (06 июня 2018 г.) от Jonathan Tan ( jhowtan )
(Объединено Юнио С Хамано - gitster - в комитете af8ac73, 02 августа 2018 г.)

fetch-pack: представить API переговорщика

Введите новые файлы fetch-negotiator.{h,c}, который содержит API, за которым абстрагируются детали согласования

fetch-pack: используйте ref adv. обрезать "есть" отправлено

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


Git 2.20 (Q4 2018) исправления git ls-remotes:

Смотрите коммит 6a139cd, коммит 631f0f8 (31 октября 2018 г.) Джеффа Кинга ( peff )
(Объединено Юнио С Хамано - gitster - в коммите 81c365b, 13 ноября 2018 г.)

git ls-remote $there foo был прерван недавним обновлением протокола v2 и перестал показывать ссылки, совпадающие с ' foo это не refs/{heads,tags}/foo, который был исправлен.


И Git 2.2O исправляет git fetch, который был немного свободен в разборе ответов с другой стороны при разговоре по протоколу v2.

См. Коммит 5400b2a (19 октября 2018 г.) Джонатана Тана ( jhowtan )
(Объединено Юнио С Хамано - gitster - в комитете 67cf2fa, 13 ноября 2018 г.)

fetch-pack: быть более точным в разборе ответа v2

Каждый раздел в ответе протокола v2 сопровождается либо DELIM пакет (с указанием большего количества последующих разделов) или FLUSH пакет (с указанием нет, чтобы следовать).

Но при разборе acknowledgments " раздел, do_fetch_pack_v2() является либеральным в принятии обоих, но определяет, продолжать читать или нет, основываясь исключительно на содержании " acknowledgments раздел, а не о том DELIM или же FLUSH был прочитан.

Нет проблем с совместимым с протоколом сервером, но это может привести к путанице в сообщениях об ошибках при обмене данными с сервером, который обслуживает неожиданные дополнительные разделы. Рассмотрим сервер, который отправляет new-section " после " acknowledgments ":

  • клиент пишет запрос
    • клиент читает раздел "подтверждений", который не содержит "готов", затем DELIM
    • поскольку не было "готово", клиент должен продолжить переговоры и пишет запрос
    • клиент читает new-section "и сообщает конечному пользователю" ожидаемые "подтверждения", полученные " new-section ""

Для человека, отлаживающего соответствующие реализации Git, сообщение об ошибке сбивает с толку " new-section "был получен не в ответ на последний запрос, а на первый.

Одним из решений является всегда продолжать читать после DELIM, но в этом случае мы можем сделать лучше.

Из протокола мы знаем, что:

  • "готово" означает, что, по крайней мере, секция packfile идет (следовательно, DELIM) и это:
  • "готово" означает, что разделы не должны следовать (следовательно, FLUSH).

Так учите process_acks() чтобы обеспечить это.

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

Во всяком случае, info/refs Файл будет существовать только на удаленном сервере, предназначенном для доступа по HTTP с тупым сервером. Вы, вероятно, не найдете его (и не нуждаетесь в нем) в своем локальном репо. (Дистанционный в этом сценарии, вероятно, голый репозиторий, кстати, так info будет в корне репо, так как голые репозитории не имеют рабочего дерева и размещают файлы, которые вы привыкли видеть в .git вместо корня.)

Если наш пульт находится в чем-то вроде github, tfs и т. Д., То вам не нужно беспокоиться об этом, так как сервер будет отлично справляться. Я предполагаю, что если вы обслуживаете репозиторий как статический контент со старого веб-сервера, это будет иметь значение, и вам придется настроить хук.

Большинство пользователей никогда не будут использовать или видеть update-server-info команда; как следует из его названия, он предназначен для репозиториев на стороне сервера - удаленных - чтобы компенсировать отсутствие git-осведомленного HTTP-сервера.

Хук post-receive вызывается после получения push; поэтому в сценарии с тупым сервером вы устанавливаете эту ловушку на пульте, чтобы при нажатии на нее она отвечала обновлением определенной информации (например, файла refs).

GET команда, которую вы просматриваете, является HTTP-командой, запускаемой при необходимости клиентом git при выполнении выборки.

В Git 2.30 (Q1 2021) транспортный уровень был обучен опционально обмениваться идентификатором сеанса, назначенным trace2 подсистема во время транзакций выборки / отправки.

См. Commit a2a066d , commit 8c48700, commit 8295946, commit 1e905bb, commit 23bf486, commit 6b5b6e4, commit 8073d75, commit 791e1ad, commit e97e1cf, commit 81bd549, commit f5cdbe4 (11 Nov 2020) by Josh Steadmon ( <tcode id="554772"></tcode>) .
(Объединено в фиксации 01b8886, 8 декабря 2020 г.)

<tcode id="554774"></tcode>: рекламировать идентификатор сеанса в возможностях версии 2

Подписано: Джош Стедмон

Если transfer.advertiseSID имеет значение true, объявить идентификатор сеанса сервера для всех соединений протокола v2 с помощью новой возможности идентификатора сеанса.

И:

<tcode id="554775"></tcode>: новая возможность рекламировать идентификаторы сессий

Подписано: Джош Стедмон

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

technical/protocol-capabilitiesтеперь включает в свою справочную страницу :


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

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

technical/protocol-v2теперь включает в свою справочную страницу :

session-id=<session id>

       
The server may advertise a session ID that can be used to identify this process
across multiple requests. The client may advertise its own session ID back to
the server as well.

Session IDs should be unique to a given process. They must fit within a
packet-line, and must not contain non-printable or whitespace characters. 

Другое новое исправление в Git 2.30 (первый квартал 2021 г.):

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

См. Commit 6031af3 (30 ноября 2020 г.) Рене Шарфе ( <tcode id="554784"></tcode>) .
(Объединено в коммите eae47db, 8 декабря 2020 г.)

: игнорировать недопустимые файлы блокировки пакета

Подписано: Рене Шарф
Рецензент: Тейлор Блау

9da69a6539 (" fetch-pack: support more than one pack lockfile ", 2020-06-10, Git v2.28.0-rc0 - слияние, перечисленное в пакете № 5) начал использовать для имен файлов блокировки пакетов вместо одного указателя строки.
Это убрало проверку из Кроме того, это функция, которая в конечном итоге удаляет эти файлы блокировки и освобождает строки их имен.

index_pack_lockfile()может вернуться, если ему не нравится содержимое, которое он читает из переданного ему файлового дескриптора.
Объявлено, что unlink(2) не принимает указатели (по крайней мере, с glibc).
Undefined Behavior Sanitizer вместе с Address Sanitizer обнаруживает случай, когда имя файла блокировки передается в unlink(2) с помощью transport_unlock_pack() в t1060 ( make SANITIZE=address,undefined; cd t; ./t1060-object-corruption.sh).

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


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

Var Arnfjör Bjarmason описывает в этой беседе сообщения об ошибках, которые вы можете увидеть:

      $ git status
    error: graph version 2 does not match version 1
$ ~/g/git/git --exec-path=$PWD status
    error: commit-graph version 2 does not match version 1
    On branch master
    [...]

В Git 2.31 (первый квартал 2021 г.) граф фиксации научился использовать исправленные даты фиксации вместо номера поколения, чтобы помочь в обходе топологической версии, чтобы отличаться от протокола v1.

См. Commit 5a3b130 , commit 8d00d7c, commit 1fdc383, commit e8b6300, commit c1a0911, commit d7f9278, commit 72a2bfc, commit c0ef139, commit f90fca6, commit 2f9bbb6, commit e30c5ee (16 Jan 2021) by Abhishek Kum <tcode id="554800"></tcode>) .
(Объединено Junio ​​C Hamano -- в фиксации 8b4701a, 17 февраля 2021 г.)

: реализовать блок данных генерации

Подписано: Абхишек Кумар
Рецензент: Тейлор Блау
Рецензент: Деррик Столи

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

Мы собираемся представить новый чанк под названием Generation DATa chunk (или GDAT).
GDAT будет хранить исправленные смещения дат коммиттера, тогда как CDAT по-прежнему будет хранить топологический уровень.

Старый Git не понимает чанк GDAT и игнорирует его, считывая топологические уровни из CDAT.
Новый Git может анализировать GDAT и использовать номера нового поколения, возвращаясь к топологическим уровням при отсутствии фрагмента GDAT (как это произошло бы с графом фиксации, написанным старым Git).

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

Мы представляем новый блок графика фиксации , Generation Data OVerflow ('GDOV') для хранения исправленных дат фиксации для коммитов со смещениями, превышающими GENERATION_NUMBER_V2_OFFSET_MAX.

Если смещение больше, чем GENERATION_NUMBER_V2_OFFSET_MAX, мы устанавливаем MSB смещения, а другие биты сохраняют позицию исправленной даты фиксации в блоке GDOV, аналогично тому, как поддерживается Extra Edge List.

Мы тестируем код, связанный с переполнением, со следующей историей репо:

                 F - N - U
         /         \
U - N - U            N
         \          /
          N - F - N

Где:

  • коммиты, обозначенные U, имеют дату коммиттера равную нулю секунд с эпохи Unix,
  • коммиты, обозначенные N, имеют дату коммиттера 1112354055 (дата коммиттера по умолчанию для набора тестов) секунд с эпохи Unix и
  • коммиты, обозначенные F, имеют дату коммиттера (2 ^ 31 - 2) секунды с эпохи Unix.

Наибольшее наблюдаемое смещение составляет 2 ^ 31, достаточно большое для переполнения.

Это обратно совместимо с v1, потому что:

: используйте поколение v2, только если вся цепочка

Подписано: Деррик Столи.
Подписано: Абхишек Кумар. Автор обзора
: Тейлор Блау.
Автор отзыва: Деррик Столи.

Поскольку существуют выпущенные версии Git, которые понимают номера поколений в блоке CDAT графа фиксации, но не понимают блок GDAT, возможен следующий сценарий:

  1. «Новый» Git записывает граф фиксации с фрагментом GDAT.
  2. «Старый» Git пишет сверху разделенный граф фиксации без блока GDAT.

Если каждый уровень разбитого графа фиксации обрабатывается независимо, как это было до этого коммита, при этом Git проверяет только текущий уровень для chunk_generation_dataуказатель, коммиты на нижнем уровне (один с GDAT) должны были исправить дату фиксации как номер их поколения, а коммиты на верхнем уровне будут иметь топологические уровни в качестве своего поколения.
Скорректированные даты фиксации обычно имеют гораздо большие значения, чем топологические уровни.
Это означает, что если мы возьмем две фиксации, одну из верхнего уровня и одну достижимую из него на нижнем уровне, то ожидание того, что поколение родителя меньше, чем порождение дочернего, будет нарушено.

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

В этом случае эта проблема может проявиться как проблема производительности, особенно с чем-то вроде " <tcode id="554808"></tcode>" ( man), так как низкие номера генерации заставят очередь с установленной степенью пройти все коммиты на нижнем уровне, прежде чем разрешить очереди топо-порядка записывать что-либо на вывод (в зависимости от размера верхнего уровня).

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

При перезаписи слоев используется аналогичный подход: если существует самый верхний уровень ниже набора перезаписываемых слоев (в цепочке разделенного графа фиксации) и он не содержит фрагмент GDAT, то результат перезаписи также не имеет фрагментов GDAT.

Что такое « исправленная дата фиксации »?

: реализовать исправленную дату фиксации

Подписано: Абхишек Кумар
Рецензент: Тейлор Блау
Рецензент: Деррик Столи

Когда большая часть подготовки сделана, давайте внедрим исправленную дату фиксации.

Исправлены даты фиксации для фиксации определяется как :

  • Коммит без родителей (корневой коммит) исправил дату фиксации, равную дате его коммиттера.
  • Для фиксации по крайней мере с одним родителем исправленная дата фиксации равна максимальной из даты фиксации и на один больше, чем самая большая исправленная дата фиксации среди его родителей.

В качестве особого случая корневой коммит с нулевой отметкой времени (01.01.1970 00:00:00Z) исправил дату фиксации на единицу, чтобы можно было отличить от GENERATION_NUMBER_ZERO (то есть не вычисляемая скорректированная дата фиксации).

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

Для сохранения исправленной даты фиксации требуется sizeof(timestamp_t) байтов, что в большинстве случаев составляет 64 бита (uintmax_t).
Однако исправленные смещения даты фиксации можно безопасно хранить, используя только 32-битные.
Это вдвое уменьшает размер блока GDAT, что примерно на 6% меньше размера файла графика фиксации.

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

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

И это улучшает характеристики:

<tcode id="554814"></tcode>: использовать исправленные даты фиксации в

Подписано: Абхишек Кумар
Рецензент: Тейлор Блау
Рецензент: Деррик Столи

091f4cf (" commit: не использовать номера поколений, если они не нужны », 2018-08-30, Git v2.19.0-rc2 - merge) изменено paint_down_to_common()использовать даты фиксации вместо номеров поколений v1 (топологические уровни), поскольку производительность снижается на определенных топологиях.
С внедрением номера поколения v2 (исправленные даты фиксации) нам больше не нужно полагаться на даты фиксации и можно использовать номера поколений.

Например, команда <tcode id="554818"></tcode>( man) v4.8 v4.9 в репозитории Linux проходит 167468 коммитов, принимая 0,135 с для даты коммиттера и 167496 коммитов, принимая 0,157 с для исправленной даты коммиттера соответственно.

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

Поскольку это уже вызывает проблемы (как указано в 859fdc0 (: define GIT_TEST_COMMIT_GRAPH, 2018-08-29, Git v2.20.0-rc0 - слияние указано в пакете №1), мы отключаем граф фиксации в t6404-recursive-merge.


Затем, все еще с Git 2.31 (первый квартал 2021 года), исправьте инкрементное обновление файла графика фиксации вокруг исправленных данных даты фиксации.

См. Фиксацию bc50d6c, фиксацию fde55b0, фиксацию 9c2c0a8, фиксацию 448a39e (2 февраля 2021 г.) и фиксацию 90cb1c4, фиксацию c4cc083 (1 февраля 2021 г.) Деррик Столи ( <tcode id="554821"></tcode>) .
(Слияние Junio ​​C Hamano - <tcode id="554773"></tcode>- в коммите 5bd0b21, 17 февраля 2021 г.)

: вычислять поколения отдельно

Подписано: Деррик Столи
Рецензент: Тейлор Блау

В compute_generation_numbers()был введен 3258c66 (": вычислить номера поколений", 2018-05-01, Git v2.19.0-rc0 - слияние перечислено в пакете №1) для вычисления того, что теперь известно как " топологические уровни ".
Они по-прежнему хранятся в файле диаграммы фиксации для обеспечения совместимости, в то время как c1a0911 («: реализовать исправленную дату фиксации», 2021-01-16, Git v2.31.0 - слияние указано в пакете № 9) обновил метод, чтобы также вычислить новая версия номеров поколений: исправлена ​​дата фиксации .

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

В частности, topo_level slab используется для хранения топологических уровней во всех случаях, но commit_graph_data_at(c)->generationчлен хранит разные значения в зависимости от состояния существующего файла графика фиксации. * Если в существующем файле графика фиксации есть фрагмент «GDAT», то эти значения представляют собой исправленные даты фиксации. * Если в существующем файле графика фиксации нет фрагмента «GDAT», то эти значения фактически являются топологическими уровнями.

Эта проблема возникает только при обновлении существующего файла графика фиксации до файла, содержащего блок «GDAT».
Текущее изменение не решает эту проблему обновления, но разделение реализации на две части здесь помогает в этом процессе, который последует за следующим изменением.

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

И:

<tcode id="554802"></tcode>: будьте особенно осторожны со смешанными поколениями

Подписано: Деррик Столи
Рецензент: Тейлор Блау

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

При вычислении номеров поколений для нового файла графа фиксации, который ожидает добавить generation_data чанк с исправленными датами фиксации, нам нужно убедиться, что член 'генерации' commit_graph_data struct устанавливается в ноль для этих коммитов.

К сожалению, отказ от использования топологического уровня для номера поколения, когда исправленные даты фиксации недоступны, наносит нам здесь вред: анализ фиксирует уведомления, которые read_generation_data ложно и заполняет «поколение» топологическим уровнем.

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

Другой аспект протокола передачи git - управление пакетами, включая ACK при запросе "HAVE":

До Git 2.27 (второй квартал 2020 г.) серверная часть протокола v2 для обслуживания "git clone" а также "git fetch"не был готов к обнаружению пакетов с разделителями в неожиданных местах, что привело к сбою.

См. Commit cacae43 (29 марта 2020 г.) и commit 4845b77, commit 88124ab (27 марта 2020 г.) Джефф Кинг (peff).
(Слияние Junio ​​C Hamano -gitster- в коммите 5ee5788, 22 апр 2020 г.)

upload-pack: обрабатывать неожиданные пакеты с разделителями

Подписано: Джефф Кинг

При обработке списка аргументов для v2 ls-refs или fetch команда, мы зацикливаемся так:

while (packet_reader_read(request) != PACKET_READ_FLUSH) {
        const char *arg = request->line;
 ...handle arg...
}

для чтения и обработки пакетов, пока мы не увидим сброс. Здесь скрыто предположение, что все, кромеPACKET_READ_FLUSHпредоставит нам допустимые пакетные данные для чтения. Но это неправда;PACKET_READ_DELIM или PACKET_READ_EOF покинет >packet->line как NULL, и мы segfault попытаемся это рассмотреть.

Вместо этого мы должны следовать более осторожной модели, продемонстрированной на стороне клиента (например, в process_capabilities_v2): продолжайте цикл до тех пор, пока мы получим нормальные пакеты, а затем убедитесь, что мы вырвались из цикла из-за реального сброса. Это устраняет segfault и правильно диагностирует любой неожиданный ввод от клиента.


До Git 2.27 (второй квартал 2020 г.) протокол выгрузки v2 отказался слишком рано, не обнаружив общего предка, что приводило к бесполезной выборке из форка проекта.

Это было исправлено, чтобы соответствовать поведению протокола v0.

См. Commit 2f0a093, commit 4fa3f00, commit d1185aa (28 апреля 2020 г.) Джонатан Тан (jhowtan).
(Слияние Junio ​​C Hamano -gitster- в коммите 0b07eec, 01 мая 2020 г.)

fetch-pack: в протоколе v2, in_vain только после ACK

Подписано: Джонатан Тан
Рецензент: Джонатан Нидер

При выборке Git прекращает переговоры, когда он отправил хотя бы MAX_IN_VAIN(что составляет 256) "имеют" строки, не имея ни одной из них ACK-ed.
Но это должно сработать только после первого ACK, так какpack-protocol.txt говорит:

Однако ограничение в 256 включается в реализации канонического клиента только в том случае, если мы получили хотя бы один "ACK %s continue" во время предыдущего цикла. Это помогает убедиться, что найден хотя бы один общий предок, прежде чем мы полностью сдадимся.

Путь кода для протокола v0 учитывает это, но не протокола v2, что приводит к более коротким раундам согласования, но значительно большему количеству файлов пакетов.
Научите кодовый путь для протокола v2 проверять этот критерий только после получения хотя бы одного ACK.


В результате работы в 2.27 (где v2 не было значением по умолчанию), v2 снова используется по умолчанию с 2.28.

См. Commit 3697caf:

config: пусть feature.experimental подразумевает protocol.version=2

Git 2.26 использовал протокол v2 в качестве протокола по умолчанию, но вскоре после выпуска пользователи заметили, что код согласования протокола v2 был склонен к сбою при выборке с некоторых пультов, которые намного опережают другие (например, linux-next.git против Линуса linux.git).
Это было исправлено 0b07eec (ветвь слияния 'jt/v2-fetch-nego-fix',2020-05-01, Git v2.27.0-rc0), но чтобы быть осторожными, мы используем протокол v0 по умолчанию в версии 2.27, чтобы выиграть время на случай появления любых других непредвиденных проблем.

С этой целью давайте позаботимся о том, чтобы пользователи, запрашивающие передовые технологии с помощью флага feature.experimental , получили протокол v2.
Таким образом, мы можем получить опыт работы с более широкой аудиторией для новой версии протокола и быть более уверенными, когда придет время включить ее по умолчанию для всех пользователей в какой-либо будущей версии Git.

Примечание по реализации: этого нет в остальной части feature.experimental варианты в repo-settings.c потому что они привязаны к объекту репозитория, тогда как этот путь кода используется для таких операций, как "git ls-remote"которые не требуют репозитория.


В Git 2.28 (третий квартал 2020 г.) протокол "выборки / клонирования" был обновлен, чтобы сервер мог указывать клиентам получать предварительно упакованные файлы пакетов в дополнение к данным упакованных объектов, передаваемых по сети.

См. Фиксацию cae2ee1 (15 июня 2020 г.) Рамзи Джонса (``).
См. Commit dd4b732, commit 9da69a6, commit acaaca7, commit cd8402e, commit fd194dd, commit 8d5d2a3, commit 8e6adb6, commit eb05349, commit 9cb3cab (10 Jun 2020) by Jonathan Tan (jhowtan).
(Слияние Junio ​​C Hamano -gitster- в коммите 34e849b, 25 июня 2020 г.)

fetch-pack: поддержка более одного файла блокировки пакета

Подписано: Джонатан Тан

Всякий раз, когда выборка приводит к загрузке файла пакета, создается файл.keep, так что файл пакета может быть сохранен (скажем, из запущенного "git repack") до тех пор, пока ссылки не будут записаны со ссылкой на содержимое файла пакета.

В последующем патче успешная выборка с использованием протокола v2 может привести к созданию более одного файла.keep. Поэтому учитеfetch_pack() и транспортный механизм для поддержки нескольких файлов.keep.

Примечания по реализации:

  • builtin/fetch-pack.c обычно не генерирует .keepфайлы, поэтому на него не повлияют эти или будущие изменения.
    Однако у него есть недокументированный "--lock-pack"функция, используемая remote-curl.c при реализации "fetch"команда удаленного помощника.
    В соответствии с протоколом удаленного помощника, только один"lock"будет когда-либо записана; остальное приведет к предупреждению в stderr.
    Однако на практике предупреждения никогда не будут записаны, потому что remote-curl.c "fetch"используется только для протокола v0/v1 (который не создает несколько .keepфайлы). (Протокол v2 использует команду "stateless-connect", а не "fetch"команда.)

  • connected.c имеет оптимизацию, заключающуюся в том, что проверки подключения по ссылке не должны выполняться, если целевой объект находится в пакете, который известен как самодостаточный и связанный. Если существует несколько файлов пакетов, эта оптимизация больше не может быть выполнена.

Ср. Packfile URI

Эта функция позволяет серверам обслуживать часть своего ответа пакетного файла как URI. Это позволяет проектировать серверы, которые улучшают масштабируемость пропускной способности и использования ЦП (например, за счет обслуживания некоторых данных через CDN), и (в будущем) обеспечивает некоторую степень возобновляемости для клиентов.

Эта функция доступна только в версии протокола 2.

Другие вопросы по тегам