Бранч что это такое в программировании: Основы использования бранчинга для параллельной разработки / Хабр

Содержание

Основы использования бранчинга для параллельной разработки / Хабр

Вступление

Как справедливо заметил Fred Brooks, серебряной пули, способной поразить зверя разработки программного обеспечения, не существует. Пока возникают новые требования, идеи и находятся новые баги, программы живут и изменяются. Путь, который проходит код от версии к версии, может быть крайне сложен и извилист. К его созданию причастно много людей: разработчики, тестировщики, бизнес-аналитики, заказчики и т.п. Несмотря на то, что существует много разных видов разработки – аутсорсинг, продуктовая разработка, open-source и т.п., проблемы, стоящие перед командой, остаются примерно одинаковыми. Программное обеспечение – вещь сложная, потребитель хочет получить его как можно быстрее (и дешевле). Качество при этом должно быть приемлемым. Перед командой разработки стоит серьезная задача – наладить эффективное взаимодействие. Одним из самых главных средств коллаборации внутри команды разработчиков является сам код, который они пишут.

В данный момент на рынке получают широкое распространение распределенные системы управления версиями – DVCS. Однако, львиную долю рынка удерживают традиционные и более простые в использовании централизованные системы, такие, как, например, SVN. Система управления версиями, а вернее, ее грамотное использование, играет ключевую роль в обеспечении эффективного взаимодействия. Вспомните, как давно вы читали книгу про свою VCS? Команде, в которой нет людей, способных выстроить грамотное взаимодействие через VCS, исходя из потребностей проекта, не позавидуешь.

Управление релизами

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

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

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

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

Отступление про версионность кода

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

Как правило, одна из наших историй является основной и носит гордое имя trunk или mainline. По аналогии с деревом, от нее отходят другие ветки. В эту ветку рано или поздно попадает готовый (или не совсем) функционал и исправления ошибок.

Branch per release

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

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

Branch per feature

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

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

Интеграция между ветками

Основная ветка (mainline, trunk) является главным местом интеграции при помощи кода. Так или иначе, все изменения, сделанные разработчиками, попадают сюда. Тем не менее, она не должна превращаться в свалку нестабильного и незаконченного кода. Именно поэтому разработку новых фич рекомендуется проводить в отдельной ветке, интегрировать с основной, тестировать и только потом объединять изменения. Иными словами, mainline должна содержать достаточно законченный код, который может послужить основой для стабилизационной релизной ветки. Также, багфиксы из релизных веток, пройдя через mainline, попадают в ветки для разработки, таким образом, работа ведется над более стабильным кодом. Хорошим правилом является то, что мы не должны отдавать нестабильные изменения в другие ветки и что мы должны принимать стабильные изменения из других веток.

Рассмотрим ситуацию, отображенную на картинке:

  • В какой то момент в Mainline накопилось достаточное количество законченного функционала для выпуска Release 1.x. Для него была создана ветка, и после тестирования и стабилизации релиз ушел заказчикам.
  • Параллельно с этим стартовала разработка нового функционала:feature A и feature B, – каждая на своей ветке.
  • Баги, найденные закзачиками в Release 1.0, были исправлены на релизной ветке, и был выпущен Release 1.1. Багфиксы из него были объединены с Mainline, откуда попали в ветки для feature A и feature B. Таким образом, работа велась над более стабильным кодом.
  • Один из заказчиков по своим причинам не смог перейти на версию 1.1 и столкнулся с рядом специфичных для себя дефектов. Это было исправлено на специально сделанной для него ветке – Release 1.0.x.
  • Была закончена разработка feature A, и, после интеграции и тестирования, эти законченные изменения попали в Mainline. Ветка для feature B получает эти изменения сразу после их попадания в Mainline, чтобы работа велась над максимально актуальной версией кода.
  • Принимается решение о выпуске нового Release 2.x, включающего feature A, и для него создается ветка, на которой осуществляется сервис этого релиза, – 2. 1, 2.2. Причем, багфиксы для релизной версии 2.2 не объединяются с Mainline, так как истории этих линий разработки кода уже слишком разошлись.

При оценке плюсов и минусов такого подхода, следует принимать во внимание:

  • Feature branches не стоят на пути Continuous Integration
  • Семантические конфликты не являются специфичными исключительно для бранчинга
  • Feature toggling и Branch-by-abstraction имеют ряд своих недостатков по сравнению с Feature branches.

Интеграция через Mainline не является единственным способом интегрироваться – возможна интеграция напрямую между ветками. Martin Fowler называет такой способ Promiscuous Integration. Для такого метода интеграции очень важна коммуникация внутри проектной команды.

Стабильность веток

У такой модели есть градация стабильности, где самыми стабильными являются релизные ветки, менее стабильной является mainline, и самыми нестабильными являются ветки для разработки. Как правило, на диаграммах самые стабильные ветки отображаются выше всех, а нестабильные – ниже всех.

Накладные расходы, связанные с использованием бранчинга

С бранчингом связаны следующие издержки:

  • Механические – это те действия, которые нужно совершить, чтобы создать ветку, переключиться с ветки на ветку, объединить (merge) изменения и т.п. Как правило, такие действия трудоемки для централизованных систем и относительно просты для децентрализованных.
  • Интеллектуальные – это те усилия, которые приходится приложить, чтобы держать в голове все существующие ветки и их предназначение. Как правило, существуют инструменты, которые облегчают эту задачу. Сюда можно отнести кривую обучения для сотрудников, связанную с освоением системы управления версиями.
  • Цена за тестирование – использование параллельной разработки способно серьезно увеличить цену ручного тестирования. Отложенное тестирование позволяет сократить расходы, но при этом имеет ряд своих недостатков. Любое автоматическое тестирование значительно уменьшает цену тестирования при использовании бранчинга. В целом, этот пункт зависит от стратегии тестирования, принятой на проекте.

Типы зависимостей между ветками и способы их решения

Между ветками могут возникать следующие зависимости:

  • Архитектурные – если мы меняем архитектуру на одной ветке, другие ветки могут зависеть от этих изменений.
  • Функциональные – некоторая новая функциональность не может быть закончена или не имеет особой ценности, пока не будет закончен другой функционал, от которого она зависит.
  • Зависимости от исправления дефектов – в случае исправления дефекта на одной ветке, может существовать несколько веток, которые должны получить это изменение.

Существует несколько типовых решений для работы с таким зависимостями:

  • Саб-бранчинг – зависимая функциональность реализуется в отдельном саб-бранче и потом объединяется со всеми заинтересованными ветками.
  • Остановка – разработка на ветке замораживается, пока не будет готова нужная функциональность.
  • Архитектурная абстракция – путем абстракции в системе создаются границы, которые изолируют разные части функциональности. В этом случае проблема решается не только на уровне системы управления версиями, но и на уровне дизайна приложения.
  • Использование заглушек – в системе используются fakes/stubs, которые заменяются на реальный функционал по мере его готовности.
  • Релиз, патч, ре-релиз – система выпускается в не полностью готовом виде и патчами доводится до совершенства (эту практику в некоторых отраслях принято называть платным бета-тестированием).

Заключение

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

Анти-паттерны бранчинга:

  • Merge Paranoia – разработчики боятся объединять код, поэтому накапливается негативный эффект отложенной интеграции.
  • Merge Mania – разработчики больше времени тратят на объединение изменений, чем на разработку.
  • Big Bang Merge – ветки не обмениваются законченными изменениями, поэтому происходит одно гигантское объединение в конце.
  • Never-Ending Merge – объединение никогда не останавливается, так как всегда есть что объединять.
  • Wrong Way Merge – объединение более поздней ветки разработки с более ранней версией.
  • Branch Mania – создание большого количества веток без нужной на то причины.
  • Cascading Branches – создание веток без объединения их с mainline в конце разработки.
  • Mysterious Branches – создание ветки без причины.
  • Теmporary Branches – создание ветки с изменяющейся причиной ее существования: ветка становится временным рабочим пространством.
  • Volatile Branches – старт ветки в нестабильном состоянии или перенос нестабильных изменений в другие ветки.
  • Development Freeze – остановка всей разработки для создания веток, объединения или создания релизов.
  • Berlin Wall – использование веток для разделения людей в команде, вместо разделения областей, над которыми они работают.

Ветки (Branch) и слияния (Merge) в TFS


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

Механизм создания веток позволяет некоторую папку в хранилище кода скопировать в другую папку хранилища как есть. Т.е. на момент создания ветки (branch) мы получим две папки абсолютно идентичные друг-другу и отличающиеся только названием. Для создания ветки, достаточно на любой папке открыть контекстное меню  и выбрать:
Ветки всегда создаются на сервере, т.е. после выбора этого пункта и ввода имени папки в которую необходимо делать ветку, на сервере TFS будет произведено копирование всех файлов с папки источника в папку приемник. Кстати, TFS запоминает все такие ветки и даже может их визуализировать. Первая картинка к этой статье, как раз показывает ветки одного из наших проектов. Правда визуализация немного хромает, если преобразовать ветку в папку. Но об этом в другой раз.
Зачем могут быть нужны две папки с абсолютно одинаковым содержимым? На самом деле, все просто. Вы можете сколько угодно изголяться над одной из веток и потом просто ее удалить. Во второй ветке у вас останется исходный код. Согласитесь неплохой способ проводить эксперименты. Еще одна замечательная возможность предоставляемая TFS заключается в слиянии (merge) веток. Если две папки связаны между собой в результате Branche, то выбрав одну из них, мы все изменения можем слить в другую (на картинке выше пункт merge):

В открывшемся окне мы можем выбрать в какую из веток выполнить слияние и указать, перенести все различия между ветками или можем выбрать конкретные наборы изменений которые необходимо перенести. Хранилище само определяет в чем заключается разница файлов хранящихся в ветках и вносит на машине пользователя необходимые изменения в локальные файлы. Т.к. в отличии от Brunch проходящего на сервере, Merge происходит на локальной машине и его нужно возвращать на сервер в рамках набора изменений. Это связано с тем, что при внесении изменений параллельно в двух ветках, при их слиянии могут возникнуть сложности с автоматическим объединением изменений в разных ветках одного и того же файла. И эти изменения придется выверять и подтверждать вручную.

Теперь о том, как мы эти ветки используем у себя.

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

Если еще не запутал, то во-вторых, ветки у нас применяются для разделения проекта. Разработка нового функционала ведется в основной папке проекта. Ближе к концу спринта, когда основной функционал реализован, все изменения перемещаются в заранее подготовленную ветку Prerelease. В этой ветке идет стабилизация версии перед релизом. После того, как QA дает отмашку на релиз, все изменения перемещаются в ветку Release и разворачиваются в эксплуатацию. Благодаря этим трем веткам всегда есть возможность спокойно проводить стабилизацию перед релизом, не опасаясь, того, что кто-то начнет писать новый функционал и сломает тот код, который в рамках стабилизации уже был подвергнут регрессу. Также, наличие ветки с кодом идентичным развернутому в Operation позволяет править ошибки обнаруженные в процессе эксплуатации именно в том коде, который эксплуатируется. И даже если в ветке разработки поправили модель данных или сломали вообще все, есть возможность внести минимальные изменения в стабильный код и развернуть его после проверки в эксплуатацию. Выглядит это примерно так:

Ну и объединяя две предыдущие картинки, схема веток Core и проектов будет выглядеть так:

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

Branching стратегии в Git — bool.dev

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

Branching & merging анти-паттерны:

  • Merge Paranoia – когда девелоперы боятся мержить код, из-за последствий которые могут возникнуть (мерж конфликты) поэтому накапливается негативный эффект отложенной интеграции.
  • Merge Mania – когда разработчики больше времени тратят на объединение изменений, чем на разработку.
  • Big Bang Merge – В ветки не подмерживаются изменения, как следствие в конце происходит один гигантский мерж в конце.
  • Never-Ending Merge – непрерывный мержинг, так как всегда есть что мержить.
  • Wrong Way Merge – объединение более поздней бранчи с более ранней версией.
  • Branch Mania – создание большого количества веток без видимой на то причины.
  • Cascading Branches – создание веток без мержа их в mainline в конце разработки.
  • Mysterious Branches – создание ветки без причины.
  • Temporary Branches – создание ветки с изменяющейся причиной ее существования: ветка становится «permanent temporary workspac’ом».
  • Volatile Branches – старт ветки в нестабильном состоянии или перенос нестабильных изменений в другие ветки.
  • Development Freeze – остановка всей разработки для создания веток, объединения или создания релизов.
  • Berlin Wall – использование веток для разделения людей в команде, вместо разделения на таски/фичи, над которыми они работают.

Git Flow (Feature Based Development)

Схематично Git Flow можно описать так:

Git Flow — одна из первых крупных стратегий ветвления, которая завоевала популярность. Git Flow описывает несколько веток для разработки, релизов и взаимодействия между ними.

Главные ветки:

По сути модель перекочевала с других существующих моделей. Репозиторий содержит 2 главные ветки:

master — дефолтная ветка знакомая каждому, кто работал с гитом. Параллельно в этой концепции существует еще одна ветка develop.

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

В Git Flow мы можем использовать следующие типы веток:

  • Feature branches
  • Release branches
  • Hotfix branches

Feature branches

  1. Могут бранчеватся от develop
  2. Должны вмержится в develop
  3. Naming convention: любые названия кроме masterdeveloprelease-*, или hotfix-*

Release branches

  1. Могут бранчеватся от develop
  2. Должны вмержится в develop и master
  3. Naming convention: release-*

Помните, до того как вмержить код в релиз ветку, необходимо добавить ей тег с версией релиза (например «0. 9 hotfix»)

Hotfix branches

  1. Могут бранчеватся от master
  2. Должны вмержится в develop и master
  3. Naming convention: hotfix-*

Плюсы и минусы Git Flow:

Плюсы:

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


Минусы:

  1. Git Flow может замедлять работу, когда приходится ревьювить большие пулл реквесты, когда вы пытаетесь выполнить итерацию быстро.
  2. Релизы сложно делать чаще, чем раз в неделю.
  3. Большие функции могут потратить дни на мерж и резолв конфликтов и форсировать несколько циклов тестирования.
  4. История проекта в гите имеет кучу merge commits и затрудняет просмотр реальной работы.
  5. Может быть проблематичным в CI/CD сценариях.

GitHub Flow

Он выглядит почти так же как и Git Flow, но фиксированная ветка всего одна — master; всё остальное принадлежит тематическим ветвям. Тематические ветви, в свою очередь, создаются в форках — клонированных копиях репозитория. То есть центральный репозиторий тематических веток не содержит. В том числе и после слияния, так как метки веток при этом снимаются и их головы становятся анонимными.

GitLab Flow

Как и в GitHub Flow, фиксированная ветка всего одна — master, всё остальное принадлежит тематическим ветвям. Однако, если в том случае релизы размещались в коммитах master-a, то здесь для каждого релиза создаётся своя, отдельная ветка. Причём никакого мержа этих веток с parent’ом не производится. Если ветка отбранчевалась, значит она будет жить своей жизнью, получая исправления ошибок в виде отдельных коммитов (возможно, портированных из head/master с учётом накопившейся разницы в функционале между ветками).

Environment branches в GitLab flow

Release branches в GitLab flow

Trunk Based Development (TBD)

На официальном сайте эта концепция отображается такой схемой:

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

Что такое Trunk Based Development (TBD) ?

TBD прозволяет бизнесу тестировать бизнес-гипотезы «As soon as possible». Тк позволяет очень быстрыми итерациями релизить код на продакшн.

В Trunk Based Development можно выделить следующие особенности:

  1. Ветки живут максимум 2 дня
  2. Feature Flags
  3. Branch By Abstraction
  4. Continuous Code Review (это концепция из экстримального программирования которая говорит о том, что код который попадает на ревью, должен ревьювится как можно быстрее)
  5. master всегда готов к деплою, даже если в нем есть не готовые фичи

Feature Flags

Feature Flags — это концепция в которой у нас есть файл конфигурации, где прописано какая из фич включена/выключена и в коде существует проверка которая позволяет пропускать какую-то логику, например


if (configurationManager. getParameter("someFuncIsEnabled")) {
    // do some stuff
} else {
    // do default logic
}

    Приемущества использования Feature Flags

    • Можем мержить и деплоить код, который еще не готов
    • A/B тесты
    • Шаринг кода между недоработанными фичами, за счет мержа всего кода в master

    Branch By Abstraction

    Trunk Based Development предлагает вместо создание ветки для фич, создавать ветку на изменение одной абстракции.

    Представим, что у нас есть объект Car, у которой есть абстракция “передние колоса” и “задние колеса”, которые мы хотим заменить на другой тип колес. В случае с feature branch, мы бы разработали реализацию нового типа колес в 1 бранче, с Branch By Abstraction все немного сложнее.

    Рассмотрим рисунок и шаги которые нам помогут раскрыть порядок действий при TBD подходе

    1. Создаем ветку, оборачиваем переднее колесо в абстракцию, отправляем Pull Request, мержим
    2. Создаем ветку, описываем новый тип передних колес и добавляем feature flag переключения типов колес, отправляем Pull Request, мержим
    3. Создаем ветку, оборачиваем заднее колесо в абстракцию, отправляем Pull Request, мержим
    4. Создаем ветку, описываем новый тип задних колес и добавляем feature flag переключения типов колес, отправляем Pull Request, мержим
    5. Включили в проде новый тип колес, убедились, что все ок
    6. Удаляем старые колеса отдельными Pull Request`ами

    И что нам это дало?

    • Частые интеграции! Мы уже пришли ранее к тому что нужно часто интегрировать маленькие кусочки кода(CI), теперь при таком подходе можно делать «микрокусочки».
    • Постепенное изменение/рефакторинг кода. Вместо переделки всего разом, меняем постепенно, шарим изменения до того как закончим большую задачу.
    • Возможность переключения на другие фичи. В случае, если нужно переключиться на другую задачу, мы можем смежить последнее изменения и вернуться к доработке потом.

    Continuous Code Review

    Ревьювим чужие pull requests, сразу после того как отправили свой. Из-за этого что пулл реквесты маленькие(изменение одной абстракции), их ревью занимает не более чем пару минут, Если от создания пулл реквеста до аппрува прошло 10 минут, то это приемлемый результат, если больше 1 часа, то это считается очень плохим результатом.

    Что нам дает концепт Continuous Code Review
    • Шаринг знаний. Все понимают как меняется сервис, переиспользуют код, подсказывают друг-другу лучшие практики.
    • Снижение тех долга за счет того что мы все рефракторим на ходу.
    • Ускорение деплоя. (пулл реквест весит не пару дней, а несколько минут и может сразу отправляться в прод)

    Плюсы и минусы Trunk Based Development

    Плюсы:

    • Позволяет быстро выполнять итерации и при этом поддерживать качество.
    • Хорошо работает в сценариях CI/CD.
    • Можно релизиться как можно чаще, в том числе несколько раз в день.

    Минусы:

    • Лучше всего работает когда у вас команда состоит с опытных разработчиков.
    • Наполовину готовые функции, неправильно реализованными feature flag’ами, может вызвать проблемы.
    • Изначально может вызвать некоторые проблемы, если нет хорошего покрытия тестами или уверенности в стабильности системы.

    Где и Как использовать Git Branch: Ветвление в Git

    VPS

    access_time

    16 января, 2020

    hourglass_empty

    3мин. чтения

    Git – это инструмент, используемый разработчиками для контроля версий их приложений. Он очень популярен и используется на многих серьёзных проектах, таких как GNOME и другие. Одной из важнейших функций Git является контроль над ветками разработки, что помогает улучшить процесс реализации проекта. Вот почему в этом руководстве мы покажем вам, как использовать git branch, или ветки Git. Любой проект, в том числе и проекты на основе VPS, определённо выиграет от этой замечательной функции.

    Ветвление в Git помогает нам организовать несколько версий приложения. Вот почему очень важно уметь работать с этой функцией. Это руководство расширит ваши базовые знания Git.

    Что Такое Git Branch

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

    Использование Git Branches имеет несколько преимуществ. Тем не менее, мы хотим подчеркнуть следующие два:

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

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

    Где и как использовать Git Branch

    Не забудьте получить доступ к вашему серверу по SSH перед запуском. Вот руководство по PuTTY, которое вам поможет!

    Работать с Git branches довольно просто, это видно из самих команд. Но, как и в большинстве других случаев, чем больше у вас веток, тем сложнее управлять ими.

    В любом проекте Git мы можем просмотреть все ветви, введя следующую команду в командной строке:

    git branch

    Если вы не создали ни одной Git branch, в терминале не будет выходных данных. Создать ветку действительно просто:

    git branch [new_branch]

    Затем нам нужно перейти в новую ветку Git, которую вы только что создали. Для этого мы запустим следующую команду:

    git checkout [new_branch]

    Результат сообщит нам, что мы перешли в новую ветку. Мы назвали её тестовой, так что мы увидим следующее сообщение:

    Switched to branch ‘test’

    Теперь в этой новой ветви разработки мы можем создать столько модификаций кода, сколько захотим, без необходимости что-либо менять в основной Git branch. Как мы видим, это поддерживает готовность программы к добавлению новых частей кода.

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

    git branch

    Есть кое-что, о чём мы должны помнить, создавая новую ветку разработки. Во-первых, мы должны сделать commit в основную ветку, чтобы Git понял, что это master branch. Если мы этого не сделаем, мы получим ошибку. Итак, сначала сделайте commit, а затем создавайте ветки разработки.

    Если мы хотим удалить ветку из Git, мы можем сделать это с помощью следующей команды:

    git branch -d [branch_name]

    Однако, мы не можем находиться в той ветке, которую хотим удалить. Сначала мы перемещаемся в главную ветку и уже оттуда удаляем только что созданную:

    git checkout master
    git branch -d test

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

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

    git merge [branch]

    Как видите, основные функции ветки Git довольно просты. Вам просто нужно знать основы и стараться поддерживать порядок в своём проекте.

    Выводы

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

    В этой статье мы научили вас основам работы с ветками Git.

    Традиционно, мы рекомендуем прочитать официальную документацию Git касательно веток, чтобы понять, как выполняются сложные операции. Удачной разработки!

    Узнайте о ветвлении с помощью Bitbucket Cloud

    Цель

    Это обучающее руководство научит вас основным приемам создания, просмотра и объединения веток, а также работы в них с помощью Git и Bitbucket Cloud.

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

    • Клонирование: копирование удаленного репозитория из Bitbucket Cloud в локальную систему.
    • Добавление или индексирование: принятие внесенных изменений и их подготовка к добавлению в историю Git.
    • Коммит:: добавление новых или измененных файлов в историю Git для репозитория.
    • Pull (извлечение): добавление в локальный репозиторий новых изменений, внесенных в репозиторий другими разработчиками.
    • Push: отправка изменений из локальной системы в удаленный репозиторий

    Если вы не знаете основ Git, ознакомьтесь с обучающим руководством Изучение Git с помощью Bitbucket Cloud, и вы быстро войдете в курс дела.

    Для чего нужно ветвление

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

    • Одновременная работа нескольких команд в одном репозитории.
    • Совместная работа в Bitbucket Cloud с привлечением участников команды из любого уголка мира.
    • Разработка одновременно по множеству независимых направлений без заморозки кода.

    Настройка

    Чтобы у вас было ощущение командной работы в общем репозитории Bitbucket, мы предоставляем вам форк нашего общедоступного репозитория.

    Что такое форк?

    Форк — это альтернативный способ сохранения клона или копии. Термин «форк» (в программировании) происходит от одноименного системного вызова в Unix, который создает копию существующего процесса. Таким образом, форк, в отличие от ветки, не зависит от исходного репозитория. Если исходный репозиторий удален, форк остается. Если вы делаете форк репозитория, вы получаете этот репозиторий вместе со всеми его ветками.

    1. Перейдите по ссылке tutorials/tutorials.git.bitbucket.org
    2. Нажмите + > Fork this repository (Сделать форк этого репозитория) в левой части экрана.
    3. Измените Name(Имя) на уникальное для вашей команды имя репозитория и нажмите Fork repository (Сделать форк репозитория).
    4. Создайте для репозитория каталог, в который можно будет легко перейти. У вас должно получиться что-то подобное:
       $ mkdir test-repositories $ cd test-repositories/ $ test-repositories
      В предыдущем примере мы создали каталог test-repositories с помощью команды mkdir (make directory — создать каталог) и перешли в этот каталог с помощью команды cd (change directory — сменить каталог).
    5. Клонируйте репозиторий, созданный с помощью форка, в созданный каталог. Это должно выглядеть примерно так:
       $ git clone https://[email protected]/dstevenstest/mygittutorial.bitbucket.io.git Cloning into 'mygittutorial.bitbucket.io'... remote: Counting objects: 12392, done. remote: Compressing objects: 100% (12030/12030), done. remote: Total 12392 (delta 8044), reused 564 (delta 360) Receiving objects: 100% (12392/12392), 2.72 MiB | 701.00 KiB/s, done. Resolving deltas: 100% (8044/8044), done. $ cd mygittutorial.bitbucket.io/
      В этом примере репозиторий клонируется с помощью команды git clone и создается каталог mygittutorial.git.bitbucket.io.

    Создание ветки и внесение изменений с помощью процесса ветвления

    В рамках этой ветки вы добавите цитату на свой веб-сайт.

    1. Создайте ветку с помощью команды git branch.
       $ git branch test-1
    2. Переключитесь на только что созданную ветку с помощью команды git checkout.
       $ git checkout test-1 Switched to branch 'test-1'
    3. Просмотрите список локальных веток с помощью команды git branch.
       $ git branch master * test-1
    4. Обновите файл editme.html, добавив в него цитату. Вы можете написать что-то подобное:
        
      Это цитата, и она мне нравится.
      Цитата: искусство цитирования
    5. Добавьте изменение.
       git add editme.html
      Примечание. Ваше изменение пока не отправлено в историю Git, оно находится в состоянии «ожидания». Мы рассматривали эту тему в разделе Сохранение изменений.
    6. Выполните коммит изменения и добавьте к нему описательный комментарий.
       git commit editme.html -m'added a new quote' [test-1 063b772] added a new quote 1 file changed, 3 insertions(+), 3 deletions(-)
      Примечание. Теперь изменение добавлено в историю Git в виде отдельного коммита. Мы рассматривали эту тему в разделе Сохранение изменений.
    7. Отправьте это изменение в Bitbucket с помощью команды git push.
       git push fatal: The current branch test-1 has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin test-1
      Вы увидите ошибку, так как при первой отправке новой ветки, созданной локально, необходимо назначить эту ветку.
    8. Отправьте ветку и изменение с помощью команды git push.
       $ git push origin test-1 Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 363 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: remote: Create pull request for test-1: remote: https://bitbucket.org/dstevenstest/dans.git.bitbucket.org/pull-requests/new?source=test-1&t=1 remote: To https://bitbucket.org/dstevenstest/dans.git.bitbucket.org.git * [new branch] test-1 -> test-1
      Эта команда говорит системе, что репозиторий origin является репозиторием назначения для этой новой ветки.
    9. Откройте учебный репозиторий и нажмите Branches (Ветки). Вы должны увидеть обе ветки: ветку master и ветку test-1. Это будет выглядеть примерно так:

    Создание и извлечение удаленной ветки, переключение на удаленную ветку

    При работе в команде вам, скорее всего, придется извлекать ветки, созданные другими участниками команды, с помощью команд pull или fetch, а также помещать ветки в Bitbucket командой push. В этом примере рассматриваются некоторые основы создания веток и работы с ветками, созданными другими участниками.

    1. ВеткиПерейдите в учебный репозиторий в Bitbucket и нажмите Branches (Ветки). Вы должны увидеть что-то подобное:
    2. Нажмите Create branch (Создать ветку), дайте этой ветке имя test-2 и нажмите Create (Создать).
    3. Скопируйте команду git fetch в диалоговое окно переключения веток. Это должно выглядеть примерно так:
       $ git fetch && git checkout test-2 From https://bitbucket. org/dstevenstest/dans.git.bitbucket.org * [new branch] test-2 -> origin/test-2 Branch test-2 set up to track remote branch test-2 from origin. Switched to a new branch 'test-2'
    4. Введите в окне терминала команду git branch. Должен появиться примерно такой список веток:
       $ git branch master test-1 * test-2
      Ветка, отмеченная звездочкой (*), является активной. В любом рабочем процессе с ветвлениями важно помнить, с какой веткой вы работаете.
    5. Введите команду git status. Вы увидите что-то подобное:
       $ git status On branch test-2 Your branch is up-to-date with 'origin/test-2'. nothing to commit, working tree clean
      Вы можете видеть, с какой веткой вы работаете и соответствует ли в настоящий момент состояние этой ветки состоянию удаленной ветки (origin).
    6. Для переключения на другую ветку используйте команду git checkout. Эта команда будет выглядеть примерно так:
       $ git checkout test-1 Switched to branch 'test-1' Your branch is ahead of 'origin/test-1' by 3 commits.  (use "git push" to publish your local commits)
      Самое важное правило, которое нужно помнить при работе с ветками: проверяйте, что вы вносите изменения в нужную ветку.

    Отправка изменений и создание запроса pull

    Настало время отправить на проверку первые изменения и выполнить слияние ветки.

    1. Нажмите +> Create a pull request (Создать запрос pull). Вы увидите, что ветка test-1 указана как источник, а ветка master — как целевая ветка.

      Так как этот репозиторий создан с помощью ответвления (форка) существующего репозитория, в качестве ветки назначения указана главная ветка master репозитория, к которому мы применяли команду ответвления.

      Чтобы исправить это, вам необходимо изменить ветку назначения (ветку, куда будет выполнено слияние ваших изменений) с tutorials/tutorials.git.bitbucket.org на ваш репозиторий.

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

    2. Нажмите Create pull request (Создать запрос pull).
    3. Добавьте в запрос pull комментарий, выбрав строку в области Diff (Сравнение) (область, в которой отображается изменение, внесенное вами в файл editme.html).
    4. Нажмите Approve (Подтвердить) в верхнем левом углу страницы. Безусловно, в реальном запросе pull у вас будут комментарии от проверяющих.
    5. Нажмите Merge (Выполнить слияние).
    6. (Необязательно) Добавьте Commit message (Комментарий к коммиту) с дополнительными сведениями.
    7. Выберите для операции слияния коммитов одну из двух возможных стратегий:
      • Merge commit (Коммит слияния): сохраняет все коммиты из исходной ветки и делает их частью ветки назначения. Этот вариант аналогичен выполнению команды git merge —no-ff в командной строке.
      • Squash (Склеивание): во время слияния исходной ветки в ветку назначения коммиты будут склеены. Этот вариант аналогичен выполнению команды git merge —squash в командной строке.
      Подробнее об этих двух стратегиях слияния.
    8. Нажмите Commits (Коммиты) — и вы увидите, как ваша ветка встраивается в общую схему изменений.

    Удаление ветки и получение данных с помощью команды pull из главной ветки (master) в локальную рабочую ветку

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

    Зачем удалять ветку?

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

    Для чего выполнять запрос pull для главной ветки и выполнять ее слияние с веткой test-2?

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

    1. Откройте терминал и выполните команду git status. Результат должен выглядеть примерно так:
       $ git status On branch test-1 nothing to commit, working tree clean
      Как видно, мы находимся в ветке, где чуть раньше вносили изменения, и сейчас в ней изменений нет. Теперь, когда мы закончили работу, эту ветку можно удалить.
    2. Переключитесь на главную ветку командой команду git checkout master. Результат должен выглядеть примерно так:
       git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. 
      Обратите внимание: в сообщении указано, что ветка находится в актуальном состоянии. Это относится только к локальной ветке. Мы знаем это, поскольку только что слили изменение в главную ветку, но не извлекли его командой pull из удаленного репозитория в локальную систему. Мы сделаем это на следующем шаге.
    3. Выполните команду git pull. Результат должен выглядеть примерно так:
       $ git pull remote: Counting objects: 1, done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://bitbucket.org/dstevenstest/dans.git.bitbucket.org 2d4c0ab..dd424cb master -> origin/master Updating 2d4c0ab..dd424cb Fast-forward editme.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
      Дело в том, что когда вы извлекаете изменения из удаленного репозитория, система Git запускает ускоренное слияние, чтобы интегрировать внесенные изменения. Она также указывает количество файлов и строк, в которых были сделаны изменения.
    4. Выполните команду git branch -d {имя_ветки}, чтобы удалить ветку test-1. Результат будет выглядеть примерно так:
       $ git branch -d test-1 Deleted branch test-1 (was 063b772)
      Как видно, команда удалила ветку, и эта ветка содержала указанный хеш последнего коммита. Это безопасный способ удаления ветки: система Git не позволила бы удалить ее, если бы в этой ветке были изменения, ожидающие коммита. Однако это не помешает ей удалить изменения, коммит которых в истории Git был выполнен, однако они не были слиты в другую ветку.
    5. Переключитесь на ветку test-2 с помощью команды git checkout.
       $ git checkout test-2 Switched to branch 'test-2' Your branch is up-to-date with 'origin/test-2'.
    6. Слейте главную ветку в свою рабочую ветку с помощью команды git merge master test-2. Результат будет выглядеть примерно так:
       $ git merge master test-2 Updating 2d4c0ab..dd424cb Fast-forward editme.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
      Помните о следующем.
      • Очень важно, какая ветка активна. Если вы хотите слить ветку master в ветку test-2, вам необходимо переключиться на ветку test-2 (сделать ее активной). То же самое верно, если вы хотите слить ветку test-2 в ветку master: вы должны переключиться на ветку master.
      • Для того чтобы узнать, какая ветка активна в данный момент, используйте команду git branch (активная ветка будет отмечена звездочкой) или git status (с ее помощью можно узнать, на какой ветке вы находитесь и есть ли в ней ожидающие локальные изменения).

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

    Знакомство с процессом ветвления

    Рабочий процесс с функциональными ветками Git является эффективным способом командной работы в Bitbucket. В этом рабочем процессе разработка функциональных возможностей выполняется в ветках, которые отделены от главной ветки (master). Это позволяет множеству разработчиков работать над своими задачами, не затрагивая основной код.

    Начните с главной ветки

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

    Создайте новую ветку

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

    Обновление, добавление, коммит и отправка изменений

    Работайте над этой функцией и делайте необходимые коммиты, как обычно при использовании Git. Завершив работу, отправьте коммиты, чтобы обновить функциональную ветку в Bitbucket.

    Отправьте код на проверку

    Чтобы получить отзыв на свой код, создайте в Bitbucket запрос pull. Затем можно добавить проверяющих и убедиться, что все работает правильно, прежде чем выполнять слияние.

    Исправление функции по отзывам

    На этом этапе коллеги комментируют и утверждают отправленные коммиты. Исправьте функцию по их отзывам локально, а затем сделайте коммит и отправьте изменения в Bitbucket. Обновления отобразятся в запросе pull.

    Выполните слияние своей ветки

    Если другие пользователи вносили изменения в репозиторий, перед слиянием может потребоваться разрешение конфликтов слияния. Если ваш запрос pull утвержден и не содержит конфликтов, вы можете добавить код в ветку master. Выполните слияние из запроса pull в Bitbucket.

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

    Интерфейс GIT в Visual Studio | Microsoft Docs