Недавно заспорил о том как стоит бранчится и обнаружил внезапно, что тема не так проста, как мне казалось изначально. Естественно, полез в инет и почитал о разных стратегия и обнаружил таки пару вещей, которых не знал. Чем и спешу поделиться.
Кстати, не могу найти нормальный перевод слову бранчится. Как действие слово «ответвляем» меня вполне удовлетворяет, а вот применительно к такому предложению «как стоит ответвляться/ветвится» звучит странно…. Мдя…Будь же ты, проклят герундий.
Ладно, назад к теме. Увы, серебряной пули среди стратегий нет. Так что, пробежимся по стратегиям.
Кстати, сразу напишу, что идет речь о том как бранчиться для создания постоянных (а не временных) веток. То есть, я не затрагиваю вопрос о том, что если мы делаем какие-то крупные и длинные изменения, что стоит их делать в отдельной ветке, которая будет удалена по окончанию работы.
— Простейшая стратегия
Если есть один человека, один продукт и одна версия то можно вообще не бранчиться. Все делается в trunk’е, ну разве что, можно помечать стабильные билды и релизовые билды.
Ну, естественно такая халява долго не держится. Буквально через пару выпущенных версии уже появляется необходимость сделать hotfix какому-то из ваших заказчиков и тогда приходится переходить к следующему этапу.
— Стратегия разумного минимума
Бранчимся только тогда, когда это уже абсолютно необходимо. То есть, как в прошлом методе ведем все в trunk, если надо сделать hotfix, то ответвляем от версии, которая отдана заказчику и там делаем исправления и мержим назад в trunk все исправления.
— Стратегия обычной средней фирмы
Естественно в какой-то момент, становится понятно, что для любой выпущенной версии нужно будет сто процентов делать хоть какие-то исправления, так что можно сразу нарезать бранчи для каждого релиза наперед. Да и плюс, людей прилично, кто-то работает над исправлением для предыдущей версии, кто-то работает над новой функциональность в trunk’е.
Вот тут уже начинаются расхождения.
а) Ранний бранчинг
Ветка создается в тот момент, когда начинается любая работа над релизом и вся работа делается в этой ветке, иногда это мержат в trunk (чаще всего в стабильных точках). Я знаю, зачем это делают на больших размерах (чуть позже напишу), но не совсем понимаю, зачем это делают в средних фирмах. В средних фирмах получается, что trunk оказывается фактически лишним.
б) Поздний бранчинг
Ветка создается только в тот момент, когда уже нужно стабилизироваться и что-бы туда не сыпали случайные изменения. Кстати, это стандартная стратегия из SVNBook.
Кстати, на этом размере появляется еще один вопрос в перпендикулярной плоскости. Как организовывать структуру веток. Можно так
/Product1/trunk
/Product1/branch1
/Product1/branch2
/Product2/trunk
/Product2/branch1
…
а можно
/trunk/Product1
/trunk/Product2
/branch1/Product1
/branch1/Product2
…
Мне по душе больше первый метод. Я считаю, что продукты должны быть по возможности независимые друг от друга и поэтому должна быть возможность отдельно их выпустить, а вывод должна быть возможность отдельно бранчить Product1 и отдельно Product2.
Если же они насколько связаны, что не имеет смысла их выпускать отдельно, то скорее у вас не два продукта, а один продукт с несколькими модулями.
Кстати, именно второй вариант (где бранчат все продукты вместе) для меня был не то, чтобы новостью, но я раньше с ним не сталкивался.
Ну и последняя добавка. Опять же с любой веткой для релиза можно поступать теме же описанными стратегиями.
— Стратегия крупной фирмы
А вот тут собственно говоря наступает самое интересное, то о чем я прочел.
Предположим, что у нас есть большое количество веток в которых мы ведем разработку. Например для версий 5.5, 6.4 и 6.5 и 7.0. Ну и еще параллельно ведется пару долгоиграющих проектов, который затрагивают несколько продуктов. Что мы хотим — иметь возможность перетягивать исправления. Условно говоря фиксы из 5.5, чтобы можно было применить в 6.4, 6.5, 7..0 и долгоиграющих проектах.
Проблема состоит в том, что кросс-бранчинговый мержинг — штука и сложная и опасная. И если начать туда сюда напрямую тасовать изменения, то можно во первых легко запутаться, а во вторых огрести много приключений.
Собственно откуда берутся приключения? Первое, мы плохо можем знать другую ветку. Человек работающий над 5.5 достаточно плохо осведомлен о специальном проекте, который собран из частей 6.5 и 7.0. Получается если он закидывает изменения — то он не знает того когда. Если же люди работающие на этим специальным проектом пытаются вытянуть изменения из 5.5, то они тоже могут не слишком хорошо знать код.
В таком случае весь мержинг делают через ветки от которых были порождены текущие. То есть, чтобы из 5.5 перенести в 6.5 то из 5.5 мержат в 5.0, из 5.0 мержат в trunk, trunk мержат в 6.0, 6.0 мержат в 6.5.
С одной стороны, количество мержингов становится ГОРАЗДО больше с другой стороны, мержиться с веткой от которой была порождена текущая всегда гораздо проще и гораздо больше шансов, что нам знакомы обе ветки.
Далее, мержинг проводится в тот момент, когда ветка стабильна (идеально в релизовом состоянии). И еще, как только от ветки что-то бранчится, то после этого в этой ветке не ведется никакой разработки. Условно говоря, как только сделан branch 2.0, то в trunk не кладется никакой код кроме мержей. Таким образом в trunk мержится только стабильный код и поэтому trunk остается в достаточно стабильном виде.
Что-то я замудро описал. В целом, разработки делаются только в «листах» дерева (веток от которых не было ничего ответвлено) и для переноса изменений, мы идем по дереву вверх и вниз. Такой метод сложен, но зато позволяется все НЕ листы ветки держать в стабильном состоянии. И это снижает вероятность проблем при следующих мержах.
Вот собственно эта схема для меня и была новая.