Использование слияния поддеревьев git, а также слияние во всех ветвях всех объединенных поддеревьев.

StackOverflow https://stackoverflow.com/questions/2137950

  •  22-09-2019
  •  | 
  •  

Вопрос

Я хотел бы использовать популярный трекер проблем с открытым исходным кодом (Redmine), который предлагает интеграцию с git.К сожалению, каждый проект в трекере может быть связан только с одним git-репозиторием.Создание нескольких проектов в трекере — не идеальная для меня установка.

Имея это в виду, я попытался использовать слияние поддеревьев git (объяснено здесь, и здесь).Я создал «зонтичный» репозиторий, который объединился с каждым из множества других репозиториев, с которыми я работаю.

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

Это возможно?

Дополнительный кредит:Что, если каждое из двух поддеревьев имеет ветвь с одинаковым именем?

Это было полезно?

Решение

Тем из нас, кто не знаком с Redmine, просьба расширить описание, включив в него ответы на следующие вопросы:Какой доступ к репозиторию нужен трекеру?Нужно ли будет делать собственные коммиты?Или ему просто нужны определенные виды доступа для чтения (возможно, для проверки хешей коммитов и сканирования журналов коммитов на предмет ключевых слов)?

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

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

Но интересный вопрос заключается не в том, «что, если два репозитория имеют ветки с одинаковым именем?», а в том, «как поступить в случае, когда в репозитории отсутствует ветка из общего «глобального» набора?».

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

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

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


Сбор ветвей без слияния

Если Redmine указывает --mirror clone, подразумевается, что он ожидает локальные ветки и, возможно, не сможет напрямую читать «ветви удаленного отслеживания», поэтому вам, вероятно, придется создать и обновить некоторые локальные ветки.

Локальные филиалы обновлены из «ветвей удаленного отслеживания»
  • Начальная настройка

    mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
    git init
    git remote add alpha <url/path-to-alpha-repo>
    git remote add bravo <url/path-to-bravo-repo>
    git remote add charlie <url/path-to-charlie-repo>
    for r in $(git remote); do
        git config --add remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.heads.tags.;s.remotes.tags/all.')"
        git config remote.$r.tagopt --no-tags
    done
    
  • Периодическое обновление

    git remote update
    git for-each-ref --shell --format \
      'git branch --force --track -l all/%(refname:short) %(refname:short)' refs/remotes \
      | sh
    
Локальные ветки, которые напрямую получают подсказки о ветках
  • Начальная настройка

    mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
    git init
    git remote add alpha <url/path-to-alpha-repo>
    git remote add bravo <url/path-to-bravo-repo>
    git remote add charlie <url/path-to-charlie-repo>
    for r in $(git remote); do
        git config remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.remotes.heads/all.')"
        git config --add remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.heads.tags.g')"
        git config remote.$r.tagopt --no-tags
    done
    
  • Периодическое обновление

    git remote update
    

Оба метода в конечном итоге собирают ветки под refs/heads/all/<remote-name>/<branch-name-on-remote>, но первый также имеет дублирующийся набор ссылок под refs/remotes/<remote-name>/<branch-name-on-remote>.Первый использует обычную спецификацию выборки и использует git branch дублировать «ветви удаленного отслеживания» (refs/remotes/…) в обычные локальные ветки (refs/heads/all/…).Второй использует специальную спецификацию ссылок для хранения полученных ссылок непосредственно в целевой иерархии ссылок.

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

Если Redmine может работать с пустым репозиторием, я бы рекомендовал использовать его.Использовать git init --bare и имя репо, которое заканчивается на .git.Также git config core.logAllRefUpdates true может быть хорошей идеей (поскольку в пустом репозитории по умолчанию это значение false).

Кроме all/ префикс в пространствах имен, еще одно отличие этого подхода от полного --mirror клон - это ссылки снаружи refs/heads и refs/tags не будут собраны.Большинство других общих ссылок считаются «локальными» по отношению к репозиторию (именно поэтому они не копируются обычным клоном).Некоторые из других ссылок являются «ветвями удаленного отслеживания» (refs/remotes), некоторое ведение записей пополам (refs/bisect), git filter-branch «оригинальные» резервные копии ссылок (refs/original), и так далее.Вероятно, ни одна из этих других вещей не важна для Redmine.Если да, то их также можно включить в дополнительные спецификации.

Создание дополнительных начальных коммитов

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top