Можно ли согласованно управлять несколькими репозиториями?

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

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

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

5 ответов

Решение

Не существует встроенного способа иметь дело с несколькими репозиториями одновременно, и если вы подумаете о распределенной природе git, на самом деле нет ничего, кроме социального соглашения, которое может это определить. (Подумайте, что если кто-то вытянет вас из одного хранилища, а другой - из другого - может ли у вас быть такая согласованность?)

Вы можете найти такой инструмент, как mr, который работает с несколькими репозиториями одновременно, полезный.

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

Если ваш код на самом деле не так тесно связан, то отбросьте понятие "ветвление должно быть в одно и то же время", и вы станете счастливее.

Вы можете использовать инструмент репо: https://gerrit.googlesource.com/git-repo/

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

Нет встроенного способа работать с несколькими репозиториями одновременно.

Но будет.

Git 2.27 (второй квартал 2020 г.) прокладывает путь с помощью "git update-ref --stdin"который выучил несколько новых глаголов, чтобы позволить пользователю более явно управлять транзакциями обновления ссылок.

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

См. Commit e48cf33, commit 94fd491, commit de0e0d6, commit 804dba5, commit 5ae6c5a, commit a65b8ac (2 апреля 2020 г.) и commit bd021f3, commit faa35ee, commit edc3069 (30 марта 2020 г.) Патрик Стейнхардт (pks-t).
(Слияние Junio ​​C Hamano -gitster- в коммите d2ea03d, 29 апр 2020 г.)

update-ref: реализовать интерактивную обработку транзакций

Подписано: Патрик Стейнхардт

В git-update-ref команда может обрабатывать транзакции в очереди прямо сейчас только через свой "--stdin", но пользователи не могут обработать транзакцию более явным образом.

Например, в реплицированном сценарии можно представить себе координатора, который порождает git-update-ref для нескольких репозиториев, и только если все согласятся, что обновление возможно, координатор отправит фиксацию.

Такой транзакционный сеанс может выглядеть как

> start
< start: ok
> update refs/heads/master $OLD $NEW
> prepare
< prepare: ok
# All nodes have returned "ok"
> commit
< commit: ok

или:

> start
< start: ok
> create refs/heads/master $OLD $NEW
> prepare
< fatal: cannot lock ref 'refs/heads/master': reference already exists
# On all other nodes:
> abort
< abort: ok

Чтобы разрешить такие транзакционные сеансы, этот коммит вводит четыре новые команды для git-update-ref, который соответствует тем, которые у нас уже есть внутри, за исключением "start":

  • start: начать новую транзакцию
  • prepare: подготовить транзакцию, то есть попытаться заблокировать все ссылки и убедиться, что их текущее значение соответствует ожидаемому
  • commit: явно зафиксировать сеанс, то есть обновить ссылки, чтобы они соответствовали их новому ожидаемому состоянию
  • abort: прервать сеанс и откатить все изменения

По дизайну, git-update-refзафиксирует, как только будет закрыт стандартный ввод.
Хотя это нормально в нетранзакционном мире, это определенно неожиданно в транзакционном мире.
Из-за этого, как только будет использована любая из новых транзакционных команд, значение по умолчанию изменится на прерывание без явного "commit".
Чтобы избежать гонки между обновлениями в очереди и первым"prepare"который начинает транзакцию,"start"добавлена ​​команда для запуска явной транзакции.

Добавьте несколько тестов, чтобы проверить эту новую функциональность.


Этот встроенный способ работы с несколькими репозиториями одновременно продолжается в Git 2.28 (Q3 2020) и новой ловушке.

См. Коммит 6754159 (19 июня 2020 г.) Патрика Стейнхардта (pks-t).
(Слияние Junio ​​C Hamano -gitster- в коммите 33a22c1, 06 июл 2020)

refs: реализовать перехватчик ссылочной транзакции

Подписано: Патрик Стейнхардт

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

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

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

Вышеупомянутый сценарий является мотивацией для новой ловушки "ссылочная транзакция", которая напрямую касается механизма ссылочной транзакции Git.

Ловушка получает в качестве параметра текущее состояние, в которое была перемещена транзакция ("prepared","committed" или "aborted") и получает через свой стандартный ввод все обновления ссылок в очереди.

В то время как код выхода игнорируется в состояниях "зафиксировано" и "прервано", ненулевой код выхода в "подготовленном" состоянии приведет к преждевременному прерыванию транзакции.

Учитывая описанный выше вариант использования, механизм голосования теперь может быть реализован с помощью этого хука: как только он будет вызван, он заберет весь стандартный ввод и будет использовать его для голосования центральной службе.
Когда все реплики репозитория согласятся, ловушка завершится с нулем, в противном случае транзакция прервется, вернув ненулевое значение.
Самым важным преимуществом является то, что это позволит поймать все команды, записывающие ссылки одновременно, что позволит реализовать сильную согласованность для обновлений ссылок с помощью единого механизма.

Чтобы проверить влияние на случай, когда у нас не установлен какой-либо хук "reference-transaction" в репозитории, этот коммит представляет два новых теста производительности для git-update-refs.
Запуск против пустого репозитория дает следующие результаты:

Test                         origin/master     HEAD
--------------------------------------------------------------------
1400.2: update-ref           2.70(2.10+0.71)   2.71(2.10+0.73) +0.4%
1400.3: update-ref --stdin   0.21(0.09+0.11)   0.21(0.07+0.14) +0.0%  

Тест производительности p1400.2 создает, обновляет и удаляет ветку тысячу раз, таким образом, среднее время выполнения git-update-refs более 3000 заклинаний.
p1400.3 вместо этого звонит git-update-refs --stdin трижды и ставит в очередь тысячу созданий, обновлений и удалений соответственно.

Как и ожидалось, p1400.3неизменно не оказывает заметного влияния, поскольку для каждого пакета обновлений существует единственный вызов доступа (3P) для поиска отрицательной ловушки.
С другой стороны, дляp1400.2, можно увидеть влияние этого набора патчей. Но выполнив пять запусков тестов производительности, каждый из которых выполнялся сGIT_PERF_REPEAT_COUNT=10,накладные расходы варьировались от -1,5% до +1,1%. Эти несогласованные показатели производительности можно объяснить накладными расходами на порождение 3000 процессов. Это показывает, что накладные расходы на сборку пути перехвата и однократное выполнение доступа (3P) для проверки его наличия в основном перевешиваются накладными расходами операционной системы.


В Git 2.29 (4 квартал 2020 г.) ловушка упрощена за счет удаления неэффективной оптимизации.

См. Commit 0a0fbbe (25 августа 2020 г.) Патрик Стейнхардт (pks-t).
(Слияние Junio ​​C Hamano -gitster- в коммите 6ddd76f, 31 августа 2020 г.)

refs: удалить кеш поиска для reference-transaction крюк

Подписано: Патрик Стейнхардт

При добавлении reference-transaction Hook, были опасения, что это может повлиять на производительность в установках, которые вообще не используют новую ловушку.
В конце концов, он выполняется каждый раз, когдаreftxподготовлен, зафиксирован или прерван, который линейно масштабируется с количеством ссылочных транзакций, созданных за сеанс.
И поскольку есть пути кода, такие как git push(man), которые создают новую транзакцию для каждой обновляемой ссылки, это может привести к вызовуfind_hook() достаточно много.

Чтобы решить эту проблему, был добавлен кеш с намерением не выполнять повторный поиск отрицательных подключений.
Оказывается, этот кеш вызвал регресс, который был исправлен с помощью e5256c82e5 ("refs: исправить чередование вызовов перехватчика с перехватом ссылки-транзакции ", 2020-08-07, Git v2.29.0 - слияние указано в пакете № 8).

В процессе обсуждения исправления мы поняли, что кеш действительно не помогает даже в случае отрицательного поиска.
Хотя тесты производительности, добавленные в тест, показали небольшое улучшение в диапазоне 1%, это действительно не означает наличия кеша.
Кроме того, это тоже довольно непрочно. Например, запуск дважды подряд дает следующие результаты:

Test                         master            pks-reftx-hook-remove-cache
--------------------------------------------------------------------------
1400.2: update-ref           2.79(2.16+0.74)   2.73(2.12+0.71) -2.2%
1400.3: update-ref --stdin   0.22(0.08+0.14)   0.21(0.08+0.12) -4.5%

Test                         master            pks-reftx-hook-remove-cache
--------------------------------------------------------------------------
1400.2: update-ref           2.70(2.09+0.72)   2.74(2.13+0.71) +1.5%
1400.3: update-ref --stdin   0.21(0.10+0.10)   0.21(0.08+0.13) +0.0%

Один случай, который заметно отсутствует в этих тестах, - это один исполняемый файл, который ищет ловушку сотни раз, что является именно тем случаем, для которого был добавлен отрицательный кеш.
p1400.2 создаст новый update-ref для каждой транзакции и p1400.3имеет только одну ссылочную транзакцию для всех ссылочных обновлений.
Таким образом, этот коммит добавляет третий тест, который выполняет неатомарную передачу тысячи ссылок. Это создаст новую ссылочную транзакцию для каждой ссылки. Но даже в этом случае отрицательный кеш не всегда улучшает производительность:

Test                         master            pks-reftx-hook-remove-cache
--------------------------------------------------------------------------
1400.4: nonatomic push       6.63(6.50+0.13)   6.81(6.67+0.14) +2.7%
1400.4: nonatomic push       6.35(6.21+0.14)   6.39(6.23+0.16) +0.6%
1400.4: nonatomic push       6.43(6.31+0.13)   6.42(6.28+0.15) -0.2%

Так что давайте полностью удалим кеш, чтобы упростить код.

Кроме того, взгляните на: http://fabioz.github.io/mu-repo/ - это такой инструмент, как mr и repo, так как я не мог заставить их работать так, как мне нужно:)

Некоторые заметки:

  • это делается на Python (поэтому хорошо работает в любой ОС, где работает Python: Linux, Win, Mac...)

  • помимо выполнения общих операций git одновременно со многими репозиториями, также предоставляет рабочие процессы для:

    • клонировать несколько репозиториев
    • открытые ссылки из репозиториев (так что можно создавать запросы извлечения сразу для нескольких репо).
    • Изменения в разных репо одновременно с winmerge или meld
    • выполнять не-git команды

Инструмент репо Android управляет созданием ветвей объектов в нескольких репозиториях. Тем не менее repo upload Команда может публиковать только в обзоре кода Gerrit.

Если вы используете обычный менеджер репозитория Git, такой как GitHub или GitLab, repo upload не будет работать; тебе нужно несуществующее repo push команда. Я реализовал repo push в форке Wave Computing репо. Мы используем его в производстве.

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

git submodule foreach --recursive <command>

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

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