Макет репозитория (или ловушка) для ветвления общих библиотек (и сохранения вашего здравого смысла) - PullRequest
4 голосов
/ 09 сентября 2009

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

Наш макет репозитория выглядит так:

(макет А)

Web
  branches
  tags
  trunk
Libraries
  Foo
    branches
    tags
    trunk
  Bar
    branches
    tags
    trunk
WindowsClient
  branches
  tags
  trunk
DB
  branches
  tags
  trunk

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

Это означает, что вместо этого мы могли бы перейти к такой структуре:

(макет B)

Web
  branches
  tags
  trunk
    main
    libs
      Foo
      Bar
    DB
WindowsClient
  branches
  tags
  trunk
    main
    libs
      Foo
      Baz
    DB

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

Окончательный вариант таков:

(макет C)

branches
tags
trunk
  Web
  Libraries
    Foo
    Bar
  WindowsClient
  DB

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

Мне нужен макет репозитория (Макет D) , который позволяет мне:

  • Разветвление проекта и его зависимых библиотек одновременно
  • Совместное использование библиотек между проектами

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

Так что вопрос:

Есть ли макет D, что это такое и как его использовать?

Редактировать: Поскольку кажется, что нет базовой схемы, которая бы дала мне эти свойства, я бы очень заинтересовался какой-нибудь функцией ловушки, чтобы доставить меня туда. Было бы особенно хорошо, если бы он работал с клиентом TortoiseSVN (Windows GUI), поскольку именно это мы и используем.

Ответы [ 7 ]

1 голос
/ 18 сентября 2009

Перейдите к варианту C, а затем выполните заказы следующим образом:

svn co -N ...../branches/mybranch workingcopy
cd workingcopy
svn update Web Libraries

Теперь, когда вы выполняете svn-операции (включая простое "svn update"), он будет работать только с каталогами Web и Libraries.

Также читайте о разреженных каталогах .

1 голос
/ 09 сентября 2009

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

На самом деле они будут разветвленными , если они находятся в одном и том же хранилище, и вы использовали относительный внешний синтаксис, например, ^\mylib\trunk. Такие внешние ссылки превращаются в обычные (скопированные) папки. Вы должны явно передать --ignore-externals в svn copy, чтобы подавить это поведение, иначе вы получите копии, как в макете B. ( edit : я был почти уверен, что это сработало кстати, но я не могу воспроизвести это поведение. Должно быть, я ошибся, извините!)

Тот факт, что внешние объекты не всегда разветвляются автоматически, не должен быть проблемой. Я бы использовал макет B, созданный с помощью svn:externals (не копий), разветвил проект (с помощью --ignore-externals), затем после ветвления адаптировал svn:externals, чтобы он указывал на правильные ветви библиотеки.

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

1 голос
/ 09 сентября 2009

Нет хорошего ответа на вопрос "как выложить мой репозиторий для этого рабочего процесса?"потому что программное обеспечение не поддерживает это.Я бы посоветовал перейти к макету B, разветвить код библиотеки и переключить соответствующий svn:external на эту ветвь по мере необходимости или сразу же, если ваши ветки должны ссылаться на версию библиотеки вне соединительной линии.

Я собирался предположить, что Git справляется с этим лучше, но это не намного.Поскольку его подмодули ссылаются на отдельные репозитории несколько иначе, чем внешние, и каждая копия репозитория является «веткой», это может быть незначительным улучшением.

0 голосов
/ 23 сентября 2009

Пройдя через подобную проблему, я знаю вашу боль. Трудно управлять зависимостями в хранилище с иерархическими компонентами.

В нашем проекте было несколько продуктов (которые вы отправляете клиентам), состоящих из различных компонентов (многие из которых являются общими). У нас был каждый компонент со своей собственной трилогией tags/branches/trunk, очень похожей на ваш макет A (что, в конце концов, рекомендуется).

Мы использовали svn:externals, чтобы предоставить каждому продукту способ указать зависимые компоненты (и подкомпоненты и т. Д.), И сначала он работал достаточно хорошо. Но в конечном итоге мы столкнулись с проблемами, такими как то, что происходит, когда вы переходите, что если одному продукту нужно закрепить на определенной ревизии зависимость, как вы распространяете теги через внешние элементы для управления конфигурацией (так что вы действительно можете восстановить то же дерево!) , и так далее. Так что svn:externals решите некоторые проблемы, но представьте другие.

Я закончил тем, что написал несколько сценариев, чтобы справиться с этим, но это все еще было немного запутанным. К счастью, вы можете использовать привязки Python-Subversion для написания приложений Python для манипулирования свойствами, так что вы можете делать такие вещи, как распространение тегов через зависимые компоненты и т. Д.

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

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

0 голосов
/ 22 сентября 2009

Это сложная проблема, у которой нет хорошего дешевого решения; Привет-решение состоит в том, чтобы использовать систему управления « линейки программных продуктов » (например, pure: : варианты ). Однако большинству из нас не приходится тратить это совпадение на систему контроля исходного кода.

Поэтому я бы пошел с LayoutA - с каждой версией библиотеки отдельно. Однако я хотел бы поставить « trunk » под « branch », так как это ветвь, и я хотел бы, чтобы все ветви были на одинаковом расстоянии от вершины.

Следующий шаг скорее зависит от вашей системы сборки, я предполагаю, что Visual Studio здесь.

  • В корне каждого дерева веток продукта
  • Создайте файл bat, определяющий переменную среды, которая содержит имя ветви каждой библиотеки, которую вы хотите использовать
  • Отредактируйте файлы проекта Visual Studio для ссылки на библиотеки, используя эти переменные среды
  • Запустите командный файл из командной строки Visual Studio перед запуском Visual Studio

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

Если у вас есть только 1 или 2 общие библиотеки, и они могут быть изменены только для одного продукта за раз, например. добавить новые методы для проекта, над которым сейчас ведется работа. Я бы подумал о том, чтобы иметь разные ветви библиотеки для каждого проекта и использовать привязку слиянием SVN 1.5 для отслеживания происходящего. (Когда изменения будут стабильными, слияние с грузовиком, затем слияние с грузовика в каждую ветку проекта, когда это необходимо)

(Если у вас есть сотни библиотек, вы должны отслеживать, какие версии каждой библиотеки нужны друг другу. Это начало становится очень сложным!)

Мне не нравится svn: external, так как из файловой системы вашего локального ПК не понятно, что происходит. Однако svn: external - работоспособное решение.

0 голосов
/ 19 сентября 2009

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

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

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

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

Когда вы явно изменяете версии библиотеки, подобные этой, вы также получаете запись в своем проекте, которая говорит: «Я сейчас использую эту версию библиотеки X», которая дает вам хорошее представление о история в вашем проекте относительно того, когда что-то работало и когда именно все изменилось.

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

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

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

Я обнаружил, что эта система работает довольно хорошо, и после перемещения рабочих мест в такое место, где это не работает, я испытываю тоску по предыдущему способу работы. Есть проблемы, в основном связанные с библиотеками, в зависимости от того, есть ли рекурсивные внешние или нет. Мое предположение заключается в том, чтобы идти рекурсивно, если это не вызывает проблемы (или чрезмерной боли), а затем перейти к «вырожденной» модели, где проект должен знать об определенных «глубоких» зависимостях, даже если он не использует их напрямую. Кроме того, решите, куда вы будете помещать свои определения externals и придерживайтесь его, нет ничего более раздражающего, чем поиск этих свойств svn: externals в случайных папках в разных проектах. Положить их на корень ствола можно.

0 голосов
/ 09 сентября 2009

Способ, который мы решили, - это использование общих внешних библиотек, используемых несколькими проектами. Общая библиотека размещается в своем собственном репозитории со своими стволом / ветвями / тегами.

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

Часть сценария сборки для зависимого проекта (обычно запускается по требованию как init / update, а не как часть стандартной сборки), затем проверяет наличие новых версий и захватывает двоичный файл. Это дает преимущество согласованного управления версиями общего артефакта между зависимыми проектами и сокращает время сборки, поскольку все зависимые проекты могут использовать одну и ту же версию.

Чтобы помочь с управлением версиями, в настоящее время мы используем Apache Ivy , который поддерживает такие вещи, как временные зависимости (то есть выборка зависимостей) и ограничения версии (например, этот проект должен использовать только версию Foo 1.2. *) .

...