Особенностью современной веб разработки является полное отсутствие планирования при создании, поддержке и выкатке проектов. Это приводит к ситуации, что достаточно часто параллельно выполняется несколько разных задач и сроки их выкатки в production никак не соотносятся. А значит традиционный подход с созданием релизов не годится.
На помощь нам приходит механизм создания веток в системах контроля версий, VCS (в нашем случае это Subversion). Ветки это разные варианты одного документа или проекта, с общей историей изменений до точки ветвления и с разными — после неё.
Ветка создается очень просто:
Теперь, чтобы изменения разработчика сохранялись не в основном стволе разработки (trunk), а в выбранной ветке, он должен переключится на эту ветку.
Теперь можно вести разработку в ветке, не беспокоясь, что не утвержденные или не проверенные решения попадут в production. При этом разработчик работает со своим хостом ЛОГИН_РАЗРАБОТЧИКА.ПРОЕКТ.КЛИЕНТ.devserver.ru
Чтобы показать готовое или промежуточное решение создается тестовый хост для этой ветки. Нужно автоматизировать этот процесс, чтобы разработчики не тратили на это время. Менеджеры и тестировщики всегда проверяют решение только на тестовом хосте НАЗВАНИЕ_ВЕТКИ.ПРОЕКТ.КЛИЕНТ.devserver.ru. Проверять что либо на хосте разработчика нельзя. Потому что:
Поэтому единственно правильной практикой будет:
Последнее надо делать, даже если в задаче эта ссылка несколько раз встречалась. Потому что из за спешки или невнимательности 4 действия из описанных 5 могут быть пропущены.
После того как менедежер проверил решение и не нашел ошибок нужно вливать ветку в trunk.
Допустим у нас есть ветка A (trunk), в которой ведется основная разработка. В ревизии 100 мы отпочковываем от нее ветку B (branches/НАЗВАНИЕ_ВЕТКИ) (A@100, B@101) Затем обе ветки активно развиваются продолжительное время (A@167, B@189) и нам надо их слить. Если сливать «в лоб» (sw A, merge A B) то будет очень много конфликтов, которые очень сложно разрешить Правильный подход следующий:
Обращаю внимание: если ветки уже сливались в прошлом, то нужно брать в качестве начальной ревизии не ревизию отпочкования, а последнюю ревизию, в которой ветки были «одинаковыми». При чем это не обязательно может быть вливание изменений из A в B, могут быть и вливание B в A.
В некоторых случаях конфликты все равно случаются, как правило если один и тот же участок кода изменялся в разных ветках. Есть инструкция по их разрешению. Нужно не забывать, что не обязательно ваше решение будет правильным в каждом конфликте, поэтому желательно чтобы merge делал человек, знакомый с изменениями в обоих сливаемых ветках и способный адекватно решить конфликт.
После слияния нужно создать тестовый хост для trunk (trunk.ПРОЕКТ.КЛИЕНТ.devserver.ru) или обновить существующую папку. После этого кидаем в задачу ссылку на проблемное место на тестовом хосте в задаче. Зачем это делать, ведь мы только что проверили изменения на хосте ветки? Изменения, которые велись в trunk или другие изменения, которые были влиты в trunk могут повлиять на те правки, которые нам нужны. Чаще всего проблемы могут быть вызваны CSS, т.к. там просто общими правилами повлиять на очень много разделов, но бывают и другие ситуации. Поэтому еще одна проверка на trunk перед выкаткой очень нужна.
Подчас менеджеру бывает совершенно наплевать на проект и более всего его беспокоит собственное душевное равновесие. Поэтому он с легкой душой пропускает шаги, которые кажутся ему не важными и пишет в задаче «Сделайте то-то и сразу же выкатывайте».
И поэтому он уже в ближайшее время получит втык от клиента «Сейчас большинство абонентов на вебе не может … используя браузер IE. Мы в прошлый раз говорили, что больше половины пользователей им пользуются так что просьба тестировать все доработки в перую очередь на IE. Поправьте, пожалуйста, как можно быстрее данную ошибку!»
Менеждер ставит задачу «СРОЧНО!!! ОШИБКА!!!» и забывает о проверках до следующего раза.
Нарушение алгоритма «сделали → проверили → (исправили → проверили)*n → выкатили» приводит к появлению срочных задач-правок выбивающих разработчиков из ритма и отвлекающие от запланированных задач, портит нашу общую репутацию перед клиентами и пользователями и нифига не ускоряеет процесс.
На помощь нам приходит механизм создания веток в системах контроля версий, VCS (в нашем случае это Subversion). Ветки это разные варианты одного документа или проекта, с общей историей изменений до точки ветвления и с разными — после неё.
Создание
Ветка создается очень просто:
svn copy svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/trunk svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/branches/НАЗВАНИЕ_ВЕТКИ -m 'КАКОЙ ТО КОММЕНТАРИЙ О ВЕТКЕ'
Теперь, чтобы изменения разработчика сохранялись не в основном стволе разработки (trunk), а в выбранной ветке, он должен переключится на эту ветку.
cd ~/web/КЛИЕНТ/ПРОЕКТ # переходим в основную папку проекта
svn sw svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/branches/НАЗВАНИЕ_ВЕТКИ
svn update # нужно в тех случаях, когда в проекте используются svn:externals с относительными ссылками
Теперь можно вести разработку в ветке, не беспокоясь, что не утвержденные или не проверенные решения попадут в production. При этом разработчик работает со своим хостом ЛОГИН_РАЗРАБОТЧИКА.ПРОЕКТ.КЛИЕНТ.devserver.ru
Чтобы показать готовое или промежуточное решение создается тестовый хост для этой ветки. Нужно автоматизировать этот процесс, чтобы разработчики не тратили на это время. Менеджеры и тестировщики всегда проверяют решение только на тестовом хосте НАЗВАНИЕ_ВЕТКИ.ПРОЕКТ.КЛИЕНТ.devserver.ru. Проверять что либо на хосте разработчика нельзя. Потому что:
- разработчики норовят забыть что-то закоммитить. Из за этого другой разработчик, работающий с той же задачей или выкатывающий решение может долго не понимать, где собственно все.
- иногда разработчики оставляют в коде привязки к своему хосту. Изза этого решение работает только у них, а при выкатке все ломается.
- многие, особенно разработчики со стажем, новорят внести какие то исправления «вслепую» и не проверяя их коммитить. Это приводит к падению сервиса на production и серии коммитов-хотфиксов с комментарием «Ой, бля»
Поэтому единственно правильной практикой будет:
- выполнить задачу
- закоммитить изменения
- выкатить их на тестовый сервер
- самому глазами хотя бы один раз посмотреть, что все выкатилось там корректно
- опубликовать ссылку на проблемное место на тестовом хосте в задаче (в мегаплане или другом тасктрекере)
Последнее надо делать, даже если в задаче эта ссылка несколько раз встречалась. Потому что из за спешки или невнимательности 4 действия из описанных 5 могут быть пропущены.
Слияние
После того как менедежер проверил решение и не нашел ошибок нужно вливать ветку в trunk.
Допустим у нас есть ветка A (trunk), в которой ведется основная разработка. В ревизии 100 мы отпочковываем от нее ветку B (branches/НАЗВАНИЕ_ВЕТКИ) (A@100, B@101) Затем обе ветки активно развиваются продолжительное время (A@167, B@189) и нам надо их слить. Если сливать «в лоб» (sw A, merge A B) то будет очень много конфликтов, которые очень сложно разрешить Правильный подход следующий:
svn switch svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/branches/НАЗВАНИЕ_ВЕТКИ # переключаемся в B
svn merge -r 101:167 svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/trunk . # вливаем туда все изменения произошедшие в A с момента отпочкования (или **последнего слияния**)
svn ci -m 'merge with -r 101:167 trunk' # разрешаем возникшие конфликты (их должно быть меньше, чем в первом случае) и коммитим. В коммите указываем какие именно изменения мы забрали
svn switch svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/trunk # переключаемся в A
svn merge svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/trunk svn://svnserver.ru/КЛИЕНТ/ПРОЕКТ/branches/НАЗВАНИЕ_ВЕТКИ . # вливаем туда изменения в B
svn ci -m 'merge with НАЗВАНИЕ_ВЕТКИ@190' # конфликтов быть уже практически не должно, т.к. мы учли изменения A в предыдущем коммите
Обращаю внимание: если ветки уже сливались в прошлом, то нужно брать в качестве начальной ревизии не ревизию отпочкования, а последнюю ревизию, в которой ветки были «одинаковыми». При чем это не обязательно может быть вливание изменений из A в B, могут быть и вливание B в A.
В некоторых случаях конфликты все равно случаются, как правило если один и тот же участок кода изменялся в разных ветках. Есть инструкция по их разрешению. Нужно не забывать, что не обязательно ваше решение будет правильным в каждом конфликте, поэтому желательно чтобы merge делал человек, знакомый с изменениями в обоих сливаемых ветках и способный адекватно решить конфликт.
После слияния нужно создать тестовый хост для trunk (trunk.ПРОЕКТ.КЛИЕНТ.devserver.ru) или обновить существующую папку. После этого кидаем в задачу ссылку на проблемное место на тестовом хосте в задаче. Зачем это делать, ведь мы только что проверили изменения на хосте ветки? Изменения, которые велись в trunk или другие изменения, которые были влиты в trunk могут повлиять на те правки, которые нам нужны. Чаще всего проблемы могут быть вызваны CSS, т.к. там просто общими правилами повлиять на очень много разделов, но бывают и другие ситуации. Поэтому еще одна проверка на trunk перед выкаткой очень нужна.
Нерадивый менеджер
Подчас менеджеру бывает совершенно наплевать на проект и более всего его беспокоит собственное душевное равновесие. Поэтому он с легкой душой пропускает шаги, которые кажутся ему не важными и пишет в задаче «Сделайте то-то и сразу же выкатывайте».
И поэтому он уже в ближайшее время получит втык от клиента «Сейчас большинство абонентов на вебе не может … используя браузер IE. Мы в прошлый раз говорили, что больше половины пользователей им пользуются так что просьба тестировать все доработки в перую очередь на IE. Поправьте, пожалуйста, как можно быстрее данную ошибку!»
Менеждер ставит задачу «СРОЧНО!!! ОШИБКА!!!» и забывает о проверках до следующего раза.
Нарушение алгоритма «сделали → проверили → (исправили → проверили)*n → выкатили» приводит к появлению срочных задач-правок выбивающих разработчиков из ритма и отвлекающие от запланированных задач, портит нашу общую репутацию перед клиентами и пользователями и нифига не ускоряеет процесс.