Software Configuration Management // Контроль версий

    И снова здравствуйте.

    Продолжаю публиковать цикл статей о SCM — управлении конфигурацией ПО.
    3 предыдущие заметки можно прочитать в этом же блоге.

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

    Disclaimer


    Далее будут описаны основные техники, реализованные в подавляющем большинстве систем контроля версий. Как они реализуются в приложениях, которые использует читатель, оставим на откуп многочисленным руководствам пользователя, how-to, FAQ и прочим документам, коих можно найти без труда. Главное – понять, по каким принципам и зачем оно работает именно так.



    О чем речь?


    Система контроля версий – это программное обеспечение, позволяющее создавать версии элементов и работать с этими версиями, как с самостоятельными элементами. В англоязычных источниках используется термин version control systems, сокращенно VCS. Работа с версиями предполагает как создание самих версий, так и структуры для их хранения. Как правило, это или цепочки, или деревья.

    Прежде чем работать с элементами и их версиями, надо эти элементы создать, т.е. дать указать системе контроля версий взять имеющиеся объекты реального мира и поместить их под свой контроль. Вместе с самим элементом всегда создается и его первая версия.
    Чаще всего в качестве элементов для контроля версий выступают:
    • файлы;
    • директории;
    • hard- и softlinks.
    Внутри системы контроля сами элементы могут размещаться по-разному – это зависит от архитекторы VCS. Пользователю важно лишь знать, что элемент помещается внутри хранилища и работа с ним идет с помощью команд выбранного инструментария.

    Ветвление и слияние версий


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

    Название модели говорит само за себя: у растений (элементов) появляются почки и листья (версии), из них, в свою очередь, ветки. На ветках – листья (другие версии) и другие ветки. На них, опять же, произрастает всё та же растительность. В результате растет дерево, у которого крона – это множество версий. Один элемент – одно дерево.

    Зачем нужна вся эта конструкция? Неужели нельзя просто наращивать версии одну за другой? Конечно, можно. Однако это сразу ограничит возможности использования подобной системы. Если версии появляются одна за одной, то в один момент времени создать новую версию сможет только один из пользователей, работающих с системой, остальные вынуждены будут подождать. Более того, когда появится новая версия, каждому надо будет соединить свои изменения с текущими наработками. И так – пока все желающие не поместят свои наработки в цепочку версий. При этом каждый должен будет убедиться, что слияние версий не привело к поломке системы. И, кроме того, пока все изменения не будут помещены таким образом под контроль, всем из ожидающих придется сохранять промежуточные результаты где-то локально, не смешивая с тем, что находится в настоящий момент в работе. И ладно, если пара человек работает над десятком элементов – они всегда смогут договориться. А если масштабы гораздо больше? Добавим десяток человек (даже не увеличивая количества элементов) – и подобные простые цепочки полностью застопорят работу. В общем, линейная структура версий порождает множество сложностей.

    Итак, ясно, что без веток не обойтись. Но ведь не растить же ветку на малейший чих разработчика? Посмотрим, в каких же случаях отращиваются ветки. Типовые примеры веток таковы:
    • ветка для запроса на изменения — заводится для версий, создаваемых в ходе работы по запросу на изменение («девелоперская», или «сиарная», ветка);
    • интеграционная ветка — служит промежуточным хранилищем для процесса стабилизации;
    • релизная ветка — для выкладывания версий при стабилизации конфигурации (см. соответствующий раздел первой части статьи). Какие-то версии на ветке могут быть в дальнейшем объявлены частью базовой конфигурации;
    • отладочная («дебажная») ветка — для кратковременного хранения версий, в основном, для целей проверки каких-либо решений.

    Дерево версий элемента

    Схема 1. Дерево версий элемента element.c

    На схеме 1 изображен пример дерева версий. У файла element.c создана релизная ветка release_1.x, куда складываются стабилизированные версии этого элемента (1-5). Для сохранения дельты по каждому запросу на изменения заводится отдельная ветка со специальным форматом имени. В нашем случае формат имеет вид rec<номер_записи>_<имя_пользователя>, где номер_записи – это ID запроса на изменение в системе отслеживания. Для объединения дельты от разных разработчиков создаются интеграционные ветки с названиями вида int_<имя_пользователя>_<суффикс>, где суффикс хранит описание интеграции или номер стабилизируемой конфигурации. Также можно увидеть ветку для отладки, чаще всего они именуются как dbg_<имя пользователя>_<произвольный_комментарий> — на неё выкладываются проверочные варианты изменений.

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

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

    Для этого используется механизм слияния версий. Как правило, он подразумевает создание новой версии элемента, для которой в качестве основы берется базовая версия на выбранной ветке (база), и к ней применяются изменения, содержащиеся в выбранной сторонней версии (источнике). В англоязычных источниках используется термин merge («мёрж»).

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

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

    К вопросу об общих предках и о слиянии изменений: кроме ручного и автоматического, слияние может быть произведено двухпозиционным и трёхпозиционным способом. Двухпозиционное слияние производится простым сравнением двух версий и сложением их дельты (разницы между версиями элемента). Алгоритм работает по принципу diff'а или приближенно к нему: взять дельту и вставить/удалить/изменить нужные строки.

    Трехпозиционное слияние учитывает «общего предка» обеих версий и высчитывает дельту исходя из истории изменения элемента в соответствующих ветках. Соответственно, при возникновении конфликта слияния разработчику предлагается 3 версии элемента – общий предок и 2 варианта, что с этим предком стало с течением времени и изменений. Такой подход помогает оценить степень и важность дельты на обеих ветках и принять решение о необходимости интеграции конфликтного куска часто даже без участия авторов изменений.

    После того как слияние проведено, информация о нём должна быть сохранена, если это возможно. Как правило, большинство зрелых VCS имеют возможность сохранить «стрелки слияния» – метаинформацию о том, откуда, куда и в каком момент времени сливались изменения и кто это делал.

    Пример ветвления и слияния


    Рассмотрим пример – дерево версий элемента на схеме 2, продемонстрировав порядок отращивания и слияния веток на нём. Как уже можно догадаться, дерево целиком взято со схемы 1, но к нему добавлены стрелки слияния.

    Пример слияния изменений между разными ветками
    Схема 2. Пример слияния изменений между разными ветками

    Итак, в проекте производится некий продукт, в который входит файл element.c. Для того чтобы хранить стабилизированные версии, в команде принято соглашение о том, что все стабильные или базовые версии хранятся на ветке «release_1.x». Это будет называть «релизная ветка». Наш элемент не исключение, и на релизной ветке создается начальная версия 1.
    Для простоты обозначения будем описывать ветки, как если бы это были директории на диске. Соответственно, первую версию назовем /release_1.x/1.

    Далее, кто-то из менеджеров в системе отслеживания запросов на изменение (далее будем называть эту систему просто «багтрекер») завел запись номер 98, где описал новую функциональность, требуемую продукту. И, конечно же, назначил ответственным за эту задачу одного из пользователей – пусть это будет user2. user2 подумал немного и начал эту задачу решать, а по истечении какого-то времени решил выложить получившиеся исходники под контроль версий. Согласно стандартам именования, принятым в рамках проекта (CM-политикам), ветку для внесения изменений в нашем проекте называют rec<номер-записи>_<пользователь>[_<комментарии>]. Поэтому новая ветка была названа rec98_user2, а от комментариев её создатель воздержался. Работа кипит, появляется версия /release_1.x/rec98_user2/1, а потом и /release_1.x/rec98_user2/2.
    На этом пока оставим разработчика user2, пусть думает над задачей. Ведь пока он работал, в багтрекере, была зарегистрирована запись (CR) за номером 121, в которой описали новую ошибку, найденную тестерами. Запись эта была назначена на пользователя user1, и он начал успешно описанную ошибку исправлять. По мере исправления он решил завести ветку для сохранения результатов. Новую ветку, согласно проектным политикам, пользователь назвал rec121_user1. Заметим, что на момент начала работы и создания ветки кто-то уже добавил очередную стабильную версию на релизную ветку – /release_1.x/2. Поэтому ветка отращивается от последней на тот момент версии (второй). Ветка создана – можно складывать версии. Конечный результат – версия /release_1.x/rec121_user1/2.

    Что дальше? Ошибка исправлена, протестирована (эту плоскость работ мы пока оставим за кадром) – пора делать эти изменения частью стабильной конфигурации и, возможно, новой базовой конфигурацией. Здесь начинает работу CM-инженер или тот участник команды, который выполняет эту роль. С помощью лома и кувалды команды слияния он создает новую версию на релизной ветке — /release_1.x/3. Обратите внимание на стрелочку с номером 1 – она отображает как раз процесс слияния.

    Вернемся к пользователю user2 – он как раз надумал сделать некоторые изменения для своей задачи, однако решил сначала на скорую руку проверить, что получится и дать коллегам посмотреть на своё решение. Для этого он создает отладочную ветку. CM-политика проекта говорит, что она должна называться dbg_<пользователь>[_<комментарий>]. Соответственно, новая ветка будет именоваться /release_1.x/rec98_user2/dbg_user2. На ней пользователь и создает версию /release_1.x/rec98_user2/dbg_user2/1. Было решено взять полученное решение в основной код, поэтому автор сделал слияние новой дельты и той версии, от которой отращивалась ветка. Вместе с тем, пользователь почистил и оптимизировал код, чтобы было не стыдно отдавать на интеграцию – в результате получилась версия /release_1.x/rec98_user2/3. Ну а яркая стрелочка под номером 2 наглядно обрисовывает процесс слияния.

    Однако user2 узнает, что за время его работы была исправлена серьезная ошибка, на которую был заведен CR #121. И это исправление может повлиять на работу новой функциональности. Принимается решение соединить обе дельты и посмотреть, что из этого получится. Делается слияние версий /release_1.x/rec98_user2/3 и /release_1.x/rec121_user1/2 с образованием версии /release_1.x/rec98_user2/4. Ну и стрелочка слияния номер 3 также появляется. Эта новая версия проверяется на работоспособность и наличие ошибок, и принимается решение – надо интегрировать! Снова берет свои инструменты CM-инженер и делает версию /release_1.x/4, рисуя к ней соответствующую стрелку номер 4 (любое совпадение цифр – случайно).

    Однако, жизнь не стоит на месте. Пока наши два разработчика вносили и сливали вместе дельту, другие участники команды уже изменили тот же самый файл. Было заведено два CR'а – 130 и 131, назначенных затем на пользователя user3. Он их успешно закончил и сделал две ветки – по одной на запись. Поскольку задачи ставились и решались в разное время, то и ветки для их решения отращивались от разных версий на релизной ветке. В итоге получились версии /release_1.x/rec130_user3/1 и /release_1.x/rec131_user3/1, отращенные от версии /release_1.x/3.

    Есть изменения – надо их объединить, стабилизировать и сделать базовой конфигурацией, если всё нормально. Для этой цели CM-инженером, который в системе контроля версий проходит под оперативным псевдонимом user7, создается интеграционная ветка, имеющая в данном проекте вид int_<пользователь>_<номер-будущего-релиза>. Стало быть, появляется ветка /release_1.x/int_user7_1.5. На неё сливаются вместе обе дельты. Сначала изменения для записи 130, с образованием версии /release_1.x/int_user7_1.5/1. Затем – для записи 131, для неё создается версия 2 на той же ветке. Для всех операций рисуются стрелочки слияния.

    Финальный аккорд CM-инженера – слияние версии /release_1.x/int_user7_1.5/2 на релизную ветку с образованием версии /release_1.x/5. Впоследствии эта ветка станет частью базовой конфигурации продукта.
    Вот такое вот немаленькое описание маленькой картинки. Один рисунок стоит сотен слов – правду говорят.

    У внимательного читателя в голове наверняка крутится вопрос – если у нас всё делается через ветки и стрелки слияния – откуда взялась версия /release_1.x/2? Ведь к ней не ведет ни одной стрелки ни от одной ветки! Закономерный вопрос. Ответ – тоже закономерен. Да, бывают ситуации, когда изменения вносятся напрямую на релизную ветку. Например, была найдена страшная ошибка, внесенная вместе с первой версией – забыли внести в раздел revision history комментарий о том, кто же внёс изменения! Конечно, это шутка, никто не будет нарушать политику ради вот таких вот мелочей. Однако – и такое случается. Главное – точно знать, кто создал новую версию и зачем он это сделал. Лучше всего, если система контроля версий позволяет ограничивать права на создание версий для каждой ветки в отдельности. В этом случае мы дополнительно обезопасим проект тем, что дадим права на добавление версий на релизной ветке только CM-инженеру. По крайней мере, с подобным ограничением будет проще найти крайнего :).

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

    Метки


    Итак, дерево версий растет, работа команды идет своим чередом. Возникает необходимость стабилизировать результаты работы и определить базовую конфигурацию, которую в любой момент времени любой участник команды сможет взять из системы контроля версий. Стабилизация производится путем слияния версий – об этом будет рассказано чуть ниже. А вот на установлении базиса остановимся подробнее.
    Получение базовой конфигурации – это по сути своей выявление набора стабильных версий и определение способа их однозначной идентификации. Для этих целей в системах контроля версий существует механизм «навешивания меток». Метка – это цифро-буквенное обозначение, однозначно определяющее конфигурацию. Имея метку, нужно всегда уметь точно и недвусмысленно выделить конфигурацию.
    В англоязычных источниках в основном используются термины label и tag.

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

    Реализация концепции меток может различаться в разных системах. В одних (от CVS до ClearCase) метка – это атрибут версии элемента. Например, на схеме 2 метка бы вешалась прямо на одну из версий, т.е. была бы просто биркой рядом с кружком. В других системах (Subversion) под меткой понимается всего лишь одна из разновидностей веток. Каждому – своё, главное, чтобы вкладываемый смысл оставался тот же.

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

    Итог


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

    По традиции — список рекомендуемых материалов для самостоятельного вдумчивого чтения.

    1. en.wikipedia.org/wiki/Comparison_of_revision_control_software — большое сравнение существующих систем контроля версий
    2. www.cmcrossroads.com/bradapp/acme/branching — хорошая статья по политикам ведения веток, рассмотрено много разных шаблонов ветвления, подходящих для разных проектов.
    3. www.infoq.com/articles/agile-version-control — толковая статья о том, как можно организовать отращивание бранчей и их слияние при использовании agile-методик. Спасибо sse за ссылку.


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

    Продолжение следует.

    P.S. Публикую в «Управлении проектами», а не в «Системах управления версиями», просто чтобы публиковать весь цикл заметок единообразно.
    Поделиться публикацией

    Комментарии 27

      +3
      большое спасибо. разжевано довольно подробно, осталось только съесть.

      «согласно проектным политикам, пользователь назвал rec98_user1.» — по-моему тут речь идет уже о rec121_user1.

        0
        Да, опечатка… Спасибо, поправил!

        Всё-таки картинки лучше словесных описаний :)
        +1
        Хорошо написано ) как раз вся суть которую пытался выудить из сухой документации.
        Вот тут то я и познал Дзен.
          0
          Спасибо.

          А насчет дзена… Хлопок одной ладони — слабО? ;)
          0
          Можно вопрос?

          "… Однако user2 узнает, что за время его работы была исправлена серьезная ошибка, на которую был заведен CR #121 ..."

          Вопрос — как он узнает об этом? Раработчику надо постоянно следить за тем, что понакодили все другие разработчики? Рассматриваем случай, например, удаленной работы, когда прямого вербального общения за чашкой кофа между разработчиками нет.
            0
            Вопросы — нужно!

            Отвечая на вопрос, как минимум, способа два:

            1. Он столкнулся с ошибкой в поведении системы. Зашел в багтрекер проекта и сделал поиск по нужным словам. Находит запись. Запись находится в состоянии Resolved или Closed (см. предыдущую заметку цикла) — т.е. готово решение.

            2. Он столкнулся с ошибкой. Повернулся к коллегам в комнате и громко спросил: «Что-то не пашет вот это хрень при таких вот параметрам входных… Фигле?» :)

            В обоих вариантах он далее идет с систему контроля версий и с помощью СМ-политик отпределяет, какая конфигурация ему нужна. Ну и далее — по тексту.
              0
              Что-то я забыл про фразу об удаленной работе… Если она имеет место быть — вариант 2 отметается. Остается только аккуратно вести записи в системе отслеживания ошибок, чтоб народ не спамил переписку вопросами или не делал ту работу, которую до него уже сделали.
            +1
            автору спасибо за цикл статей.
            Подскажите пожалуйста грамотную и бесплатную систему контроля версий, если есть такие
              +2
              Совсем забыл вставить нужную ссылку, добавил её в заметку:
              en.wikipedia.org/wiki/Comparison_of_revision_control_software — ольшой список сравнения существующих систем.

              Я бы взял на твоём месте CVS, Subversion или Mercurial.

              CVS — прост до невозможности и при этом функционален. Для небольших задач отличная вещь. Вот тут неплохое введение:
              rsdn.ru/article/devtools/cvs.xml

              Subversion — продолжение идеи CVS, делается выходцами из команды CVS. В последние несколько лет стабильно отбирает у него аудиторию. Соответственно, есть большое коммьюнити, не пропадешь. Для понимания принципов работы прочитай
              svnbook.red-bean.com/

              Mercurial (AKA Hg) имеет другую идеологию (он из распределенных систем контроля), но тоже неплох.

              Попробуй эти и ещё что-нибудь вроде git, составь своё собственное мнение.

                0
                спасибо попробую
                  0
                  Выскажу частное мнение — лучше Git ничего не видел. Попробуйте его.
                    0
                    не возражаю, пусть пробует :) главное тобы выбрал то, что именно ему будет удобно.
              +1
              Большинство народу все же использует svn.

              Из них так же большая часть использует tortoisesvn.

              Есть грамотеи (как я) которые умеют делать только update/commit — потому что это просто благодаря клиенту.

              Когда речь заходит о ветвлении — мозг вступает в ступор — по докам все вроде ясно — а вот на практике ничего не понятно.

              Вчера потратил кучу времени на то чтобы попробывать создать ветку и затем слить её с основной линией разработки (пробывал методом тыка, особо не понимая что делаю).

              Вот собственно что я хотел бы спросить:

              Видел ли ктонибуть статью с скринами и картинками которая показывала бы как на практике в tartoisesvn клиенте работать с ветками?
                0
                Лично я навскидку не скажу. Мжет кто их апологетов подскажет…

                Возможно, придётся писать отдельную заметку :)

                Но то, что ветки в тортойзе просто так не сольёшь вместе — не повод отказываться от веток вообще. Проще перети на что-то более дружественное. К примеру, не так давно пролетала заметка про работу git совметно с svn — думаю, тебе есть смысл попробовать.
                  +1
                  byte.ho.com.ua/svn/branches.html
                  Делал примитивную инструкцию «для внутреннего пользования». Правда пока только по созданию веток. Скоро буду делать merge — может накропаю и по нему инструкцию.
                    0
                    Вот здесь
                    belonesox.habrahabr.ru/blog/69308/
                    камрад выложил лекцию по работе с SVN.
                    0
                    А вот скажите как в cvs в легкую перенести файл из одного пути в другой с сохранением истории версий. Пока делаем это шаманским способом через манипуляцию с файлами itemname,v в репозитории. Или пора пойти в ногу с прогрессом и ставить svn, git...etc???
                      0
                      Собсно, я ведь и написал, что CVS — простая система :) Да, перемещения файлов с историей там нет. Также, как нет атомарных коммитов.

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

                      А насчет прогресса — распределенные системы, по сравнению с централизованными репозитариями, имеют свои недостатки, так что я бы не стал однозначно называть это прогрессом. Скорее, ответвление в развитии. Кстати, следующая заметка будет как раз про них.
                      0
                      И еще вопросец ;) представим был у нас BuzinessLogicForSuperBuzinessActionCodeFile.cs был он вначале меленьким маленьким с парой классов в 200 строк, все четко по ТЗ;) а потом бац через пол года обнаруживается, что он уже 5000 строк и растет прям как бамбук в шри ланке;) После первого этапа рефакторинга он превращается в 20 новых файлов (на 90% просто разбивка классов по разным файлам). Так вот как бы это все оформить в системе контроле версий, чтобы можно было проследить изменения в конкретной функцию от начала ее появления в BuzinessLogicForSuperBuzinessActionCodeFile.cs до перехода ее в отдельный файл.
                        0
                        То, что git весьма неплох и даже в чем-то весьма крут — я давно знал :)
                          0
                          Кто не понял — это одна из фишек git — отслеживание вот такого перемещения ;)
                            0
                            Да ???$) пойду читать доки )))
                        0
                        Случайно набрел на этот топик. Можно запоздалый вопрос?
                        Почему изменения 130 и 131 идут через интеграционную ветку, а 121 и 98 напрямую в релизную?
                          0
                          Конечно.

                          Ветки для обоих изменений были отращены от старой версии — 3. А к моменту интеграции появилась свежая версия. И теперь их надо не только «проапмёржить» обе ветки на релизную ветку (т.е. слить изменения с последними доступными), но и слить их между собой. Поэтому вводится промежуточный шаг — ветка, отрощенная от последней версии на релизной ветке (таким образом будет решена проблема апмёржа). И на этой ветке всё сливается в одно целое (мёрж изменений между собой). И с промежуточного шага (версия 2 на интеграционной ветке) делается переход снова на релизную ветку.

                          Можно и без него — сначала отрастить ветку для изменения 130 и слить туда изменения, чтобы слить их с релизной веткой. А потом то же самое — для 131. Но это было бы более громоздко. Если учесть, что таких параллельных изменений может быть с десяток одновременно — введение интеграционных веток становится необходимым.
                            +1
                            Спасибо, разница получается довольно субъективная и не четкая, но суть понял :)
                              0
                              Внешне разница в том, сколько версий будет на стабильной релизной ветке. В описаном мной случае получается 1 версия на релтизной ветке — т.е. 1 релиз = 1 версия. Если для каждого изменения заводить по версии — получится бардак. Релизная ветка ведь содержит только те версии, которые готовы к выпуску/отгрузке/основы для работы. Так что промежуточные ингтеграционные ветки как раз служат для складирования версий, не предназначенных для широкой публики.

                                0
                                Еще раз спасибо, так стало еще понятнее.

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

                        Самое читаемое