Как управлять открытой и коммерческой версиями одного и того же проекта с использованием источника управления?
Мы разрабатываем проект с открытым исходным кодом, и мы используем Mercurial для управления исходным кодом. Репозиторий Mercurial для этого проекта является общедоступным (мы используем Bitbucket).
Теперь у нас есть клиент, для которого нам нужно настроить наше программное обеспечение с открытым исходным кодом. Эти настройки должны быть конфиденциальными, поэтому нам, вероятно, нужно создать новый Hg-репозиторий для этого клиента; этот новый репозиторий будет закрытым.
Но проблема в том, что нам нужно [время от времени] изменять слияние (например, новые функции или исправления ошибок) из открытого репозитория в наш частный репозиторий.
Какой лучший способ достичь этого? Я читал, что можно объединить два или более хранилища Mercurial, но история будет потеряна. Также слияние может быть болезненным из-за многих конфликтов. Что делать, если в будущем мы получим еще несколько клиентов, как мы должны управлять своими репозиториями? Должны ли мы использовать один репозиторий и несколько веток? Что делать, если две версии проекта начинаются в разных направлениях, а два хранилища становятся все более разными?
Поделитесь своим опытом об этом.
Спасибо заранее!
Ответы
Ответ 1
То, что вы описываете, является стандартной вещью с распределенной системой управления версиями: разработка в двух хранилищах и сохранение одного подмножества другого. Начните с создания клона для частного развития:
hg clone open private
Затем перейдите в private
и создайте новые функции. Зафиксируйте как обычно. Репозиторий private
теперь будет содержать больше наборов изменений, чем репозиторий open
, а именно новые функции.
Когда исправления и новые функции помещаются в репозиторий open
как часть обычного процесса с открытым исходным кодом, вы переносите их в репозиторий private
:
cd private
hg pull
hg merge
Таким образом, вы сохраняете инвариант: репозиторий private
всегда содержит все в открытой версии плюс частные улучшения. Если вы работаете над частной версией и обнаруживаете ошибку, не забудьте взглянуть на открытую версию, чтобы узнать, существует ли там ошибка. Если это так, тогда сначала исправьте его в открытой версии и объедините исправление в приватную версию. Если вы исправите ошибку в приватной версии по ошибке, используйте hg transplant
, чтобы скопировать исправление в другую открытую версию.
Там не будет никакой потери истории. Вам придется разрешить слияние, как обычно, когда вы делаете hg merge
, и конфликты будут только такими, насколько это требуется вашими частными изменениями.
Важно помнить, что никогда не нажимайте (или не тянуть) другой путь, если вы не хотите начать выпуск некоторых частных изменений в версию с открытым исходным кодом.
Вы можете использовать эту настройку несколько раз с разными клиентами, и вы также можете нажимать/вытягивать списки изменений между разными частными репозиториями, если для нескольких клиентов требуется одно и то же личное расширение.
Ответ 2
В принципе базовая модель относительно проста; иметь отдельный приватный репозиторий, который является клоном (ветвью) публичного, делать все частные изменения там, а затем регулярно объединять публичный в частный. Нет проблем в сохранении истории, я не знаю, почему вы читаете, что произойдет.
Однако задача состоит в том, чтобы не оказаться в неимоверном слиянии ад, и это может быть достигнуто только через строгую дисциплину.
Самые основные правила для любых долгоживущих ветвей:
-
Держите частную ветвь как можно меньше. Минимизируйте количество изменений там и держите их маленькими, поэтому не начинайте рефакторинг огромных частей кода или изменения отступа. В ситуации одностороннего слияния, такой как здесь, любой код, который вы модифицируете, может конфликтовать, даже по линии.
-
Слияние часто. Чем чаще, тем лучше. Если вы этого не сделаете, когда вы захотите интегрировать изменения из общего репозитория, вы получите одно супер-слияние, у которого будет тонна конфликтов.
Кроме того, вы должны быть дисциплинированы в организации и написании кода для облегчения этого сценария. Имейте четкие правила о том, что происходит там, где на какой ветке, и отделив куски кода.
В идеале вы бы моделировали настраиваемые функции как плагин или внешнюю библиотеку, даже отдельный проект. Это может не всегда быть легко достижимым, в этом случае, по крайней мере, попытайтесь написать все частные модификации с точки зрения подклассов оригинала, которые вы создаете с помощью методов factory. Сделав все ваши изменения в независимых файлах, которые существуют только на частной ветке, вы минимизируете риск конфликтов.
Также напишите автоматизированные тесты. Многие из них. Кроме того, вы не будете быстро обнаруживать проблемы слияния (что произойдет), и частная ветвь часто будет нарушена.
Наконец, совет: сделайте пусковой крючок в публичном репозитории, который отрицает любой push, содержащий набор изменений, который, как вы знаете, является конфиденциальным; это предотвратит случайную публикацию частного кода и потенциально сэкономит вам много головных болей.
Ответ 3
Как обычно, проект состоит из набора модулей.
По моему опыту иногда даже лучше иметь некоторые модули в отдельных хранилищах-источниках-репозиториях. Например, некоторый модуль-модуль или основной модуль, такой как web-framework или модуль DAO (ORM). В этом случае вы можете использовать ветки в исходных элементах управления, поскольку они должны использоваться для поддержки разработки и поддержки каждой версии выпущенной версии в одном хранилище исходных элементов управления, чтобы иметь возможность объединять ветки.
Поэтому я предлагаю вам перепроектировать структуру ваших модулей приложений таким образом, чтобы вы могли отделять основные (открытые) функции от коммерческой (зависящей от клиента) настройки.
Поэтому для управления версиями с открытым исходным кодом и коммерческими версиями вам необходимо иметь отдельные процедуры сборки - они могут быть более или менее похожими, или даже коммерческий релиз может использовать выпуск с открытым исходным кодом как набор полных артефактов и расширяет их.
На самом деле это очень интересная задача - я потратил на нее много времени в прошлом году. Мое решение состоит в том, чтобы один core-repositoy (open-source) с полностью функционирующей задачей maven выпустил его. И отдельное репо для каждого клиента, которое поддерживает только настройку дизайна и некоторую бизнес-логику, ориентированную на клиента (просто используйте псевдонимы в клиентском spring XML для переопределения ваших "основных" сервисов spring - см. BeanDefinitionOverriding), а задача maven для моего клиента основана на использовании основных артефактов (часто распространяет некоторые из них - см., например, "наложения" в maven-war-plugin, что позволяет продлить существующую WAR). В таком случае у вас никогда не будет клона того же класса в другой ветке - вы будете использовать его или расширять его точно так же, как вы используете классы log4j в своем приложении. Вы должны просто расширить выпуск с открытым исходным кодом.
Еще одна интересная задача - управлять конфигурационными файлами. Я рекомендую вам увидеть Maven Remote Resources Plugin вместо стандартного Плагин Maven Resources. Он позволяет вам иметь шаблон конфигурационных файлов и переместить все значения в профили maven, которые должны быть конкретными для каждого клиента. И посмотрите на Maven Tiles Plugin - это помогает мне значительно упростить "pom.xml" в проекте клиента (я могу повторно использовать "плитки" maven сборка и сборка)
Ответ 4
Ну, некоторые расширения и варианты.
- Для рабочего процесса Martin вы можете использовать парадигму "Branch Per Task" (ветки должны быть созданы в базовом проекте, "Open" ) и "push -b -new-branch" (публиковать только ветку, а не весь набор изменения также в mainline) до "Private", в котором ветвь также должна быть объединена по умолчанию.
Увеличенное количество вилок в этом случае стоит "+2 команды +1 репозиторий" на fork
- Вариация ветвления: реестр разработчиков с одним разработчиком, много названных ветвей (Branch per Target + Branch per Task). Небольшое отклонение v.1 - только одно репо-процесс разработки, в котором Open & Private называются ветвями (среди других ветвей short-termb). Задача также (как и в п. 1) реализована в отдельной ветке, которая (без толчка) сливается с нужными целями (Open и Private). Пользовательские открытые и закрытые репозитории должны обновляться также с помощью кнопки -b
Увеличенное количество вилок в этом случае стоит "+1 команда +1 ветвь" для каждой вилки
- Патч-модель. Единый общий код, все изменения выполняются поверх наборов кодовых таблиц "Ванильный Open". С включенным MQ только с применением патчей в конверте очереди Open to Private. Если случай "существует в Open, не должен существовать в Private", мы перейдем к ситуации трехуровневого управления версиями Core-Open-Private. Для такой ситуации необходимо использовать разные патч-наборы поверх Core. "Различные патч-наборы" могут быть: а) разным названием ветвей для разных целей и ручного применения и контроля; б) использования охранников; в) для довольно свежего Mercurial возможно, что отдельные очереди и для каждой уникальной цели также имеют уникальную очередь. Задачи могут быть разработаны в ветвях, как и раньше, или в MQ-patch (позже qfinish) или
Увеличение количества вилок в этом случае стоит "+1 патч" для каждой вилки и, возможно, "+1 очередь" (см. выше). Я предпочитаю одиночную очередь с защитой для простоты и управляемости.