Comments 21
В базе у нас тоже 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.
Особенно интересует:
проставляет версии, тэги, сливает, заливает, защищает,и
custom hooks которые смотрят, чтобы ветки аккуратно назывались, например, feature/prjid-123-abc-def-xyz и в каждом коммите была ссылка на тикет типа PRJID-123.
Выложить скрипт просто так не могу: собственность компании. Я поговорю с шефом по поводу открытия кода на гитхабе, но там нет ничего особенного и сверхъестественного, так собрание мини-хаков и гит-трюков.
У нас jira + java + maven + gitlab. Приведу пока описание без кода, что было сделано.
- Скрипт в целом параметризован с помощью
getopts
. Он вызывает процедуры в порядке, необходимом для получения состояния в соответствии с правилами git-flow. - Версии. Тут мы пользуемся функциональностью maven
versions:set/commit
иhelp:evaluate
для project.version. Потом можно просто использоватьgit tag -m "$ticket" -m 'Release 1.2' $version
. Аналогично для веток. - Слияние работает только если нет конфликтов. Чтобы избежать очевидных конфликтов как то начало релиза
1.2.0-SNAPSHOT
и переход к2.0.0-SNAPSHOT
в разработке. Очевидно, что при слиянии веток у нас будут конфликты вpom.xml
. Можно автоматически слить ветки используя стратегию ours. Тогда конфликты проигнорируются при последующих слияниях. - Jira. У нее есть Rest API которое можно дернуть, чтобы залогиниться и получить заголовок по номеру задачи. Этой функциональностью мы пользуемся, чтобы при автоматических операциях проставить например, PRJ-1234 Hotfix 1.2.3
- Gitlab. У него также есть Rest API. Им мы пользуемся для того, чтобы защитить ветку в начале разработки. Например release/1.2. Скрипт вызывает функцию типа
gitlab_api release/1.2 protect
. - custom hooks. Тут написан простой рецепт на ruby — я вообще начинал с примеров. Там есть конфигурация, какой идентификатор проекта и что проверять. Скрипт просто собирает регулярное выражение с возможными названиями веток и проверяет подходит ли присланная ветка под шаблон. Наряду с этим скрипт смотрит, чтобы в каждом присланном коммите был тикет типа
PRJ-\d+
, пустая вторая строка и первая строчка не слишком длинная. Единственный трюк был — получить список именно новых коммитов. - idempotent. Где возможно старался сделать скрипт идемпотентным, чтобы можно было запускать подряд несколько раз, если слияние не удалось из-за конфликтов и пришлось их вручную разруливать (rerere тут не получилось заставить работать). Например, sed для того, чтобы обновить
<tag>release-1.2.3</tag>
на<tag>release-1.2.4</tag>
.
Если компания даст добро, то переработаю скрипты и выложу на гитхаб. У нас заняла чуть больше года разработка этого скрипта. Писалось все в фоне и по мере необходимости.
Загвоздка тут, все это написано под конкретно наши нужды. Выделить общую часть будет сложно. Есть уже git-flow для bash, который уже многое делает, но нам нужны еще дополнительные фунуции и шаги
Бывают случаи, когда критический баг в релизе обнаруживается уже на проде. Например, новая версия не держит высоких нагрузок. Или на прод по недосмотру попало то, что не должно было. Или обнаружилась уязвимость. В этом случае релиз с прода откатывается на предыдущую версию. А тем временем от мастера уже стартовала куча новых веток, которые тянут с собой изменения, попавшие в новый релиз. Это может быть не прод, а пре-прод (не просто же так пре-прод нужен, да?) и из-за одной сломанной фичи приходится задерживать весь релиз. Иногда задержка может длиться несколько дней, ибо выпилить фичу уже сложно, а починить не понятно как. Поэтому есть хорошее правило: заливать в мастер только тот код, который проверен на проде и признан стабильным. И только после этого от него можно начинать ветки.
Откатиться — ничего не мешает. А вот reverse-merge всех веток — проблема.
Вариант, когда критическая проблема обнаружилась не через 0-1-2 дня — это аварийная ситуация. Тут простого решения нет. Я бы бросил все силы на hotfix.
Затем, чтобы спокойно решить проблему, не останавливая деплой других фич, а не чинить не готовую к релизу фичу впопыхах. У нас последовательность такая:
- Решили выложить релиз.
- Собрали готовые к релизу фичи в отдельной ветке.
- Протестировали, что всё работает.
- Если фичи конфликтуют — чиним прямо в релизной ветке или собираем новый релиз без некоторых из фич.
- Тестируем релиз на реальных данных.
- Выкладываем на прод и проверяем, что всё ок.
- Вливаем в мастер.
Если на 6 шаге обнаруживаются проблемы — откатываемся и спокойно решаем проблемы. После чего собирается новый релиз или вообще релиз переносится на другой день.
Сомнительный/спорный совет. Существует практика, что после сборки приложения, один и тот-же пакет (сейчас можно делать контейнер) проходит по всем окружениям, от dev до prod.
Существует, да, но часто оказывается сильно тормозит процесс, когда редкий дев-билд доходит до прода.
Atlassian называет свою методологию Simple Git Workflow, все посты в их блоге про эту методологию объединены тегом Git together. Идея примерно та же, но есть некоторые отличия. Например, они агитируют за rebase
& merge --ff-only
веток, что приводит к абсолютно линейной истории и на мой взгляд не очень-то полезно. И их методология не настолько проработана по части CI и рабочих окружений.
Но идеи-то везде общие, вы можете использовать Bitbucket и практиковать GitLab Flow с какими-то модификациями. Судя по комментариям выше, многие подстраивают систему под себя.
Прочитал статью, перечитал комменты, поглядел на опусы, типа If you cherry pick, your branch model is wrong или Stop cherry-picking, start merging и вижу, что как только появляется ветка support (а если не одна?) то без cherry-pick уже не обойтись: когда изменения /обычно фиксы/ появились уже давно в dev или даже master, и вдруг потребовались в support-release-1.0. При этом сам cherry-pick не предоставляет возможности проследить историю изменения. Странно, что в том же Subversion, худо-бедно это сделано через обычный merge и svn:mergeinfo
(пожалуй, единственное, что мне нравится в Subversion).
Т.е. для приложений, для сервисов подобные схемы вполне себе, но для библиотек нужно, даже если исходить из семантического версионирования: выпустили релиз 1.0.0, для него логично иметь tag v1.0.0 и бранч поддержки release-1.0, куда будут попадать только багофиксы некоторое время, при этом остальная команда будет работать над 1.1 и, внезапно, пофиксит проблему, которая актуальна и для 1.0...
GitLab Flow