Структура проектов в системе контроля версий

Я знаю, что существует как минимум 10 различных способов структурировать проект в системе контроля версий. Мне любопытно, какие методы используются и какие работают для вас. Я работал с SVN, TFS и, к сожалению, с VSS. Я видел, как контроль версий реализован очень плохо и нормально, но никогда не был хорош.

Вот обзор того, что я видел.

Этот пример основан на SVN, но применим к большинству VCS (не столько к распределенному контролю версий).

  1. ветвление отдельных проектов, которые являются частью site / Division / web / projectName / vb / src / [trunk | branch | tags]

  2. разветвить весь сайт, в случае, который я видел, был разветвлен весь сайт, за исключением основных компонентов. / подразделение / [ствол | ветви | теги] / web / имя проекта / vb / src /

  3. Использовать main-line по умолчанию, ветвление только тогда, когда это необходимо для значительных изменений.

Ответов (9)

Я думаю, что политики и процедуры SCM, которые принимает команда, будут сильно зависеть от процесса разработки, который они используют. Если у вас есть команда из 50 человек, в которой несколько человек работают над основными изменениями одновременно, а выпуски выпускаются только каждые 6 месяцев, для каждого имеет смысл иметь свою собственную ветку, где он может работать изолированно и объединять только изменения из другие люди, когда он хочет их. С другой стороны, если вы команда из 5 человек, сидящих в одной комнате, имеет смысл разветвляться гораздо реже.

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

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

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

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

/project
    /trunk
    /tags
        /builds
            /PA
            /A
            /B
        /releases
            /AR
            /BR
            /RC
            /ST
    /branches
        /experimental
        /maintenance
            /versions
            /platforms
        /releases

PA означает, что пре-альфа A означает, что альфа B означает, что бета AR означает, что альфа-релиз BR означает, что бета-версия RC означает, что релиз-кандидат ST означает стабильную

Есть различия между сборками и выпусками .

  • Теги в папке builds имеют номер версии, соответствующий шаблону N.x.K, где Nи Kявляются целыми числами. Примеры: 1.x.0, 5.x.1,10.x.33
  • Метки под выпусками папки имеют номер версии , соответствующий шаблону N.M.K, где N, Mи Kявляются целыми числами. Примеры: 1.0.0, 5.3.1, 10.22.33.

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

Также есть мой ответ на вопрос «Несколько репозиториев SVN против репозитория одной компании». Это может быть полезно, если вы затронете этот аспект структурирования репозитория в своем вопросе.

Пример для SVN:

сундук/

ветвь/

теги /

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

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

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

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

Изменить: для сторонних материалов это зависит. Если я могу этого избежать, у меня нет контроля версий. Я храню его в каталоге вне системы управления версиями и включаю оттуда. Для таких вещей, как jquery, я оставляю его под контролем источника. Причина в том, что это упрощает мой сценарий для нажатия. Я могу просто сделать svn export и rsync.

В своих проектах я всегда использую эту структуру.

  • сундук
    • config
    • документы
    • sql
      • исходный
      • обновления
    • src
      • приложение
      • тестовое задание
    • третья сторона
      • lib
      • инструменты
  • теги
  • ветви
  • config - используется для хранения шаблонов конфигурации моего приложения. В процессе сборки я беру эти шаблоны и заменяю заполнители токенов фактическими значениями в зависимости от того, какую конфигурацию я создаю для сборки.
  • docs - Здесь размещается любая документация по приложению.
  • sql - я разбиваю свои sql-скрипты на два каталога. Один для начальной настройки базы данных, когда вы начинаете заново, а другой - для моих сценариев обновления, которые запускаются в зависимости от номера версии базы данных.
  • src - исходные файлы приложения. Здесь я разбиваю исходные файлы на основе приложений и тестов.
  • третья сторона - сюда я помещаю свои сторонние библиотеки, на которые я ссылаюсь в своем приложении и которые недоступны в GAC. Я разделил их на основе библиотеки и инструментов. Каталог lib содержит библиотеки, которые необходимо включить в фактическое приложение. Каталог инструментов содержит библиотеки, на которые ссылается мое приложение, но они используются только для запуска модульных тестов и компиляции приложения.

Мой файл решения помещается прямо в основной каталог вместе с моими файлами сборки.

А как насчет внешних зависимостей, таких как AJAXTookit или какое-либо другое стороннее расширение, которое используется в нескольких проектах?

Контроль версий предназначен для исходного кода, а не для двоичных файлов. Храните любые сторонние сборки / jar-файлы в отдельном репозитории. Если вы работаете в мире Java, попробуйте что-нибудь вроде Maven или Ivy. Для проектов .Net простой общий диск может работать хорошо, если у вас есть приличная политика в отношении того, как он структурирован и обновляется.

Мы практикуем высококомпонентную разработку с использованием Java, у нас есть около 250 модулей в магистрали, которые имеют независимые жизненные циклы. Зависимости управляются через Maven (это лучшая практика прямо здесь), каждая итерация (раз в две недели) активно разрабатываемые модули помечаются новой версией. Трехзначные номера версий со строгой семантикой (major.minor.build - основные изменения означают обратную несовместимость, незначительные изменения означают обратную совместимость, а изменения номера сборки означают обратную и прямую совместимость). Наш конечный программный продукт - это сборка, в которую входят десятки отдельных модулей, опять же как зависимости Maven.

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

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

Мы делаем примерно следующее:

svnrepo/
  trunk/
    modules/
      m1/ --> will result in jar file
      m2/
      ...
    assemblies/
      a1/
      ...
  tags/
    modules/
      m1/
        1.0.0/
        1.0.1/
        1.1.0/
       m2/
      ...
    assemblies/
      a1/
        iteration-55/
        ...
  branches/
    m1/
      1.0/
      ...

Что касается внешних зависимостей, я не могу переоценить что-то вроде Maven: управляйте своими зависимостями как ссылками на версионные, однозначно идентифицированные двоичные артефакты в репозитории.

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

Я могу оценить логику отказа от размещения двоичных файлов в репозитории, но я думаю, что это также имеет огромное преимущество. Если вы хотите получить определенную ревизию из прошлого (обычно это более старый тег), мне нравится иметь все, что мне нужно, из svn checkout. Конечно, это не включает Visual Studio или .NET framework, но наличие правильной версии nant, nunit, log4net и т. Д. Позволяет действительно легко перейти от оформления заказа к сборке. Таким образом, начать работу так же просто, как "svn co project", за которым следует "nant build".

Единственное, что мы делаем, - это помещаем двоичные файлы ThirdParty в отдельное дерево и используем svn: external, чтобы получить нужную нам версию. Чтобы упростить жизнь, у нас будет папка для каждой использованной версии. Например, мы можем добавить в текущий проект папку ThirdParty / Castle / v1.0.3. Таким образом, все необходимое для сборки / тестирования продукта находится внутри или ниже корня проекта. По нашему опыту, компромисс с дисковым пространством того стоит.

Мы мигрировали из плохого мира VSS с одним гигантским репозиторием (более 4G), прежде чем перейти на SVN. Мне было очень сложно создать новый репозиторий для нашей компании. Наша компания очень "старой" школы. Сложно добиться перемен. Я один из молодых разработчиков, мне 45! Я являюсь частью группы корпоративных разработчиков, которая работает над программами для ряда отделов нашей компании. В любом случае я настроил наши каталоги вот так

+ devroot
    +--Dept1
        +--Dept1Proj1
        +--Dept2Proj2
    +--Dept2
        +--Dept2Proj1
    +--Tools
        +--Purchase3rdPartyTools
        +--NLog
        +--CustomBuiltLibrary

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

  • Трудно исправить производственные проблемы, если вы работаете над крупным обновлением продукта (т. Е. Потому, что мы не делаем ветвления)
  • Трудно управлять концепцией продвижения от «Dev» к «Prod». (Даже не спрашивайте о продвижении в QA)

Поскольку все артефакты и конструкции находятся в одном дереве, мы получаем что-то вроде:

  • Сундук

    • Планирование и отслеживание
    • Req
    • Дизайн
    • Строительство
      • Корзина
      • База данных
      • Lib
      • Источник
  • Развертывать

  • QA
  • MA