Для тех из нас, кто не знаком с 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
Оба метода в конечном итоге собирают ветки под 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