Как использовать Mercurial subrepos для общих компонентов и зависимостей?
Мы разрабатываем.NET Enterprise Software на C#. Мы стремимся улучшить нашу систему контроля версий. Я использовал Mercurial раньше и экспериментировал с его использованием в нашей компании. Однако, поскольку мы разрабатываем корпоративные продукты, мы уделяем большое внимание повторно используемым компонентам или модулям. Я пытался использовать суб-репозитории Mercurial для управления компонентами и зависимостями, но у меня возникли некоторые трудности. Вот основные требования для контроля версий / управления зависимостями:
- Многоразовые компоненты
- Совместно с источником (для отладки)
- Наличие зависимостей от сторонних двоичных файлов и других повторно используемых компонентов
- Может быть разработан и передан на контроль источников в контексте потребляющего продукта
- зависимости
- Продукты зависят от сторонних двоичных файлов и других повторно используемых компонентов
- Зависимости имеют свои зависимости
- Разработчики должны быть уведомлены о конфликтах версий в зависимостях
Вот структура в Mercurial, которую я использовал:
Многоразовый компонент:
SHARED1_SLN-+-docs
|
+-libs----NLOG
|
+-misc----KEY
|
+-src-----SHARED1-+-proj1
| +-proj2
|
+-tools---NANT
Второй многократно используемый компонент, потребляющий первый:
SHARED2_SLN-+-docs
|
+-libs--+-SHARED1-+-proj1
| | +-proj2
| |
| +-NLOG
|
+-misc----KEY
|
+-src-----SHARED2-+-proj3
| +-proj4
|
+-tools---NANT
Продукт, который потребляет оба компонента:
PROD_SLN----+-docs
|
+-libs--+-SHARED1-+-proj1
| | +-proj2
| |
| +-SHARED2-+-proj3
| | +-proj4
| |
| +-NLOG
|
+-misc----KEY
|
+-src-----prod----+-proj5
| +-proj6
|
+-tools---NANT
Заметки
- Репо в CAPS
- Предполагается, что все дочерние репозитории являются вложенными
- Сторонние (двоичные) библиотеки libs и внутренние (исходные) компоненты являются вложенными элементами, расположенными в папке libs.
- Сторонние библиотеки хранятся в отдельных Mercurial репозиториях, так что проекты-потребители могут ссылаться на конкретные версии библиотек (т.е. старый проект может ссылаться на NLog v1.0, а новый проект может ссылаться на NLog v2.0).
- Все файлы Visual Studio .csproj находятся на 4-м уровне (папки proj*), что позволяет создавать относительные ссылки на зависимости (т.е. ../../../libs/NLog/NLog.dll для всех проектов Visual Studio, которые ссылаются на NLog)
- Все файлы Visual Studio .sln находятся на 2-м уровне (папки src), поэтому они не включаются при "совместном использовании" компонента в потребляющий компонент или продукт.
- Разработчики могут свободно организовывать свои исходные файлы по своему усмотрению, если они являются дочерними для папки proj* потребляющего проекта Visual Studio (т. Е. Может быть n дочерних элементов для папок proj*, содержащих различные источники / ресурсы).
- Если Боб разрабатывает компонент SHARED2 и продукт PROD1, для него совершенно законно внести изменения в источник SHARED2 (скажем, источники, принадлежащие proj3) в репозиторий PROD1_SLN и зафиксировать эти изменения. Мы не против, если кто-то разработает библиотеку в контексте потребляющего проекта.
- Внутренне разработанные компоненты (SHARED1 и SHARED2) обычно включаются источником в потребляющий проект (в Visual Studio добавление ссылки на проект вместо просмотра ссылки на dll). Это позволяет улучшить отладку (шаг в коде библиотеки), позволяет Visual Studio управлять, когда необходимо перестроить проекты (когда изменяются зависимости), и позволяет изменять библиотеки при необходимости (как описано в приведенном выше примечании).
Вопросы
Если Боб работает над PROD1, а Алиса работает над SHARED1, как Боб узнает, когда Алиса фиксирует изменения в SHARED1. В настоящее время с Mercurial, Боб вынужден вручную извлекать и обновлять в каждом подпункте. Если он выталкивает / извлекает на сервер из репозитория PROD_SLN, он никогда не узнает об обновлениях в подпунктах. Это описано в Mercurial Wiki. Как Боб может быть уведомлен об обновлениях в подпунктах, когда он извлекает последнюю из PROD_SLN с сервера? В идеале он должен быть уведомлен (предпочтительно во время извлечения), а затем должен вручную решить, какие подпункты он хочет обновить.
Предположим, что SHARED1 ссылается на NLog v1.0 (commit/rev abc в Mercurial) и SHARED2 ссылается на Nlog v2.0 (commit/rev xyz в Mercurial). Если Боб поглощает эти два компонента в PROD1, он должен быть осведомлен об этом несоответствии. Хотя технически Visual Studio/.NET позволяет двум сборкам ссылаться на разные версии зависимостей, моя структура этого не допускает, поскольку путь к NLog фиксирован для всех проектов.NET, которые зависят от NLog. Как Боб может знать, что две его зависимости имеют конфликт версий?
Если Боб настраивает структуру хранилища для PROD1 и хочет включить SHARED2, как он может знать, какие зависимости требуются для SHARED2? С моей структурой ему пришлось бы вручную клонировать (или просмотреть на сервере) репозиторий SHARED2_SLN и либо заглянуть в папку libs, либо посмотреть на файл.hgsub, чтобы определить, какие зависимости ему нужно включить. В идеале это было бы автоматизировано. Если я включу SHARED2 в свой продукт, SHARED1 и NLog также автоматически включаются, уведомляя меня, если есть конфликт версий с какой-либо другой зависимостью (см. Вопрос 2 выше).
Большие вопросы
Является ли Mercurial правильным решением?
Есть ли лучшая ртутная структура?
Является ли это допустимым использованием для подпунктов (т. Е. Разработчики Mercurial пометили подпункты как функцию последнего средства)
Имеет ли смысл использовать Mercurial для управления зависимостями? Мы могли бы использовать еще один инструмент для управления зависимостями (может быть, внутренний канал NuGet?). Хотя это будет хорошо работать для сторонних зависимостей, на самом деле это создаст проблемы для внутренних компонентов (т. Е. Если они активно разрабатываются, разработчикам придется постоянно обновлять канал, нам придется обслуживать их внутри, и это не позволит компоненты, которые будут изменены потребляющим проектом (Примечание 8 и Вопрос 2).
У вас есть лучшее решение для программных проектов Enterprise .NET?
Рекомендации
Я прочитал несколько вопросов SO и нашел этот вопрос полезным, но принятый ответ предполагает использование специального инструмента для работы с зависимостями. Хотя мне нравятся возможности такого инструмента, он не позволяет изменять зависимости и фиксировать их из потребляющего проекта (см. Более широкий вопрос 4).
2 ответа
Возможно, это не тот ответ, который вы искали, но у нас есть недавний опыт начинающих пользователей Mercurial, использующих суб-репо, и я искал возможность передать наш опыт...
Таким образом, мой совет, основанный на опыте: какими бы привлекательными ни были суб-репозитории Mercurial, не используйте их. Вместо этого найдите способ расположить ваши каталоги рядом и настроить ваши сборки, чтобы справиться с этим.
Однако, кажется привлекательным связать ревизии в суб-репо с ревизиями в родительском репо, на практике это просто не работает.
В течение всей подготовки к конверсии мы получали советы из разных источников о том, что суб-репо были хрупкими и плохо реализованными - но мы все равно продолжали, поскольку нам требовались атомарные коммиты между репо и суб-репо. Совет - или мое понимание этого - говорил больше о принципах, а не о практических последствиях.
Только когда мы начали жить с Mercurial и суб-репо, я действительно правильно понял совет. Здесь (из памяти) приведены примеры проблем, с которыми мы столкнулись.
- Ваши пользователи будут в конечном итоге бороться с процессом обновления и слияния.
- Некоторые люди будут обновлять родительское репо, а не суб-репо
- Некоторые люди будут выталкивать из суб-репо, анг. Hgsubstate не будет обновляться.
- В конечном итоге вы "потеряете" ревизии, сделанные в суб-репо, потому что кому-то удастся оставить.hgsubstate в неправильном состоянии после слияния.
- Некоторые пользователи попадут в ситуацию, когда.hgsubstate был обновлен, а суб-репо - нет, и тогда вы получите действительно загадочные сообщения об ошибках и потратите много часов, пытаясь понять, что происходит.
- А если вы сделаете разметку и разветвление для выпусков, инструкции о том, как получить это право как для родительского, так и для дополнительного репо, будут состоять из нескольких десятков строк. (И у меня даже был хороший, прирученный специалист по Mercurial, помогите мне написать инструкцию!)
Все эти вещи достаточно раздражают опытных пользователей, но когда вы внедряете Mercurial для начинающих пользователей, они становятся настоящим кошмаром и источником большого потраченного времени.
Итак, потратив много времени на конверсию с суб-репо, через несколько недель мы конвертировали суб-репо в репо. Поскольку у нас было большое количество истории конверсии, которая ссылалась на суб-репо через.hgsubstate, это оставило нам нечто гораздо более сложное.
Я только хотел бы, чтобы я действительно оценил практические последствия всех советов намного раньше, например, на странице " Особенности последней инстанции" Mercurial:
Но мне нужно иметь управляемые подпроекты!
Опять же, не будь так уверен. Важные проекты, такие как Mozilla, которые имеют множество зависимостей, прекрасно работают без использования подпунктов. Большинство небольших проектов почти наверняка будут лучше без использования подпунктов.
Изменить: Мысли о репозитории оболочки
С отказом от ответственности у меня нет никакого опыта их...
Нет, я не думаю, что многие из них. Вы по-прежнему используете суб-репо, поэтому все те же проблемы пользователей применимы (если, конечно, вы не можете предоставить скрипт-обертку для каждого шага, конечно, чтобы избавить людей от необходимости предоставлять правильные опции для обработки суб-репо.)
Также обратите внимание, что на вики-странице, которую вы цитировали, перечислены некоторые специфические проблемы с репозиториями оболочки:
- слишком строгое отслеживание отношений между проектом / и somelib /
- невозможно проверить или отправить проект / если репозиторий somelib / source становится
- недоступно отсутствие четко определенной поддержки рекурсивных diff, log и
- статус рекурсивный характер коммита удивительный
Редактировать 2 - сделать пробную версию с участием всех ваших пользователей
В тот момент, когда мы действительно начали понимать, что у нас возникла проблема, когда несколько пользователей начали совершать коммиты, а также вытягивать и толкать, включая изменения в суб-репо. Для нас было слишком поздно, чтобы ответить на эти вопросы. Если бы мы знали их раньше, мы могли бы ответить намного проще и проще.
Поэтому на данный момент лучший совет, который я могу предложить, - рекомендовать вам выполнить пробный запуск макета проекта до того, как макет будет вырезан в камне.
Мы оставили полномасштабную пробную версию слишком поздно, чтобы вносить изменения, и даже тогда люди вносили изменения только в родительское репо, а не в суб-репо, поэтому мы все еще не видели полную картину, пока не стало слишком поздно.
Другими словами, какой бы макет вы ни рассматривали, создайте структуру репозитория в этом макете и заставьте множество людей вносить изменения. Постарайтесь поместить достаточно реального кода в различные репо / суб-репо, чтобы люди могли вносить реальные изменения, даже если они будут одноразовыми.
Возможные результаты:
- Возможно, вы обнаружите, что все работает нормально - в этом случае вы потратили некоторое время, чтобы обрести уверенность.
- С другой стороны, вы могли бы выявить проблемы гораздо быстрее, чем тратить время на попытки выяснить, какими будут результаты.
- И ваши пользователи тоже многому научатся.
Вопрос 1:
Эта команда, когда выполняется в родительском репозитории "shell", будет проходить через все вложенные репозитории и перечислять наборы изменений из положения извлечения по умолчанию, которого нет:
hg incoming --subrepos
То же самое можно сделать, нажав кнопку "Входящие" на панели "Синхронизировать" в TortoiseHg, если у вас установлен флажок "--subrepos" (на той же панели).
Спасибо пользователям в Mercurial IRC канале за помощь здесь.
Вопросы 2 и 3:
Сначала мне нужно изменить свои структуры репо, чтобы родительские репозитории были действительно "оболочечными" репозиториями, как рекомендовано в hg wiki. Я возьму это до крайности и скажу, что оболочка не должна содержать контента, только подпункты как дочерние элементы. Таким образом, переименуйте src в main, переместите документы в подпункт main и измените папку prod на subrepo.
SHARED1_SLN:
SHARED1_SLN-+-libs----NLOG
|
+-misc----KEY
|
+-main----SHARED1-+-docs
| +-proj1
| +-proj2
|
+-tools---NANT
SHARED2_SLN:
SHARED2_SLN-+-libs--+-SHARED1-+-docs
| | +-proj1
| | +-proj2
| |
| +-NLOG
|
+-misc----KEY
|
+-main----SHARED2-+-docs
| +-proj3
| +-proj4
|
+-tools---NANT
PROD_SLN:
PROD_SLN----+-libs--+-SHARED1-+-docs
| | +-proj2
| | +-proj2
| |
| +-SHARED2-+-docs
| | +-proj3
| | +-proj4
| |
| +-NLOG
|
+-misc----KEY
|
+-main----PROD----+-docs
| +-proj5
| +-proj6
|
+-tools---NANT
- Все общие библиотеки и продукты имеют собственные репо (SHARED1, SHARED2 и PROD).
- Если вам нужно работать с совместно используемой библиотекой или продуктом независимо, доступна оболочка (мои репозитории заканчиваются _SLN), которая использует hg для управления ревизиями зависимостей. Оболочка только для удобства, потому что она не содержит контента, только подпункты.
- При развертывании релиза совместно используемой библиотеки или продукта разработчик должен перечислить все зависимости и их hg revs/changesets (или, предпочтительно, удобные для человека теги), которые использовались для создания релиза. Этот список должен быть сохранен в файле в репозитории для библиотеки или продукта (SHARED1, SHARED2 или PROD), а не оболочки. См. Примечание A ниже, чтобы узнать, как это может решить вопросы 2 и 3.
- Если я запускаю выпуск совместно используемой библиотеки или продукта, я должен поместить соответствующие теги в репозиторий проектов, и его оболочка для удобства, однако, если оболочка выходит из строя (озабоченность, выраженная в реальном опыте в ответе @Clare)), это действительно не должно иметь значения, потому что сама оболочка тупая и не содержит содержимого.
- Файлы Visual Studio Visual Studio попадают в корень общей библиотеки или репозитория продукта (SHARED1, SHARED2 или PROD), опять же,не в оболочку. В результате, если я включу SHARED1 в PROD, у меня могут появиться дополнительные решения, которые я никогда не открою, но это не имеет значения. Кроме того, если я действительно хочу работать над SHARED1 и запускать его модульные тесты (работая в оболочке PROD_SLN), это действительно просто, просто откройте указанное решение.
Примечание А:
Что касается пункта 3 выше, если в файле зависимостей используется формат, аналогичный.hgsub, но с добавлением тега rev/changeset/, получение зависимостей может быть автоматизировано. Например, я хочу SHARED1 в моем новом продукте. Клонируйте SHARED1 в мою папку libs и обновляйтесь до подсказки или последнего ярлыка релиза. Теперь мне нужно посмотреть файл зависимостей и а) клонировать зависимость в правильное местоположение и б) обновить до указанного rev/changeset/tag. Очень возможно автоматизировать это. Чтобы продвинуться дальше, он может даже отслеживать rev/changeset/ tag и предупреждать разработчика о конфликте зависимостей между разделяемыми библиотеками.
Дыра остается, если Алиса активно разрабатывает SHARED1, а Боб разрабатывает PROD. Если Алиса обновит SHARED1_SLN для использования NLog v3.0, Боб, возможно, никогда этого не узнает. Если Алиса обновляет свой файл зависимостей, чтобы отразить изменение, то у Боба есть информация, ему просто нужно сообщить об этом изменении.
Большие вопросы 1 и 4:
Я считаю, что это проблема управления исходным кодом, а не то, что может быть решено с помощью инструмента управления зависимостями, так как они обычно работают с двоичными файлами иполучают только зависимости (не позволяют фиксировать изменения обратно в зависимости). Мои проблемы с зависимостями не являются уникальными для Mercurial. Исходя из моего опыта, все инструменты контроля версий имеют одинаковую проблему. Одним из решений в SVN было бы просто использовать svn:externals (или svn-копии) и рекурсивно включать каждый компонент в свои зависимости, создавая, возможно, огромное дерево для создания продукта. Однако это разваливается в Visual Studio, где я действительно хочу включить только один экземпляр общего проекта и ссылаться на него везде. Как следует из ответа @Clare и ответа Грега на мою электронную почту в список рассылки hg, компоненты должны быть как можно более плоскими.
Большие вопросы 2 и 3:
Есть лучшая структура, как я изложил выше. Я считаю, что у нас есть веские аргументы в пользу использования подпунктов, и я не вижу жизнеспособной альтернативы. Как упомянуто в ответе @Clare, есть лагерь, который верит, что зависимостями можно управлять без подпунктов. Тем не менее, мне еще предстоит увидеть какие-либо доказательства или фактические ссылки, подтверждающие это утверждение.
Большой вопрос 5:
Все еще открыты для лучших идей...