Цикл разработки через Github

    Разработка



    Я расскажу о цикле разработки через Github, который я использую. Он был проверен в течении года на командах разного размера: 3 — 14 человек.

    Существует 2 основных ветки: master и dev.

    master — стабильная ветка, готовая к выкатыванию на production сервер в любой момент.

    dev — ветка, над которой в данный момент работает команда.

    Итак, в начале разработки master и dev ветки идентичны.



    1. Когда программист начинает работу над новым дефектом / функционалом, он должен переключиться на ветку dev и получить ее последнюю версию.

    git checkout dev
    git pull origin dev
    


    2. К примеру, разработчик хочет начать исправлять дефект страницы аутентификации. Номер ошибки на Github — 1234. Разработчик должен создать новую ветку из dev

    git checkout -b 1234-bug-login
    


    1234-bug-login это только пример. Первым словом должен быть номер дефекта, вторым — bug / feature, а дальше — описание проблемы.

    3. Далее разработчик продолжает работу локально: делает изменения, коммиты и т.д. Commit-cообщения должны содержать номер ошибки и техническое описание

    git add ...list of files...
    git commit -m "#1234 changing backbone model url"
    


    4. Итак, разработка окончена, и теперь необходимо отправить изменения на Github

    git push origin 1234-bug-login
    


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

    git checkout dev
    git pull origin dev
    


    И затем влить все изменения, которые произошли в dev ветке, в свою ветку (1234-bug-login)

    git checkout 1234-bug-login
    git rebase dev
    git push -f origin 1234-bug-login
    


    5. Отлично! Ветка с решенными конфликтами в репозитории. Теперь разработчик делает Сreate Pull Request из 1234-bug-login в dev ветку при помощи Github. Так же необходимо разместить ссылку на задачу (#1234) в описании Pull Request.

    6. Pull Request отправлен, любой разработчик может сделать code review, написать комментарии, уточнения и т.д.
    Комментарии должны быть исправлены и отправлены на Github обычным способом. Pull Request обновится автоматически.

    7. Иногда, исправления занимают некоторое время, и другие разработчики уже слили свои ветки с dev. В этом случае есть 2 варианта:

    — кнопка Merge pull request на Github активна. Это означает, что изменения других разработчиков не конфликтуют с текущими изменениями, и ничего дополнительного делать не требуется.

    — кнопка Merge pull request неактивна. Необходимо вернуться к пункту 4) и заново слить и отправить изменения из dev ветки в 1234-bug-login.

    git checkout dev
    git pull origin dev
    git checkout 1234-bug-login
    git rebase dev
    git push -f origin 1234-bug-login
    


    8. Отлично! Все изменения сделаны, и кто-то написал комментарий «merge it» в Pull Request. Пора нажимать кнопку Merge pull request, чтобы влить изменения 1234-bug-login в dev ветку.

    Тестирование



    9. Как только 1234-bug-login попадает в dev, Jenkins (система непрерывной интеграции) автоматически обновляет dev сервер из dev ветки. QA могут начинать тестировать и как итог подтвердить или переоткрыть задачу.

    10. Если Pull Request вносит много изменений, разработчик может при помощи Jenkins загрузить свою ветку на qa сервер для проверки тестерами.

    Релиз



    11. Перед обновлением production сервера необходимо влить dev ветку в master. Для этого мы создаем Pull Request из dev в master при помощи Github и нажимаем Merge pull request, вот и все. При выполнении предыдущих пунктов, никаких конфликтов быть не будет.

    12. Если регрессионное тестирование успешно закончено, можно обновлять production сервер, при этом берется последний пакет (тот, на котором проходило тестирование), и именно он устанавливается на production сервер.

    13. Иногда QA находят ошибки во время регрессионного тестирования. В этом случае исправления выполняются по стандартной схеме, исключая то, что ветка создается и сливается не из dev, а из master. После релиза необходимо влить исправления из master в dev.

    git checkout master
    git pull origin master
    
    git checkout dev
    git pull origin dev
    
    git merge master
    
    git push origin dev
    
    Метки:
    Поделиться публикацией
    Комментарии 59
    • +6
      А тегами вы не пользуетесь?
      • 0
        есть несколько типов релизов:
        — обычное обновление раз в неделю
        — выкатывание неких глобальных изменений

        В первом случае теги не ставятся, во втором случае ставятся в формате 1.1, 1.2, 1.3 и т.д. В приложении отображается номер тега и номер билда в формате 1.1.112, 1.1.113
        • 0
          Вообще, первый и второй случай, как правило, лишь различаются мажоными и минорными наименованиями тегов. Недельные можно поменять номером недели, и, если были какие-то критические ошибки, буквой, например, 1.5.14a, 1.5.14b, где цифра 1 — первая версия конечного продукта, 5 — некая промежуточная версия, с новыми фичами и прочим, 14 — номер недели, a и b — буквенная нумерация релиза, так как, по идее, редко бывает больше релизов каждую неделю, которые исправляют какие-то баги.
    • +15
      Ох, не нравится мне 13й пункт
      • +1
        Всегда приходится идти на компромисы между красотой и удобством. Я пробовал вводить отдельную ветку для пред-релизных исправлений, и только после регрессии вливать ее в master. С одной стороны это правильно, но это занимало больше времени и кроме этого (и самое важное) — регрессионное тестирование тогда ведется не на том билде, который попадает на production
        • 0
          Зачем сливать master в dev? там может появиться множество конфликтов.
          Слейте в dev, а потом сделайте cherry-pick в ветку, отведенную от мастера и влейте её в мастер.

          Кстати, у нас схема подобная, только ветка, в которой ведется разработка — master, а на каждый релиз от неё отводится новая ветка, которая потом никуда не сливается.
      • +3
        CI должен собирать все ветки, а не ждать, пока изменения смержат в Dev.

        А так нормально. У нас разработка в мастере, а релизы в отдельных ветках, для каждого энва свои ветки. Используем бранчи, а не таги, т.к. бывают всякие случаи, когда коммиты приходится с мастера черрипиком переносить. Например, когда одна из фич должна попасть в релиз, а какая-то другая — еще нет.
        • 0
          Веток может быть очень много. К примеру 6 разработчиков коммитят свои изменения в свои ветки. Собирать каждую на каждый пуш на гитхаб слишком накладно по ресурсам.
          • +3
            Вы преувеличиваете. У нас в компании 100+ репозиториев, в каждом 2 основные и ~ 15 разработческих веток, ~ 350 пушей в день. Собирается каждая ветка. С этим всем, прекрасно справляются всего 2 ноды сборки.
            • 0
              Это совсем не проблема, темболее если аутсорсить CI на сервис типа circleci.com (рекомендую).
              • 0
                У нас несколько десятков разработчиков, у каждого за день проскакивает по три-четыре ветки, и в каждую улетает по несколько пушей, собирается четыре билда для каждого пуша, и сборочная ферма справляется.
            • +11
              За «git push -f» вас переодически будут вспоминать «добрым» словом. Особенно, если ошибётесь с текущей веткой и веткой куда форсируете push.
              • 0
                Если есть опасения, что кто-то что-то сломает, то можно делать merge вместо rebase, и пушить без -f. Но у меня за год случился только 1 случай, когда разработчик ошибся. Исправили очень быстро и безболезненно.
                Преимущество — чистая история без двойных мержей. Кроме этого rebase можно делать больше одного раза, и история будет выглядеть однозначно понятной и удобной для чтения
                • 0
                  Я не против rebase'а, я против «push -f». Переименуйте ветвь (или push-нете её с новым именем), а потом делайте ff-only сколько влезет.
                  • 0
                    Это требует больше времени, шагов, внимания разработчика. И кроме того, как показала практика, в push -f в dev ветку нет ничего страшного. Если даже что-то случилось — всегда есть build сервер с последней версией dev
                  • +6
                    Чем линейная история понятнее дерева? В дереве точно видно что две фичи делались параллельно, а в случае линейной это можно отследить только по датам, которые, кстати будут перепутаны. К тому же, вы пишете про достаточно небольшие команды, Так что у вас скорее всего не будет больше 10 параллельных бранчей.

                    Вот кстати хорошие посты были про rebase habrahabr.ru/post/179123/ и habrahabr.ru/post/179673/.
                    • 0
                      У нас в районе сотни параллельных бранчей, тоже активно используется rebase, ничего не напрягает.

                      Кстати, rebase тут нужен, чтобы чистый merge происходил на сервере в процессе pull request. Если оказывается, что при мердже возникает конфликт, значит pull request не будет вмерджен, пока его не отребэйзят на свежее состояние ветки.
                      • 0
                        Ну не обязательно ребэйзить — можно и замержить (в данном случае dev на feature). Если потом будет фастфорвард так и никаких двойных мержей не будет.
                        • 0
                          В наших условиях не реально — в любом случае придется ждать сборок, а это еще часа два, если очередь пустая, а значит кто-то наверняка успеет что-нибудь вмерджить.
                          • +2
                            Если кто-то успеет вмержить то чем поможет ребейз? Придется ж ребейз переребейзить.
                • +2
                  Обычно еще нужно такое понятие как «Hot Fix». Это когда на боевом сервере нужно срочно что то исправить и добавить это изменение в «dev» чтобы не потерялось. На этот счет вот эта методика http://habrahabr.ru/post/106912/ это лучшее что я видел. Для автоматизации всего этого есть gitflow, еще можно использовать клиент SourceTree, в него эта методика уже встроена.
                  • +12
                    Вы практически изобрели git flow

                    push -f после rebase… конечно, Вы получите более изящную структуру истории проекта, но можете получить и неприятности(сам с подобным сталкивался). Лучше уж сливаться.
                    • –1
                      git flow сложнее, я пробовал его применить, но так мне показалось проще. Кроме этого на практике все работает отлично.
                      • +7
                        можете рассказать, какие возникли сложности с gitflow?
                    • –4
                      В чём смысл разделения master и dev ветки, если можно пользоваться тэгами?
                      • +4
                        Смысл в том, что релизы обычно отстают от разработки. Допустим релиз тестируется неделю перед выходом в продакшн. Всё это время в dev ветке идёт разработка. Затем релиз уходит в продакшн, и на нём обрануживается баг, который необходимо исправить срочно. От master-ветки создаётся некий hotfix-branch, вносится правка, а затем мёрджится в master и в dev. В случае с тегами это будет не так удобно и прозрачно.
                      • +2
                        Товарищи, есть же Gerrit.
                        • 0
                          Поддерживаю, немного пояснения как у нас:

                          • 1 ветка master и теги, а все активности в gerrit
                          • в геррите можно
                            • создавать патч
                            • обновлять патч (заливать новый патч сет)
                            • смотреть изменения в между патч сетами одного пуша
                            • строить цепочку патчей
                            • зачекаутить или зачерипикать любой патч или патчсет и залить новый патч сет
                            • ревьювить код
                          • для новой фичи берется либо мастер, либо существующий патч
                          • когда патч хороший он мержится в master (когда плохой нужно залить новый патч сет с разрешенными конфликтами), для релизов делаются теги
                          • для каждого пуша проходят тесты и может собираться рабочая версия (тк веб и в планах собирать рабочую версию автоматически)
                          • 0
                            ну и зачем тогда git?
                            • 0
                              gerrit работает с git, все патч сеты это отдельные git ветки в gerrit, не говоря о локальном репозитории, так что боюсь что не понял сути вопроса.
                        • +3
                          Вместо 5 вот этих команд:
                          git checkout dev
                          git pull origin dev
                          git checkout 1234-bug-login
                          git rebase dev
                          git push -f origin 1234-bug-login

                          Предлагаю использовать вот такие 3:
                          git fetch origin
                          git rebase origin/dev
                          git push -f origin 1234-bug-login
                          • 0
                            Иногда в origin может быть больше десятка веток для тестирования и прочего, это все выкачивать нет необходимости
                            • +2
                              Ну тогда
                              git fetch origin dev
                              • 0
                                И (на случай, если мы в другой ветке):
                                git rebase origin/dev 1234-bug-login
                                
                                • 0
                                  да, все верно. Видимо, просто дело привычки
                            • +2
                              Если команда маленькая (1-3 человека) и задачи выполняются небольшие (из серии: поправить верстку и т.п.) имеет ли смысл создавать в этом случае для каждой задачи ветку? Поделитесь опытом.
                              • +4
                                Мое мнение, что это стоит делать даже если 1 человек ведет разработку.
                                • +1
                                  да. это особенно удобно когда название ветки соответствует названию таска. плюсом такого подхода вы можете легко переключаться между заданиями или отрываться на исправление срочного бага, а потом возвращаться к работе над задачей. Так же очень легко понять что конкретно реализует эта ветка.

                                  Еще я не вижу смысла в дев ветке (лично я от нее отказался), достаточно иметь мастер со стабильной версией и выполнять слияние только через fast-forfard.
                                  • 0
                                    Мастер в любой момент должен быть протестирован и готов к выкатыванию на production сервер. Без dev ветки регрессионное тестирование практически невозможно.
                                    • 0
                                      дык тестируйте свой мастер. кто мешает? просто при том подходе что я написал вы не сможете слить ветку с ff не применив на ней все обновления мастера, кто мешает в этот момент прогнать тесты сливаемой ветки?
                                      Ну в общем тут у каждого свое, и все зависит от проекта, от его размера, от того как организовано взаимодействие. Я больше писал про индивидуальный цикл разработки.
                                • 0
                                  А зачем писать bug/feature в названии ветки? Из номера тикета это все можно получить, а так делается ненужное дублирование.

                                  Ну и в целом вы описали по-моему вполне себе обычный способ работы с git. Прочитал и задался вопросом — а что, бывает как-то по-другому?
                                  • +1
                                    Мы это делаем, т.к. в истории легче понять что происхдило
                                  • 0
                                    «никаких конфликтов быть не будет» — классное выражение
                                    • +4
                                      Могу я попросить Вас убрать «Путь Github» из заглавия Вашей блогозаписи?

                                      А не то, знаете ли, имя собственное «GitHub Flow» («Рабочий процесс Гитхаба») достаточно давно принадлежит вон тому рабочему процессу, который в существенной степени отличается от описываемого Вами. И может путаница получиться.
                                      • –3
                                        Это рабочий процесс, использующий Github. В самом начале написано «Я расскажу о цикле разработки через Github, который я использую.». Это действительно проблема?
                                        • 0
                                          Варианты «Мой путь GitHub» или «Путь через GitHub» уже не путали бы. Буду благодарен, если поменяете.
                                    • 0
                                      git push -f origin 1234-bug-login — подходит только если над фичей/фиксом работает один человек. Если два и более, что в принципе иногда случается то проблемы будут.
                                      • 0
                                        Просто оставлю это здесь…
                                        Удачная модель ветвления для Git
                                        • 0
                                          Известная штука. Сложновато только.
                                          • +1
                                            git-flow от nvie упоминалось на этой странице уже не единожды.
                                          • 0
                                            Если я правильно понял, то в dev у нас изменения, которые разработчики считают законченными и достойными вливания в мастер. Что, если часть из них не прошла тестирование/приемку, причем эта часть где-то в середине истории и последующие коммиты уже от неё зависят?
                                            • 0
                                              Есть несколько вариантов
                                              — если это небольшие изменения, то они сразу влились после код ревью в дев, и если перед релизом в них обнаружена ошибка, то обычно не составляет труда ее исправить

                                              — если это более масштабные изменения, то тестер проверяет отдельно ветку перед сливанием с девом

                                              В целом по такой схеме мы ни разу не пропустили обновление (обновляемся 1 раз в неделю)
                                              • 0
                                                Речь прежде всего именно о масштабных изменениях и о внешнем тестировании (приемке). В общем ситуация, когда заказчик заказал масштабное изменение (может не одно) параллельно с мелкими фиксами/фичами, а потом видя на тестовом сервере говорит, что в ТЗ он имел в виду нечто другое и надо все переделать, но вот эти фиксы давно пора выкатить на продакшен.
                                            • 0
                                              В моих проектах часто меняется база данных — добавляются поля в таблицах, меняются типы полей итп.
                                              Есть ли средства для создания похожей версионности с миграциями в БД? Чтобы при переключении на нужную ветвь структура базы данных тоже приходила к той версии?
                                              • 0
                                                Скрипты на checkout. Откатываем базу до ближней общей точки в текущей ветке и накатываем до последней в новой ветке. Но удовлетворительно работает только если миграции не разрушающие или перед разрушением делается бэкап.
                                              • 0
                                                Рекомендую пометить пост как «tutorial».
                                                • 0
                                                  Чтобы не писать в комментарии к коммиту номер тикета можно воспользоваться хуком: gist.github.com/peterdemin/6483893

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