Как мне управлять открытой и коммерческой версией одного и того же проекта с помощью контроля версий? - PullRequest
16 голосов
/ 07 октября 2011

Мы разрабатываем проект с открытым исходным кодом, и мы используем Mercurial для управления исходным кодом.Хранилище Mercurial для этого проекта является общедоступным (мы используем Bitbucket).

Теперь у нас есть клиент, для которого нам нужно настроить наше программное обеспечение с открытым исходным кодом.Эти настройки должны оставаться закрытыми, поэтому нам, вероятно, нужно создать новый репозиторий Hg для этого клиента;этот новый репозиторий будет закрытым.

Но проблема в том, что нам необходимо [время от времени] объединять изменения (например, новые функции или исправления ошибок) из открытого репозитория в наш частный репозиторий.

Каков наилучший способ достичь этого?Я читал, что возможно объединить два или более хранилищ Mercurial, но история будет потеряна.Также слияние может быть болезненным из-за многих конфликтов.Что если в будущем у нас будет еще несколько клиентов, как нам следует управлять их репозиториями?Должны ли мы использовать один репозиторий и несколько веток?Что, если две версии проекта начнут двигаться в разных направлениях, а два хранилища станут все более разными?

Пожалуйста, поделитесь своим опытом по этому поводу.

Заранее спасибо!

Ответы [ 4 ]

13 голосов
/ 08 октября 2011

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

hg clone open private

Затем перейдите в private и добавьте туда новые функции. Совершайте как обычно. Репозиторий private теперь будет содержать больше наборов изменений, чем репозиторий open, а именно новые функции.

Когда исправления и новые функции добавляются в репозиторий open как часть обычного процесса с открытым исходным кодом, вы помещаете их в репозиторий private:

cd private
hg pull
hg merge

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

Не будет никакой потери истории. Вам придется разрешить слияние как обычно, когда вы выполните hg merge, и конфликты будут настолько большими, насколько этого требуют ваши личные изменения.

Важно помнить, что никогда нельзя толкать (или тянуть) по-другому, если только вы не хотите начать выпускать некоторые частные изменения в версию с открытым исходным кодом.

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

6 голосов
/ 07 октября 2011

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

Однако задача состоит в том, чтобы не закончить с неуправляемым адом слияния, и это может быть достигнуто только посредством строгогодисциплина.

Основные эмпирические правила для любых долгоживущих веток:

  1. Держите частную ветвь как можно меньше.Минимизируйте количество изменений и сохраняйте их небольшими, чтобы не начинать рефакторинг огромных частей кода или изменение отступов.В ситуации с односторонним слиянием, как здесь, любой изменяемый код может конфликтовать, даже если он находится на линии вниз.

  2. Слияние часто.Чем чаще, тем лучше.Если вы этого не сделаете, то когда вам захочется интегрировать изменения из общедоступного репозитория, вы получите одно суперслияние, которое имеет массу конфликтов.

ДополнительноВы также должны быть дисциплинированы в организации и написании своего кода, чтобы облегчить этот сценарий.Имеют четкие правила относительно того, что происходит, куда, в какую ветку, и разбивают фрагменты кода.

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

Также пишите автоматизированные тесты.Много их.В противном случае вы не будете своевременно обнаруживать проблемы слияния (которые произойдут ), и частная ветвь часто будет повреждена.

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

1 голос
/ 10 января 2013

Проект, как обычно, состоит из набора модулей. По моему опыту, иногда даже лучше иметь несколько модулей в отдельных репозиториях управления исходным кодом. Например, некоторый служебный модуль или основной модуль, такой как веб-каркас или модуль DAO (ORM). В этом случае вы можете использовать ветки в элементах управления исходным кодом, так как они должны использоваться - для поддержки разработки стволов и поддержки каждой выпущенной версии в одном и том же хранилище элементов управления исходным кодом, чтобы иметь возможность объединять ветви.

Поэтому я предлагаю вам изменить структуру модулей приложения таким образом, чтобы отделить основные функции (с открытым исходным кодом) от коммерческой (зависящей от клиента) настройки. Поэтому для управления открытыми и коммерческими выпусками вам нужно иметь отдельные процедуры сборки - они могут быть более или менее похожими, или даже коммерческий выпуск может использовать выпуск с открытым исходным кодом в качестве набора полных артефактов и расширяет их.

На самом деле это очень интересная задача - я потратил на нее много времени в прошлом году. Мое решение состоит в том, чтобы иметь одну core-repositoy (с открытым исходным кодом) с полнофункциональной задачей maven, чтобы выпустить ее. И отдельное репо для каждого клиента, которое сохраняет только индивидуальную настройку дизайна и некоторую бизнес-логику для конкретного клиента (просто используйте псевдонимы в Spring XML клиента для переопределения ваших «основных» сервисов Spring - см. BeanDefinitionOverriding ) и maven- Задача для моего клиента основана на использовании основных артефактов (часто расширяет некоторые из них - см., например, «оверлеи» в maven-war-plugin , который позволяет расширить существующие WAR). Работая таким образом, вы никогда не будете иметь клона того же класса в другой ветке - вы будете использовать его или расширять его точно так же, как вы используете классы log4j в своем приложении. Вы должны просто расширить релиз с открытым исходным кодом.

Другая интересная задача - как управлять конфигурационными файлами. Я рекомендую вам видеть Плагин удаленных ресурсов Maven вместо стандартного Плагин ресурсов Maven . Это позволяет вам иметь шаблон файлов конфигурации и перенести все значения в профили maven , которые должны быть индивидуальными для каждого клиента. И посмотрите на Maven Tiles Plugin - это помогает мне значительно упростить «pom.xml» в проекте клиента (я могу повторно использовать «плитки» процедуры сборки и сборки maven)

1 голос
/ 10 января 2013

Ну, некоторые расширения и вариации.

  • Для рабочего процесса Мартина вы можете использовать парадигму "Branch Per Task" (ветви должны быть созданы в базовом проекте, "Open") и "push -b"--new-branch "(публиковать только ветку, а не весь набор изменений также в основной ветке) в" Private ", в которой ветвь также должна быть объединена со значением по умолчанию.

Увеличено количество вилок вв этом случае стоит «+2 команды +1 репозиторий» на разветвление

  • Вариация ветвления: репо одного разработчика, множество именованных ветвей (Ветвь на цель + Ветвь на задачу).Небольшое отклонение v.1 - только одно репо разработки, которое содержит открытые и частные именованные ветви (среди других краткосрочных ветвей).Задача также (как в п.1) реализована в отдельной ветке, которая (без push) сливается с нужными целями (Open и Private). Видимый пользователю Открытые и частные репозитории также должны быть обновлены с помощью push -b

Увеличенное количество вилок в этом случае стоит "+1 команда +1 ветвь" за вилку

  • Модель на основе патчей.Единый общий код, все изменения выполняются поверх наборов изменений "vanilla Open".При включенном MQ только применение исправлений в очереди конвертирует Open в Private.Если дело «существует в Open, не должно существовать в Private», мы перейдем к ситуации трехуровневого управления версиями Core-Open-Private.Для такой ситуации должны использоваться различные наборы патчей поверх Core .«Различные наборы патчей» могут быть: а) ветвями с разными именами для разных целей и ручного применения и контроля; б) с использованием защитных приспособлений; в) для относительно свежего Mercurial возможно наличие отдельных очередей, и для каждой уникальной цели также есть уникальная очередь.Задачи могут быть разработаны в ветках, как и раньше, или в MQ-патче (qfinish'ed позже или нет)

Увеличенное количество вилок в этом случае стоит «+1 патч» за вилку и, возможно,«+1 очередь» (см. Выше).Я предпочту одну очередь с охраной для простоты и управляемости

...