Использование git слияния поддеревьев, а также слияние во всех ветвях всех объединенных поддеревьев - PullRequest
8 голосов
/ 26 января 2010

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

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

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

Возможно ли это?

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

1 Ответ

7 голосов
/ 26 января 2010

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

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

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

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

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

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

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


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

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

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

    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>. Первый использует обычную привязку refspec и использует git branch для дублирования «ветвей удаленного отслеживания» (refs/remotes/…) в обычные локальные ветки (refs/heads/all/…). Второй использует пользовательские refspec для хранения выбранных ссылок непосредственно в иерархии ссылок назначения.

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

Если 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. Если они есть, они также могут быть включены с дополнительными refspecs.

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

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

...