Это перевод достаточно важной статьи про GitLab Flow, альтернативе Git flow и GitHub flow. Статья была написана в 2014, так что скриншоты успели устареть. Тем не менее сама статья более чем актуальна:




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


  • Не описан точным образом весь рабочий процесс,
  • Вносится ненужная сложность,
  • Нет связи с трекером задач (issue tracker).

Мы хотим представить вам GitLab flow — чётко определённый набор практик, решающий эти проблемы. Он объединяет в одну систему:




Эта статья описывает все аспекты GitLab flow, включая работу с ветками, интеграцию с задачами, непрерывную интеграцию и развёртывание. Её цель — помочь новым командам перейти на git и сразу внедрить простые, прозрачные и эффективные правила работы с ним.


Four stages (working copy, index, local repo, remote repo) and three steps between them


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


  1. Добавить изменения из рабочей области проекта в индекс (область подготовленных файлов, staging area);
  2. Сделать коммит на основе индекса;
  3. Запушить коммит в удалённый репозиторий.

Освоение этих действий — первый шаг в изучении git. Следом идет работа с ветками.


Multiple long running branches and merging in all directions


Если не устанавливать никаких правил работы с ветками, в репозитории начинает расти энтропия:


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

Для решения этих проблем обычно внедряется некая стандартная модель работы, например git flow или GitHub flow. Мы считаем, что у всех этих моделей есть потенциал для улучшения, поэтому мы разработали GitLab flow.


Git flow и его ограничения


Git Flow timeline by Vincent Driessen, used with permission


Модель рабочего процесса Git flow появилась одной из первых и стала довольно широко известной. Она предполагает наличие основной ветки master, ветки для накопленных изменений develop, а также отдельных веток для фич, релизов и хотфиксов. Разрабатываемые изменения мержатся в develop, оттуда в релизные ветки, и в итоге попадают в master. Git flow достаточно подробно и четко определяет рабочий процесс, но его сложность порождает две проблемы.


Во-первых, разработчики должны использовать ветку develop, а не master, потому что последняя зарезервирована под релизный код. Это противоречит привычной практике называть master основную ветку, от которой ответвляются прочие ветки, и в которую мержится результат. Нередко разработчики по ошибке мержат какие-то изменения только в master, забывая про develop. А большинство графических интерфейсов к git по умолчанию считают основной веткой именно master, поэтому в них приходится каждый раз что-то переключать или настраивать.


Во-вторых, лишняя сложность появляется из-за веток релизов и хотфиксов. Большинство команд, особенно небольших, может легко обойтись без них. Сегодня большинство организаций придерживается практики непрерывной доставки (continuous delivery), которая предполагает, что код из основной ветки можно развёртывать на продакшен (production, то, что предоставляется пользователям).


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


GitHub flow – более простой вариант


Master branch with feature branches merged in


В противовес сложной модели git flow был разработана модель GitHub flow. В ней есть только master и feature-ветки. Это упрощение привело к успешному внедрению GitHub flow множеством компаний. Компания Atlassian предложила похожую стратегию. Но, в отличие от GitHub, они предпочитают делать ребейз (rebase), а не мерж веток в master.


Мерж всех изменений в master и частое развёртывание позволяют не писать код «в стол», а сразу выпускать изменения. Это соответствует идеям бережливого (lean) производства и непрерывной доставки. Но множество вопросов остаются без ответа: когда именно нужно развёртывать и в каких окружениях, как выпускать релизы, как связать всё это с трекером задач. GitLab flow отвечает на все эти вопросы.


GitLab flow: ветка production


Master branch and production branch with arrow that indicate deployments


GitHub flow строится на предположении, что вы можете развернуть ваш код на продакшен в любой момент, сразу после мержа feature-ветки в master. Это верно для SaaS-приложений, но неверно в множестве других случаев. Бывает, что вы не можете влиять на точное время релиза. Например, вы выпускаете приложение под iOS и каждое обновление должно пройти валидацию в AppStore. Другой пример — когда релизить можно в строго определённое время (например, с 10 до 16 в будние дни, когда все сотрудники находятся на рабочем месте), но замержить ветку в master можно в любое время.


Для управления выпуском кода в продакшен GitLab flow предлагает использовать специальную ветку production. Настройте автоматическое развёртывание кода из этой ветки при каждом изменении в ней. Теперь для релиза достаточно сделать мерж из ветки master в production. Состояние ветки даст вам точную информацию о том, какая версия кода сейчас выпущена, а приблизительное время выпуска можно будет определить по времени создания мерж-коммита. Если вам нужна абсолютная точность, можно в процессе развёртывания создавать новый тег с timestamp'ом в описании.


GitLab flow: ветки для нескольких сред


Multiple branches with the code cascading from one to another


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


Предположим, что у вас есть несколько сред: стейджинг (staging), пре-продакшен (pre-production) и продакшен (production). Код из master автоматически развёртывается на стейджинг. Как только вы готовы развернуть его на пре-продакшен, вы создаете мерж-реквест из master в pre-production. Соответственно, мерж из pre-production в production означает окончательный релиз. Такой процесс, когда все коммиты проходят через ветки в строго определенном порядке, гарантирует, что изменения прошли тестирование во всех средах.


Если вам нужно быстро «протащить» хотфикс на продакшен, то можно реализовать его в обычной feature-ветке, а потом открыть мерж-реквест в master, не удаляя ветку. Теперь, если код в master проходит тесты и жизнеспособен (правильно настроенная непрерывная доставка должна гарантировать это), вы можете замержить ветку хотфикса последовательно в pre-production и production. Если же изменения требуют дополнительного тестирования, то вместо немедленного мержа нужно открыть мерж-реквесты в те же ветки. В «экстремальном» случае отдельная среда может создаваться для каждой ветки. Так делается, например, в Teatro.


GitLab flow: релизные ветки


Master and multiple release branches that vary in length with cherry-picks from master


Ветки релизов понадобятся вам только если вы выпускаете ПО для внешних клиентов. В таком случае каждая минорная версия будет храниться в отдельной ветке (2.3-stable, 2.4-stable и т.п.).


Стабильные (stable) ветки должны создаваться от ветки master. Их нужно создавать как можно позже, чтобы минимизировать добавление хотфиксов в несколько веток. После того, как релизная ветка создана, в неё можно включать только исправления серьёзных багов. Следуйте правилу "upstream first": всегда, когда это возможно, сначала делайте мерж исправлений в master, и только оттуда — cherry-pick в релизную ветку. Благодаря этому правилу вы не забудете сделать cherry-pick исправлений в master и не встретите тот же самый баг в следующем релизе. Правило "upstream first" применяется в том числе в Google и Red Hat. Каждый раз, когда в релизную ветку добавляется исправление бага, нужно повысить третье число в номере версии (по правилам семантического версионирования). Обозначьте эту версию новым тегом в git. В некоторых проектах используется ветка stable, которая всегда указывает на тот же коммит, что и последний релиз. Ветка production (или master в правилах git flow) в таком случае не нужна.


GitLab flow: мерж/пулл-реквесты


Merge request with line comments


Мерж-реквест или пулл-реквест создаётся в системе управления git-репозиториями. Это запрос на мерж одной ветки в другую, подобно задаче, назначаемый на какого-либо исполнителя. GitHub и Bitbucket используют термин «пулл-реквевст», потому что первое необходимое действие — сделать пулл предлагаемой ветки. GitLab и Gitorious используют термин «мерж-реквест», потому что заключительное действие — собственно, мерж ветки. Далее в этой статье мы будем называть это мерж-реквестом.


Если вы работаете над веткой больше, чем пару часов, имеет смысл поделиться промежуточным результатом с коллегами через мерж-реквест. Не назначайте его на кого-либо, а просто упомяните (командой /cc @имя) ваших коллег в описании реквеста или в комментарии — они получат уведомление. Это будет означать, что реквест не готов к мержу, но по нему уже можно давать обратную связь. Вы можете явным образом обозначить, что работа над реквестом не завершена. Для этого начните заголовок реквеста с [WIP] или WIP:, то есть "Work in progress". Такой мерж-реквест даже нельзя будет замержить через интерфейс GitLab (хотя по-прежнему можно вручную через git).


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


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


В GitLab есть стандартная практика — «защищать» долгоживущие ветки (такие как master или production). Защита ветки не позволяет участникам с уровнем доступа "Developer" пушить в неё любые изменения.


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


GitLab flow: интеграция с задачами (issues)


Merge request with the branch name 15-require-a-password-to-change-it and assignee field shown


GitLab flow позволяет вам явным образом связывать код и задачи из трекера.


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


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


Хороший пример: «Как администратор, я хочу иметь возможность удалить пользователя без ошибок».
Плохой пример: «Админ не может удалять пользователей».


Приступая к работе над задачей, создайте новую ветку от ветки master. Её название должно начинаться с номера тикета, например 42-admin-can-remove-users.


Когда вы завершили работу над задачей или хотите получить промежуточную обратную связь, открывайте мерж-реквест. Помните о возможности отправить оповещение (/cc @имя) коллегам и отметке WIP:.


В момент, когда вы считаете, что работа завершена, назначьте реквест на ревьюера и уберите WIP:.


Ревьюер может принять (замержить) реквест как через командную строку, так и через кнопку в интерфейсе реквеста. Нажатие на кнопку автоматически создаёт мерж-коммит, описание которого формируется на основе описания реквеста. Мерж-коммит полезен тем, что он сохраняет в истории время и обстоятельства мержа. Поэтому, по умолчанию, коммит создаётся всегда, даже если был возможен "fast-forward merge", когда master просто переключается на последний коммит вашей ветки. В git эта стратегия называется "no fast-forward" и используется с командой git merge --no-ff. GitLab EE и .com предлагают выбор поведения при мерже, подробности далее в статье.


Feature-ветка обычно больше не нужна после мержа, поэтому интерфейс реквеста позволяет удалить её. Предположим, что ветка была замержена, после чего вы обнаружили какие-то недоработки и переоткрыли задачу. Если старая ветка удалена, можно создать новую ветку с тем же именем и продолжить разработку в ней. Как правило, одной задаче соответствует не более одной ветки, но в одной ветке может решаться несколько задач.


Связывание задач и мерж-реквестов


Merge request showing the linked issues that will be closed


В сообщении коммита, либо в описании мерж-реквеста можно упомянуть задачу по её номеру, используя слово-триггер, например: fixes #14, closes #67. При этом GitLab публикует в упомянутой задаче комментарий с обратной ссылкой на коммит или реквест. А в мерж-реквесте появляется список связанных задач. Когда вы замержите код в основную ветку, связанные задачи будут отмечены как выполненные. Обратите внимание: триггеры распознаются только на английском, то есть fixes #14 сработает, а исправляет #14 — нет.


Если вы хотите создать ссылку на задачу, но не закрывать её, напишите просто её номер: "Duck typing is preferred. #12".


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


Rebase и объединение коммитов


Vim screen showing the rebase view


Git позволяет объединить (squash) несколько коммитов в один или поменять их порядок с помощью команды rebase -i. В GitLab EE и .com вы можете сделать это непосредственно перед мержем через веб-интерфейс. Это имеет смысл, если в процессе работы вы сделали несколько небольших коммитов, но хотите чтобы в master попал один, или если хотите выстроить коммиты в логическом порядке.


Помните, что коммиты, которые уже попали в удалённый репозиторий и, тем более, в стабильную ветку, ребейзить нельзя. Причина этого в том, что-нибудь мог оставить ссылку на них или вытащить (cherry-pick) в свою ветку. Ребейз меняет идентификаторы (SHA-1) коммитов, потому что фактически создаёт из них новые коммиты. В результате ваши изменения появляются в истории git с несколькими разными идентификаторами, что приводит к путанице и ошибкам. Ребейз также затрудняет ревью кода, так как теряется информация о том, какие изменения были внесены после ревью. Если объединяются коммиты разных авторов, то информация об авторстве тоже будет потеряна. Это лишает авторов указания на их авторство, а ещё мешает работе git blame (показывает, в каком коммите и кем изменялась каждая строка).


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


Изменения, которые уже попали в master, нельзя стирать из истории и не так просто отменить через git revert. Если все коммиты были объединены в один с помощью rebase, можно применить revert к этому единственному коммиту. Однако мы убеждены, что в объединении коммитов больше вреда, чем пользы. К счастью, git умеет отменять мерж-коммиты. Если вы передумали и хотите вернуть отменённый мерж-коммит, то применяйте revert к коммиту, созданному в результате первого revert. Git всё равно не позволит вам замержить один и тот же коммит дважды.


Чтобы это стало возможным, необходимо сначала создать этот мерж-коммит. Поэтому, если вы мержите вручную, добавляйте опцию --no-ff. Система управления репозиториями сделает это за вас в момент принятия мерж-реквеста.


Не меняйте порядок коммитов с помощью rebase


List of sequential merge commits


Git позволяет вам сделать ребейз feature-ветки на master, в результате чего коммиты этой ветки оказываются в истории после коммитов в master. Это позволяет сделать мерж без мерж-коммита и в результате у вас получается простая линейная история. Но здесь действует то же правило, что и с объединением коммитов: не трогайте то, что уже попало в удалённый репозиторий. Мы рекомендуем не ребейзить даже промежуточные результаты вашей работы, отданные на ревью через мерж-реквест.


Использование rebase вынуждает вас многократно разрешать одни и те же конфликты. В некоторых случах это можно сделать командой git rerere (reuse recorded resolutions). Но ещё проще — вовсе не ребейзить и разрешать конфликты всего один раз, при мерже. Чем с меньшим количеством мерж-конфликтов вы сталкиваетесь — тем лучше.


Чтобы избежать лишних конфликтов, нужно не слишком часто мержить master в feature-ветки. Давайте разберём три возможных причины мержа master куда-либо ещё: «подтягивание кода» (leveraging code), мерж-конфликты и долгоживущие ветки.


Если вам нужно «подтянуть» изменения из master в feature-ветку — обычно можно обойтись вытаскиванием (cherry-pick) одного нужного коммита.


Конфликт при мерже feature-ветки обычно разрешается с помощью создания мерж-коммита. Если строки вашего файла могут находиться в произвольном порядке, то можно избежать некоторых конфликтов с помощью настройки gitattributes. Например, в файле .gitattributes репозитория GitLab есть строка CHANGELOG merge=union, и это позволяет мержить список изменений автоматически.


Последняя ситуация, когда необходимо мержить master куда-то ещё — это использование долгоживущих веток, которые периодически нужно обновлять до актуального состояния. Мартин Фаулер в своей статье о feature-ветках рассуждает о практике непрерывной интеграции (continuous integration, CI). Мы в GitLab немного путаем CI с тестированием веток.


Цитируя Фаулера: "Я знаю людей, которые утверждают, что практикуют CI, потому что выполняют сборку каждой ветки и каждого коммита, и даже могут при этом использовать CI-сервер. То, что они делают, называется непрерывной сборкой (continuous building). Это тоже благородное дело, но интеграции-то нет, а значит, нет и «непрерывной интеграции»."


Решение заключается в том, что feature-ветки должны существовать недолго и быстро мержиться. Можно ориентироваться на срок в один рабочий день. Если разработчик держит ветку для реализации задачи более одного дня, подумайте о том, чтобы раздробить задачу на более мелкие части. В качестве альтернативы можно использовать «переключатели фич» (feature toggles).


Для работы с долгоживущими ветками есть две стратегии:


  • Стратегия непрерывной интеграции предполагает, что вы мержите master в долгоживущую ветку в начале каждого дня,
    чтобы предотвратить более сложные мержи в будущем.
  • Стратегия «точки синхронизации» (synchronization point strategy) разрешает мержить только строго определённые коммиты,
    например отмеченые тегом релизы. Линус Торвальдс рекомендует именно такой способ, потому что код релизных версий лучше изучен.

GitLab EE предлагает возможность делать rebase непосредственно перед принятием мерж-реквеста. Вы можете включить эту возможность в настройках проекта, выбрав Merge Requests Rebase.


Merge request settings


Перед принятием мерж-реквеста выберите опцию rebase before merge.


Merge request widget


GitLab попытается сделать rebase перед мержем. Если rebase без конфликтов невозможен, будет выполнен обычный мерж.


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


Используйте эмодзи в задачах и мерж-реквестах


Emoji bar in GitLab


Общепринятая практика — выражать одобрение или неодобрение с помощью кнопок +1 и -1.
В GitLab вы можете использовать эмодзи, чтобы, например, «дать пять» автору хорошей задачи или мерж-реквеста.


Пуш и удаление веток


Remove checkbox for branch in merge requests


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


Когда ветка замержена в master, её можно удалить из репозитория. В GitLab и подобных ему системах это можно сделать непосредственно во время мержа. Это гарантирует, что при обзоре веток в системе управления репозиториями, вы увидите только те, над которыми действительно идёт работа. А ещё это освобождает имя и позволяет назвать им новую ветку. Это необходимо, если вы переоткрыли задачу и вам нужна новая ветка и новый мерж-реквест.


Делайте коммиты часто и пишите к ним корректные сообщения


Good and bad commit message


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


Сообщение коммита должно описывать ваши намерения, а не пересказывать содержимое кода — его и так несложно посмотреть. Важно то, зачем вы сделали этот коммит.


Пример хорошего сообщения: «Скобминировать шаблоны, чтобы разгрузить интерфейс пользователя».


Некоторые слова портят сообщение, потому что ничего конкретного не значат: «поменять», «улучшить», «отрефакторить» и т.п. Слова «чинит», «исправляет» тоже лучше не использовать, только если вы не пишете "fix" (только на английском) в конце сообщения и вместе с номером задачи. Если вы хотите больше подробностей, рекомендуем прочитать отличную статью из блога Tim Pope.


Тестирование перед мержем


Merge requests showing the test states, red, yellow and green


В старых моделях рабочего процесса сервер непрерывной интеграции (CI server), как правило, запускал тесты только на ветке master. Поэтому разработчикам приходилось нести ответственность за то, чтобы не сломать master. В GitLab flow разработчики создают свои ветки от master, поэтому её всегда нужно поддерживать «зелёной». Поэтому каждый мерж-реквест нужно тестировать, прежде чем мержить. Инструменты CI, такие как GitLab CI или Travis, умеют показывать результаты сборки (build) непосредственно в мерж-реквесте.


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


Если ветки мержатся быстро и конфликтов при мерже нет, то обычно можно рискнуть и замержить, не тестируя результат. Если конфликты всё-таки есть, то можно замержить master в feature-ветку (т.е. наоборот), после чего ваш сервер CI запустит тесты на полученном коммите. Если feature-ветки живут дольше, чем несколько дней, стоит подумать об уменьшении масштаба ваших фич.


Мерж чужого кода в ваш код


Shell output showing git pull output


Когда начинаете работу над задачей, всегда создавайте feature-ветку от последнего коммита в master. Только если ваша работа требует изменений из определённой ветки, начните с этой ветки. Если впоследствии вам понадобилось замержить другую ветку, обязательно объясните необходимость этого в сообщении мерж-коммита. Пока вы не запушили вашу ветку в общий репозиторий, можно ребейзить её на master или другую ветку. Не нужно мержить стабильные ветки в свои feature-ветки, если в этом нет строгой необходимости. Линус Торвальдс вообще запрещает мержить стабильные ветки в feature-ветки, за исключением крупных релизов.


Ссылки



Перевод с английского выполнил nick_volynkin с небольшой помощью переводческой артели «Надмозг и партнеры», http://nadmosq.ru

Что практикуете?

Проголосовало 198 человек. Воздержалось 67 человек.

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

Поделиться с друзьями
-->

Комментарии (20)


  1. symbix
    02.12.2016 10:42

    Использую git flow с минимальной модификацией (master=develop, production). Всегда merge --no-ff и тег, соответствующий фиче, ребейз в ветку — иногда и без фанатизма: считаю, что достоверность истории важна и имеет практическую ценность, а линейность мастера — чистая вкусовщина.


  1. mwambanatanga
    02.12.2016 10:57

    Использую git flow с минимальной модификацией (stable, unstable и веточки с фичами). Готовые веточки ребейсятся в unstable; готовый к релизу код из unstable мерджится в stable.


  1. dmkuznetsov
    02.12.2016 12:40

    Используем feature baranches и создание релизных веток от мастера при выкате


  1. edubrovka
    02.12.2016 14:37

    В базе у нас тоже git-flow, но слегка модифицированный. Добавили еще release ветку по принципу hotfix, но только от develop — для стабилизации. И еще support ветки, которые начинаются с какого-то тега в master, куда мы через cherry-pick переносим какие-то единичные критичные фиксы в минорный релиз прошлой мажорной версии.
    Вокруг этого постепенно был написан скрипт который автоматизирует создание и завершение hotfix/release веток, проставляет версии, тэги, сливает, заливает, защищает, и т.п. Делает много рутинной работы. Наш начальник уже сам как-то пару релизов делал: gf -y -i 123 -a finish -b hotfix — закончить hotfix под тикетом 123, собрать локально и залить в репозиторий не переспрашивая.
    Дополнительно к этому в gitlab используем защищенные ветки: develop, master, support, release, hotfix — только основная команда может в них мержить, аутсорс поставляет merge request'ы, которые мы проверяем и заливаем, если все хорошо на ревью. Плюс у нас еще есть custom hooks которые смотрят, чтобы ветки аккуратно назывались, например, feature/prjid-123-abc-def-xyz и в каждом коммите была ссылка на тикет типа PRJID-123.


    Несмотря на все это есть еще простор для автоматизаций.


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


    1. tim_fake
      03.12.2016 13:14

      Поделитесь рецептом скрипта?

      Особенно интересует:

      проставляет версии, тэги, сливает, заливает, защищает,
      и
      custom hooks которые смотрят, чтобы ветки аккуратно назывались, например, feature/prjid-123-abc-def-xyz и в каждом коммите была ссылка на тикет типа PRJID-123.


      1. edubrovka
        04.12.2016 21:22

        Выложить скрипт просто так не могу: собственность компании. Я поговорю с шефом по поводу открытия кода на гитхабе, но там нет ничего особенного и сверхъестественного, так собрание мини-хаков и гит-трюков.


        У нас jira + java + maven + gitlab. Приведу пока описание без кода, что было сделано.


        1. Скрипт в целом параметризован с помощью getopts. Он вызывает процедуры в порядке, необходимом для получения состояния в соответствии с правилами git-flow.
        2. Версии. Тут мы пользуемся функциональностью maven versions:set/commit и help:evaluate для project.version. Потом можно просто использовать git tag -m "$ticket" -m 'Release 1.2' $version. Аналогично для веток.
        3. Слияние работает только если нет конфликтов. Чтобы избежать очевидных конфликтов как то начало релиза 1.2.0-SNAPSHOT и переход к 2.0.0-SNAPSHOT в разработке. Очевидно, что при слиянии веток у нас будут конфликты в pom.xml. Можно автоматически слить ветки используя стратегию ours. Тогда конфликты проигнорируются при последующих слияниях.
        4. Jira. У нее есть Rest API которое можно дернуть, чтобы залогиниться и получить заголовок по номеру задачи. Этой функциональностью мы пользуемся, чтобы при автоматических операциях проставить например, PRJ-1234 Hotfix 1.2.3
        5. Gitlab. У него также есть Rest API. Им мы пользуемся для того, чтобы защитить ветку в начале разработки. Например release/1.2. Скрипт вызывает функцию типа gitlab_api release/1.2 protect.
        6. custom hooks. Тут написан простой рецепт на ruby — я вообще начинал с примеров. Там есть конфигурация, какой идентификатор проекта и что проверять. Скрипт просто собирает регулярное выражение с возможными названиями веток и проверяет подходит ли присланная ветка под шаблон. Наряду с этим скрипт смотрит, чтобы в каждом присланном коммите был тикет типа PRJ-\d+, пустая вторая строка и первая строчка не слишком длинная. Единственный трюк был — получить список именно новых коммитов.
        7. idempotent. Где возможно старался сделать скрипт идемпотентным, чтобы можно было запускать подряд несколько раз, если слияние не удалось из-за конфликтов и пришлось их вручную разруливать (rerere тут не получилось заставить работать). Например, sed для того, чтобы обновить <tag>release-1.2.3</tag> на <tag>release-1.2.4</tag>.

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


        Загвоздка тут, все это написано под конкретно наши нужды. Выделить общую часть будет сложно. Есть уже git-flow для bash, который уже многое делает, но нам нужны еще дополнительные фунуции и шаги


  1. vintage
    02.12.2016 17:05
    +1

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


    1. symbix
      02.12.2016 17:38

      Что мешает откатиться на предыдущую версию-то? Хоть по тегу, хоть тупо по sha?


      1. EndUser
        14.03.2017 23:11

        Надо полагать, означает бычка.
        Ниже отображена проекция бычка.
        И реакция человека, не знающего про голограммы на проекцию бычка.


        1. symbix
          03.12.2016 15:39

          А зачем? Есть production-ветка (как бы она ни называлась), на каждый релиз ставится тег, если обнаружились проблемы — просто выкладываем предыдущую версию.

          Вариант, когда критическая проблема обнаружилась не через 0-1-2 дня — это аварийная ситуация. Тут простого решения нет. Я бы бросил все силы на hotfix.


          1. vintage
            03.12.2016 16:09

            Затем, чтобы спокойно решить проблему, не останавливая деплой других фич, а не чинить не готовую к релизу фичу впопыхах. У нас последовательность такая:


            1. Решили выложить релиз.
            2. Собрали готовые к релизу фичи в отдельной ветке.
            3. Протестировали, что всё работает.
            4. Если фичи конфликтуют — чиним прямо в релизной ветке или собираем новый релиз без некоторых из фич.
            5. Тестируем релиз на реальных данных.
            6. Выкладываем на прод и проверяем, что всё ок.
            7. Вливаем в мастер.

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


  1. sentyaev
    02.12.2016 17:15
    +1

    Немного сумбурно написано. Смешали и методологию и сам продукт, и git, и best practices.
    Пришлось пару раз перечитать.

    По сути, для Git flow нужны всего две ветки:
    1. develop, для разработки
    2. master, для стабильной версии
    Все остальное можно либо не использовать, если у вас в команде полтора человека, либо использовать, то что вам нужно.
    У меня например нет релизных веток, т.к. деплоится каждая законченная фича.

    В GitLab flow мне не нравится, что репозиторий с кодом, берет на себя дополнительную ответственность, а именно начинает управлять деплойментом (ветки production, pre-production etc). По моему мнению это ответственность CI и CD, и удобнее управлять релизами используюя соответствующие инструменты.

    Простой пример.
    Git flow:
    У нас баг на проде. Берем master, фиксим, прогоняем по окружениям (сборка, автотесты, автодеплоймент и т.д.).
    Учитывая, то, что мы берем один и тот же код, а еще лучше один и тот-же пакет/контейнер у нас пропадает куча рисков.
    GitLab flow:
    У нас баг на проде. В какой ветке его фиксить, production или pre-production? Ведь возможно в pre-production он уже пофикшен. Логично, что в production, но есть вероятность, что придется следить и помнить о мелких расхождениях в этих ветках.

    Во-первых, разработчики должны использовать ветку develop, а не master, потому что последняя зарезервирована под релизный код.

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

    Следовательно, можно исключить ветки релизов и хотфиксов и всю лишнюю работу

    Тут все зависит от процесса. У кого-то деплой на прод раз в час, а у кого-то раз в месяц. Ветки релизов удобны, когда выпускаете сразу набор фич. Соответственно у каждого релиза может быть свой CI и свое окружение для тестов и экспериментов.
    Почему нужно отказываться от веток для хотфиксов — непонятно. Я любую фичу или баг делаю в отдельной ветке. Т.е. непонятно в чем сложность делать и мерджить ветки в git?

    ветки для нескольких сред

    Сомнительный/спорный совет. Существует практика, что после сборки приложения, один и тот-же пакет (сейчас можно делать контейнер) проходит по всем окружениям, от dev до prod.


    1. VolCh
      03.12.2016 16:53

      Сомнительный/спорный совет. Существует практика, что после сборки приложения, один и тот-же пакет (сейчас можно делать контейнер) проходит по всем окружениям, от dev до prod.

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


      1. sentyaev
        03.12.2016 17:36

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


        1. VolCh
          05.12.2016 15:51

          Основная проблема — видение заказчика о новой фиче изменилось до выкладки на прод. Грубо, «не, синенькую кнопочку мы на прод не пустим, переделайте на красненькую».


          1. sentyaev
            05.12.2016 16:12

            Хм, в этом случае заказчик должен понимать, чем грозит внесение изменений перез деплоем.

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

            Да и процесс выкладки на прод тоже обсуждается. Бывает, что нужен аппрув QA lead или непосредственно заказчика, или обязательное прохождение определенного набора тестов (возможно даже ручных) и неважно что мы там меняли.

            Вот для примера, я работал в компании где был крутейший QA lead и он мог спокойно отложить деплой если считал, что качество недостаточное. Причем даже если заказчик говорил — деплойте, последнее слово оставалось за QA lead. С другой стороны, если даже после деплоя нужно было поменять цвет кнопочки, то можно было вместе с ним поправить шаблон на проде, конечно если это можно было так простоо сделать, например изменив css стиль.


  1. sumanai
    02.12.2016 17:17

    Жду статьи «Bitbucket Flow», или может даже две: «Bitbucket Git Flow» и «Bitbucket Mercurial Flow».


    1. nick_volynkin
      02.12.2016 17:26
      +2

      Atlassian называет свою методологию Simple Git Workflow, все посты в их блоге про эту методологию объединены тегом Git together. Идея примерно та же, но есть некоторые отличия. Например, они агитируют за rebase & merge --ff-only веток, что приводит к абсолютно линейной истории и на мой взгляд не очень-то полезно. И их методология не настолько проработана по части CI и рабочих окружений.


      Но идеи-то везде общие, вы можете использовать Bitbucket и практиковать GitLab Flow с какими-то модификациями. Судя по комментариям выше, многие подстраивают систему под себя.


      1. sumanai
        02.12.2016 22:01

        Отлично, первая половина есть. Осталось про Mercurial, заодно решится проблема ребейсов- HG их не поддерживает без плагинов, как и сам Bitbucket, так что ребейс на каждый чих там не сделаешь.
        А по настройке под себя это само собой. Я вот веду сейчас маленький форк крупного проекта, и после поддержки репозитория и предвидящегося выхода новой мажорной версии понял, что текущий Workflow никуда не годится, как и вообще все известные. Пришлось выдумывать свой путь, как опробую на переходе на следующую мажорную версию, напишу статью, если он будет удачным.


        1. nick_volynkin
          02.12.2016 22:27

          Если не трудно, оповестите как-нибудь о статье, мне будет очень интересно почитать.