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

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

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

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

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

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


person anthony    schedule 26.01.2010    source источник
comment
Вторая ссылка, объясняющая слияние поддеревьев, не работает. Вместо этого попробуйте здесь   -  person runexe    schedule 10.09.2010


Ответы (1)


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

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

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

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

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

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

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


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

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

Local Branches Updated From ‘Remote Tracking Branches’
  • Начальная настройка

    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
    
Local Branches That Directly Receive Fetched Branch Tips
  • Начальная настройка

    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 в разделе Как создать новую ветку без предка. Два рецепта включают другой репозиторий, из которого вы отправляете или извлекаете ветку после выполнения обычного шага инициализации/добавления/фиксации (именно то, что приведенные выше рецепты делают автоматически).

person Chris Johnsen    schedule 26.01.2010
comment
Спасибо за ваш продуманный ответ. Redmine просто нужен доступ только для чтения к клону --mirror в локальной файловой системе. Эти вложенные репозитории определенно не используют один и тот же набор хорошо известных имен веток, что еще больше усложняет проблему. Удаленное отслеживание ветвей/несколько первоначальных коммитов кажется многообещающим, я проведу расследование. - person anthony; 26.01.2010
comment
Эм, дополнительный вопрос. Какие команды я использую для создания нескольких первоначальных коммитов? - person anthony; 26.01.2010
comment
+1 Спасибо за информацию. Я также сожалею, что могу проголосовать за это только один раз :) это очень помогло мне с этим вопросом< /а> - person gingerlime; 12.05.2012