Как использовать подпункты mercurial для общих компонентов и зависимостей?

Мы разрабатываем .NET Enterprise Software на С#. Мы стремимся улучшить нашу систему контроля версий. Раньше я использовал ртуть и экспериментировал с ней в нашей компании. Однако, поскольку мы разрабатываем корпоративные продукты, мы уделяем большое внимание многократно используемым компонентам или модулям. Я пытаюсь использовать mercurial sub-repos для управления компонентами и зависимостями, но у меня есть некоторые трудности. Вот основные требования для управления версиями/управления зависимостями:

  • Многоразовые компоненты
    • Общие сведения об источнике (для отладки)
    • Имеют зависимости от сторонних двоичных файлов и других компонентов многократного использования.
    • Может быть разработано и поручено контролю источника в контексте потребляющего продукта
  • Зависимости
    • Продукты имеют зависимости от сторонних двоичных файлов и других компонентов многократного использования.
    • Зависимости имеют свои зависимости
    • Разработчики должны быть уведомлены о конфликтах версий в зависимостях

Вот структура в 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
  • 3-сторонние библиотеки хранятся в отдельных меркуриальных репозиториях, так что потребляющие проекты могут ссылаться на конкретные версии libs (то есть старый проект может ссылаться на NLog v1.0, а более новый проект может ссылаться на NLog v2.0).
  • Все файлы Visual Studio.csproj находятся на 4-м уровне (proj * folders), что позволяет относить ссылки на зависимости (то есть.. /../../libs/NLog/NLog.dll для всех проектов Visual Studio, которые ссылаются NLog)
  • Все файлы Visual Studio.sln находятся на 2-м уровне (папки src), чтобы они не включались при "совместном использовании" компонента в потребляющем компоненте или продукте.
  • Разработчики могут свободно организовывать свои исходные файлы по своему усмотрению, пока исходные файлы являются дочерними страницами проекта proj * в проекте потребляющего Visual Studio (т.е. в папках proj * могут быть n детей, содержащих различные источники/ресурсы)
  • Если Боб разрабатывает компонент SHARED2 и продукт PROD1, для него совершенно законно вносить изменения в источник SHARED2 (скажем, источники, принадлежащие proj3) в репозитории PROD1_SLN, и фиксировать эти изменения. Мы не против, если кто-то разрабатывает библиотеку в контексте потребляющего проекта.
  • Внутренне разработанные компоненты (SHARED1 и SHARED2) обычно включаются источником в проект потребления (в Visual Studio добавление ссылки на проект, а не просмотр ссылки на dll). Это позволяет усилить отладку (вступая в библиотечный код), позволяет Visual Studio управлять, когда ему нужно перестраивать проекты (при изменении зависимостей), и позволяет при необходимости модифицировать библиотеки (как описано в примечании выше).

Вопросы

  • Если Боб работает над PROD1, и Алиса работает над SHARED1, как Боб может узнать, когда Алиса вносит изменения в SHARED1. В настоящее время с Mercurial, Боб вынужден вручную вытягивать и обновлять в каждом подпоре. Если он выталкивает/вытаскивает сервер из PROD_SLN-репо, он никогда не знает об обновлениях для subrepos. Это описано в Mercurial wiki. Как Боб может быть уведомлен об обновлениях в subrepos, когда он вытаскивает последнюю версию PROD_SLN с сервера? В идеале, он должен быть уведомлен (предпочтительнее во время вытаскивания), а затем должен вручную решить, какие субрепоты он хочет обновить.

  • Предположим, что ссылки SHARED1 NLog v1.0 (commit/rev abc in 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 правильным решением?

  • Есть ли лучшая структура ртути?

  • Является ли это допустимым использованием для subrepos (т.е. разработчики Mercurial отметили subrepos как особенность последнего средства)?

  • Имеет ли смысл использовать mercurial для управления зависимостями? Мы могли бы использовать еще один инструмент управления зависимостями (возможно, внутренний фид NuGet?). Хотя это будет хорошо работать для сторонних зависимостей, это действительно создаст проблему для внутренних компонентов (т.е. Если они будут активно развиваться, разработчикам придется постоянно обновлять фид, нам придется обслуживать их внутренне, и это не позволит компоненты, которые должны быть изменены потребляющим проектом (Примечание 8 и Вопрос 2).

  • У вас есть лучшее решение для программных проектов Enterprise.NET?

Ссылки

Я прочитал несколько вопросов SO и нашел этот, чтобы помочь, но принятый ответ предлагает используя специальный инструмент для зависимостей. Хотя мне нравятся функции такого инструмента, он не позволяет изменять зависимостей и совершенствовать их из проекта потребления (см. Большой вопрос 4).

Ответ 1

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

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

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

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

Это было только однажды, когда мы пошли жить с Mercurial и sub-repo, что я действительно правильно понял совет. Здесь (из памяти) приведены примеры тех проблем, с которыми мы столкнулись.

  • Ваши пользователи в конечном итоге будут бороться с процессом обновления и слияния.
  • Некоторые люди будут обновлять родительское репо, а не суб-репо
  • Некоторые люди будут оттолкнуться от субрепо, ang.hgsubstate не будет обновляться.
  • В результате вы будете "потерять" ревизии, которые были сделаны в субрепо, потому что кому-то удастся покинуть .hgsubstate в некорректном состоянии после слияния.
  • Некоторые пользователи попадут в ситуацию, когда обновление .hgsubstate было обновлено, но у sub-repo нет, а затем вы получите действительно загадочные сообщения об ошибках и потратите много часов, пытаясь понять, что происходит.
  • И если вы делаете тегирование и разветвление для выпусков, инструкции о том, как получить это право как для родительского, так и для субрепо, будут длинными десятками строк. (И у меня даже был хороший, ручный эксперт Mercurial, помогите мне написать инструкции!)

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

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

Я только хочу, чтобы я действительно оценил практические последствия всех советов, которые были сделаны ранее. в Mercurial Особенности Last Resort страница:

Но мне нужно управлять подпроектами!

Опять же, не будьте так уверены. Значительные проекты, такие как Mozilla, которые имеют тонны зависимостей, отлично подходят без использования subrepos. Большинство небольших проектов почти наверняка будут лучше без использования subrepos.


Изменить: Мысли о shell repos

С отказом от ответственности я не имею никакого опыта от них...

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

Также обратите внимание, что указанная вами страница wiki перечисляет некоторые специфические проблемы с репозиториями оболочки:

  • чрезмерно строгое отслеживание отношений между project/и somelib/
  • невозможно проверить или нажать проект/если somelib/source repo становится
  • Отсутствует четкая поддержка рекурсивного diff, log и
  • статус рекурсивного характера совершения неожиданного

Изменить 2 - выполнить пробную версию, включающую всех ваших пользователей

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

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

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

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

Возможные исходы:

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

Ответ 2

Вопрос 1:

Эта команда, когда она выполняется в родительском реплике "shell", будет перемещать все подположения и списки изменений из исходной позиции потяжения, которые отсутствуют:

hg incoming --subrepos

То же самое можно сделать, нажав кнопку "Входящие" на панели "Синхронизировать" в TortoiseHg, если у вас есть опция "-subrepos" (на той же панели).

Благодаря пользователям в Mercurial IRC-канале для помощи здесь.

Вопросы 2 и 3:

Сначала мне нужно изменить свои структуры репо, чтобы родительские репозитории были действительно "оболочечными" репозиториями как рекомендованные в hg wiki. Я доберусь до крайности и скажу, что оболочка не должна содержать содержимого, а только subrepos как дети. В общем, переименуйте src в main, переместите документы в подпоре под основным и измените папку prod на подрепорт.

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).
  • Если вам необходимо самостоятельно работать с общим lib или продуктом, есть доступная оболочка (мои репозиции, заканчивающиеся на _SLN), которая использует hg для управления изменениями зависимостей. Оболочка предназначена только для удобства, потому что она не содержит содержимого, а только subrepos.
  • При запуске выпуска общей библиотеки lib или продукта разработчик должен указать все зависимости и их hg revs/changesets (или, желательно, дружественные человеку теги), которые были использованы для создания релиза. Этот список должен быть сохранен в файле в репо для lib или продукта (SHARED1, SHARED2 или PROD), а не в оболочке. См. Примечание A ниже, как это может решить вопросы 2 и 3.
  • Если я запустил выпуск общей библиотеки или продукта, я должен поместить соответствующие теги в репо проектов и оболочку для удобства, однако, если оболочка выходит из строя (проблема, выраженная в реальном опыте в @Clare answer), это действительно не имеет значения, поскольку сама оболочка не указана и не содержит содержимого.
  • Файлы sln для Visual Studio попадают в корень разделяемого репликации lib или продукта (SHARED1, SHARED2 или PROD), а не оболочки. В результате, если я включу SHARED1 в PROD, я могу получить некоторые дополнительные решения, которые я никогда не открываю, но это не имеет значения. Кроме того, если я действительно хочу работать с SHARED1 и запускать его модульные тесты (при работе в оболочке PROD_SLN), это очень просто, просто откройте указанное решение.

Примечание A:

В отношении пункта 3 выше, если файл зависимостей использует формат, похожий на .hgsub, но с добавлением rev/changeset/tag, тогда получение зависимостей может быть автоматизировано. Например, я хочу SHARED1 в своем новом продукте. Clone SHARED1 в мою папку libs и обновление до конца или последней метки релиза. Теперь мне нужно посмотреть файл зависимостей и a) клонировать зависимость до правильного местоположения и b) обновить указанный rev/changeet/tag. Очень возможно автоматизировать это. Чтобы сделать это дальше, он мог даже отслеживать rev/changeset/tag и предупреждать разработчика о конфликте зависимости между разделяемыми библиотеками.

Отверстие остается, если Алиса активно развивает SHARED1, а Боб развивает PROD. Если Алиса обновит SHARED1_SLN, чтобы использовать NLog v3.0, Боб, возможно, никогда не узнает об этом. Если Алиса обновит свой файл зависимостей, чтобы отразить это изменение, то у Боба есть информация, он просто должен быть ознакомлен с этим изменением.

Большие вопросы 1 и 4:

Я считаю, что это проблема управления версиями, а не то, что может быть разрешено с помощью средства управления зависимостями, поскольку они обычно работают с двоичными файлами и только получают зависимости (не позволяйте делать изменения обратно в зависимости). Мои проблемы с зависимостью не уникальны для Mercurial. По моему опыту, все средства управления источниками имеют одинаковую проблему. Одним из решений SVN было бы просто использовать svn: externals (или svn копии) и рекурсивно включать в каждый компонент его зависимости, создавая, возможно, огромное дерево для сборки продукта. Однако это разваливается в Visual Studio, где я действительно хочу включить только один экземпляр совместно используемого проекта и ссылаться на него повсюду. Как подразумевается в @Clare answer и Ответ Greg на мой адрес электронной почты в список hg mail, сохраните компоненты как можно более плоскими.

Большие вопросы 2 и 3:

Существует лучшая структура, как я изложил выше. Я считаю, что у нас есть сильный прецедент для использования subrepos, и я не вижу жизнеспособной альтернативы. Как упоминалось в @Clare answer, есть лагерь, который считает, что зависимости могут управляться без subrepos. Тем не менее, я еще не видел никаких доказательств или фактических ссылок на это выражение.

Более высокий вопрос 5:

Все еще открыт для лучших идей...