Надоела реклама? Купите платный аккаунт и больше вы не увидите рекламы!

Про ИТ-менеджмент

Постараемся сделать мир чуточку счастливее

Previous Entry Поделиться Next Entry
Version Control for Multiple Agile Teams - часть 1
anton_nix
Разобрали сchivorotkiv статью Version Control for Multiple Agile Teams. В рунете не нашел, поэтому выкладываю свой вольный перевод - ибо, имхо, фундаментальный труд =)



Как нескольким agile командам работать над одной базой исходных кодов, при этом не мешая друг другу? Как быть уверенными, что у нас всегда будет готовая к релизу версия в конце каждой итерации? В статье описывается пример того, как управлять системой версионирования исходных кодов, когда у нас есть несколько agile команд - та самая схема, к которой мы пришли в компании, описанной в книге "SCRUM и XP из окопов".

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


Содержание
:

  1. Введение
  2. Цели
  3. Обо всем одной страницей
  4. Паттерн контроля версий
    • Владелец и политика ветвей
    • Концепция "Сделано"
    • Ветка "сделанного"
    • Когда мы создаем дополнительные ветки?
    • Рабочие ветки
    • Публикация из рабочей ветки в ствол
    • Что если наша команда реализует две истории одновременно?
    • Сделано - означает регрессионное тестирование!
    • Разрешаем конфликты при мерджах
    • Несколько команд - что если другие команды тоже публикуют код в ствол?
    • Ветки релизов
    • Большая картинка
  5. Вариации
  6. ЧаВо
  7. Где в этой схеме можно применить Непрерывную Интеграцию (Continuous Integration)?
  8. Какой самый лучший инструмент для такой системы версионирования?
  9. Как насчет комитов, которые не относятся к какой-либо истории пользователя?
  10. Мерджить грустно, поэтому я хочу делать этот как можно реже!
  11. У меня есть еще вопросы!

Введение

Эта статья описывает пример, как управлять версиями исходных кодов, когда у нас несколько agile команд. Вам нужно знать базовые принципы Scrum & XP. Это не я изобрел эту схему - она основана на модели "главной линии" или паттерне "стабильного ствола" (см. ссылки).

Я написал эту статью, потому что постоянно вижу команды, которые действительно нуждаются в ней. И большинству команд эта схема нравится сразу, как только они начинают ее понимать. К этой схеме мы пришли в компании, описанной в "Scrum & XP из окопов". Она, безусловно, помогла нам вести разработку и выпускать софт по agile. Может быть, описав эту модель в легкой для понимания форме, мне больше не придется объяснять ее у доски :o)

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

Цели

В agile среде со множеством команд, система версионирования исходных кодов должна способствовать достижению следующих целей:
  • Фиксим быстро
    • Конфликты исходников и проблемы интеграции должны разрешаться как можно раньше.
    • Лучше часто фиксить маленькие проблемы, чем редко фиксить большие.
  • Всегда готовы к релизу
    • Даже после самого плохого спринта должно быть что-то, что можно выпустить в свет.
  • Простота
    • Все члены команды будут использовать эту схему каждый день, поэтому правила должны быть как можно яснее и проще.

Обо всём одной страницей

Если эта картинка шокирует вас, не переживайте, а просто читайте дальше.
Если эта картинка для вас очевидна, дальше можно не читать.




Еще её можно загрузить отсюда.

Паттерн контроля версий

Владелец и политика ветвей

Вот вам простое правило: каждая ветка (даже ствол) имеет владельца и политику.

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

Концепция "Сделано"

Когда история пользователя "сделана"? Другими словами, когда ваша команда перемещает некоторую историю пользователя в колонку "сделанное" на доске задач, что это на самом деле означает?

Я буду предполагать следующее: что-то сделано = это что-то можно выпускать в продакшн.

Т.о. когда член команды говорит, что история сделана и перемещает ее карточку в колонку сделанного, заказчик может тут же вбежать в комнату и сказать "Отлично! Давайте выпускать!", и никто в комнате не может возразить: "нет! подождите!".

Вообще-то, вы можете определить "сделанное" как хотите. Но помните - если вы определите это как нечто меньшее, чем "релизное", то вам придется ответить на вопросы: что не включено в "сделанное"? И кто будет делать эту оставшуюся работу? Когда? И что происходит, если что-то работает неправльно уже будучи "сделанным"?

Когда мы создаем дополнительные ветки?

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

Рабочие ветки

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

Подождите-ка! Готовый к выпуску означает протестированный на интеграцию. И это значит, что нужно запустить интеграционные тесты. Т.е. нужно запускать интеграционные тесты перед тем, как комитить в ствол.

Итак, куда я должен закомитить код, который мне кажется законченным, но его требуется проверить перед помещением в ствол? Конечно, я могу протестировать его на своей локальной машине, и затем закомитить его прямо в ствол. Но это немного страшно, т.к., я уверен, каждый из вас попадал в ситуацию "а у меня на машине все работает!".

Другая проблема: "Пойду-ка я домой. Куда бы закомитить код? Он еще не протестирован, так что в ствол нельзя. Но мне надо его куда-то положить, чтобы другие члены команды могли продолжить над ним работать" (agile команда = коллективное владение кодом, правильно?).

Т.о. нам что-то нужно закомитить, но некуда, т.к. нарушим политики этих существующих веток. Так что вполне оправдано создать новую ветку.

Давайте назовем ее рабочей веткой, открытой всем членам команды. Некоторые зовут ее development веткой.

Политика рабочей (development) ветки команды А:
  • код компилится и собирается, все тесты проходят.


Отлично, теперь у нас есть две ветки! Одна стабильная (ствол) и одна чуть менее стабильная (ветка команды). Ветка команды - красная, чтобы подчеркнуть, что она менее стабильная, т.е. её содержимое проходит юнит-тесты, но она может не поддаваться интеграционному тестированию и может быть недостаточно стабильной для релиза. Хорошо, теперь у команды есть ветка, куда можно класть текущую работу!

Хммм... А как насчет синхронизации ветвей? Читаем дальше...

Публикация из рабочей ветки в ствол

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

Для удобства назовем это "публикацией", раз уж мы сделали некоторую работу, которая уже готова к "опубликованию" и выпуску в релиз.

Например, мы реализовали две истории: Register и Deposit. Они Сделаны, т.е. прошли юнит-тесты, интеграционные тесты и готовы к выпуску. Мы только что начали работать над Задолженностью, но она еще пока не Сделана. Доска задач будет выглядеть примерно так:


Каждая желтая записка на доске представляет собой задачу, т.е. один кусочек работы, необходимой, чтобы завершить историю. Например, отредактировать класс Х, обновить скрипт сборки, и т.д. Каждая задача обычно длительностью около одного дня работы, каждая история обычно означает 3-8 дней работы. История ветви могла бы выглядеть как-то так:


Итак, первая команда реализовала Register. Закомитим это в рабочую ветку, запустим интеграционные тесты, поправим баги, опять закомитим, опять запустим тесты - работает! Регистрация Сделана! Опубликуем ее в ствол.

Далее делаем Депозит. Нужен был только один комит. Интеграционные тесты прошли, так что релизим это в ствол.  

Теперь команда посреди реализации Задолженности. Уже сделали два комита, но это все еще не завершено.

Заметье, что "зарелизить в ствол" не означает, что мы копируем код только одной какой-то истории в ствол. Это означает, что мы копируем все из рабочей ветки в ствол, т.к. делаем полную синхронизацию.

Здесь возникает два интересных вопроса:
  1. Что если наша команда реализует две истории одновременно?
  2. Что если другие подкоманды также публикуют что-то в ствол?
Давайте попорядку.

Что если наша команда реализует две истории одновременно?

Если команда реализует одну историю в один момент, публикация в ствол тривиальна. Как только история реализована и протестирована в рабочей ветке мы копируем все из рабочей в ствол. Готово.  

Стоп! Что если мы делаем несколько историй одновременно? Что если Register закончена, а Deposit в процессе?


Если мы синхронизируемся со стволом в этот момент, то мы включим частично завершенную историю Deposit, которую нельзя релизить! Нарушение политики ствола!

Конечно, мы могли бы подождать пока Deposit будет сделана.

(ждем-с...)

ОК Deposit теперь завершена! Отлично! Стоп... теперь кто-то начал работу над Withdraw! Блин! Та же проблема!


Если один из тестов Deposit упадет, об этом будет тяжело узнать - это из-за бага в Deposit, или потому что Withdraw завершен только частично и закомичен в ту же ветку.

Ожидание не помогает. Мы как катящийся снежный ком, который будет катиться не будучи зарелизеным, пока мы не завершим все истории (если такое вообще случится).  

И это всеобщая проблема. Что же делать?

Вот несколько стратегий:
  • Не вести столько параллельных разработок. Попробуйте сосредоточить команду на одной истории в один момент.
  • Если кто-то собирается начать работать над Deposit прежде, чем был завершен Register, подождать комитить код Deposit, пока заканчивается Register. Или даже может быть закомитить Deposit в другую временную ветку, если вам нравится играться с ветками.
  • Если кто-нить собирается начать работать над Deposit прежде, чем завршена Register, начните с безопасных и невидимых изменений, изменений которые оставят ветку готовой к релизу. Например, если Deposit требует некоторого нового кода и некоторой модификации существующего кода, реализуйте новый код сейчас (новые методы, новые классы, новые тесты и т.д.), но не модификации. Если Deposit нужны новые элементы GUI, сделайте их пока невидимыми. Как только Register будет завершена и помещена в ствол, мы сможем начать реализовывать остаток Deposit.

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

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

Вот почему Scrum-команды предполагают небольшой размер (< 9 человек) - они могут тесно сотрудничать и концентрировать общие усилия. Если каждый делает его собственную историю параллельно, то хорошего сотрудничества, видимо, не получится. Конечно, у вас может быть народ смотрящий вперед, готовящий следующую историю и ведущий какую-то часть разработки. Но в любой заданный момент времени огромные командные усилия должны быть сфокусированы на верхнеприоритетной истории.

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

Сделано - означает регрессионное тестирование!

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

Правило: кто бы ни тронул ствол, он обязан удостовериться, что весь ствол остается готовым к выпуску - включая всю уже готовую функциональность!

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

Стоп! А это случайно не бред? Запускать все регрессионные тесты каждый раз, когда завершается какая-нибудь история? Хм... Для начала, я не говорил ВСЕ регрессионные тесты. Я сказал все затронутые регрессионыне тесты. Вспомните что у нас всегда чистый готовый к выпуску ствол, и сейчас мы всего лишь добавили одну историю! Это невероятно маленькое дополнительное изменение. Если у нас есть автоматизированные регрессионные тесты, мы можем запустить их всех. Но если есть ручные регрессионные тесты, мы будем вынуждены тестировать выборочно. Все это - баланс между стоимостью и рисками. Для каждого ручного регрессионного теста мы должны посчитать стоимость этого теста (т.е. как много работы нужно выполнить, чтобы прогнать этот тест) и сопоставить с тем, сколько важных дефектов может быть найдено в процессе. И, конечно, взвесить стоимость автоматизации этого теста :о)

Разрешаем конфликты при мерджах

Что если я сижу довольный и пишу код, который вызывает класс Widget. О чем я не знаю, так это о том, что мой сотоварищ Джим удалил класс Widget час назад в процессе рефакторинга. Теперь у меня есть конфликтующий код. Я хочу обнаружить это как можно быстрее, перед тем как потрачу зря кучу драгоценного времени в процессе написания кода обращающегося к классу Widget.

Правило: непрерывно синхронизируйте ваш код с рабочей веткой (= как можно чаще).

Синхронизация в этом случае означает оба направления. Сначала смерджить код из рабочей ветки, а потом закомитить ваш код. Первую часть можно назвать "поймать" (= Я хочу обнаружить, чего там накомитил остальной народ). Вторую часть можно назвать "публикация" (= Я хочу сделать мои изменения доступными остальной команде).

Делать это раз в час или около того становится хорошей привычкой, когда вы перемещаетесь от одной задачи к другой. Но это не только означает "Я хочу как можно быстрее узнать, что кто-то пишет код, конфликтующий с моим", еще это означает "Я хочу, чтобы другие ребята как можно быстрее узнали, что я пишу код, который конфликтует с их кодом". Просто не забывайте о политике рабочей ветви (рабочие юнит-тесты).

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

Несколько команд - что если другие команды тоже публикуют код в ствол?

Представим, что у нас есть две команды А и Б. Они кроссфункциональны и работают над системой продажи авиабилетов. Команда А сфокусирована ни процессе продажи, команда Б сфокусирована на серверной части.

И вот они собираются начать спринт. На каждую команду у нас по две истории (в следующих спринтах будет поболее историй).


Каждая команда работает в своей собственной ветке, т.к. им обеим нужно где-то тестировать их код перед публикацией этого кода в ствол.


И тут появляется интересная проблема. Например, я нахожусь в команде А и у нас есть своя ветка. Так вот - в стволе могут оказаться изменения, которых еще нет в моей рабочей ветке! Почему? Потому что есть другая команда, и они публикуют код в ствол как только заканчивают их историю!

Т.о. в любой данный момент времени в стволе может оказаться код, о котором я еще ничего не знаю. И этот код может (черт побери!) конфликтовать с моим кодом! Может быть кто-то в команде Б переименовал класс Widget, который я вызываю из своего кода и... хм... стоп! А не говорили ли мы только что об этом?

Точно, так и есть - та же самая проблема. И то же самое решение. Но немного в другом масштабе.

Правило: мерджи код из ствола в рабочую ветку каждый день.


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

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

Правило: конфликты разрешаются в менее стабильной ветке.

Конечно, сливяние от ствола - пустая трата времени, если народ не регулярно публикует в ствол. Любое расхождение в коде между командами А и Б невидимо, пока кто-то не опубликует код в ствол. Отсюда имее следующее правило:

Правило: Слияние из твоей рабочей ветки в ствол должно быть регулярным, например, после того как закончена история. Не ждите конца спринта!

Заметим интересные эффект:

Эффект: тот кто комитит первый - побеждает!

Если две команды пишут конфликтующий код, команда, которая комитит последней, должна порешать эти конфликты. Это вот такой вот милый эффект, который заставляет команды комитить код как можно раньше :о)

Вот пример спринта.



Спринт идет 6 дней и участвуют в нем две команды. Команда А планирует реализовать Book и Cancel. Команда Б планирует реализовать Invoice и Blacklist. Давайте посмотри чего получается.

ДеньКоманда АКоманда Б
Ствол
1Мерджим из ствола. Ничего нового. Работаем над Book. Комитим в нашу рабочую ветку.Мерджим из ствола. Ничего нового. Работаем над Invoice, комитим в нашу рабочую ветку.Сегодня ничего не произошло.
2Мерджим из ствола. Ничего нового. Заканчиваем Book. Тестируем её на интеграцию. Сделано! Копируем в ствол. Начинаем работать над Cancel.То же, что и вчера.
Book сделана!
3Мерджим из ствола. Ничего нового. Всё ещё работаем над Cancel.Мерджим из ствола. Ага! Изменения! Добавлена Book! Мерджим с нашим кодом в ветке команды Б, разрешаем любые конфликты. Затем продолжаем работать над Invoice.Сегодня ничего не произошло.
4То же, что и вчера.Мерджим из ствола. Ничего нового. Заканчиваем Invoice. Тестируем её на интеграцию (включая Book!), копируем в ствол. Начинаем работать над Blacklist.Invoice сделана!
5Мерджим из ствола. Ага! Изменения! Добавлен Invoice! Мерджим с нашим кодом в ветке команды А, разрешаем любые конфликты. Затем продолжаем работать над Cancel.Мерджим из ствола. Ничего нового. Прдолжаем работать над Blacklist.Сегодня ничего не произошло.
6Мерджим из ствола. Ничего нового. Заканчиваем Cancel, копируем в ствол.То же, что и вчера
Cancel теперь сделана!

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

Релизные ветки


Предположим, мы закончили первый спринт и выпустили версию 1.0.0 системы. Теперь мы в середине второго спринта, и найдена серьёзная ошибка в выпушенной версии! О нет! Что же делать?

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

Тем не менее могут быть причины не рализить новые истории прямо сейчас. Например:
  • То что найден серьезный дефект вообще-то означает, что ствол был поломан во время релиза. Это, в свою очередь, означает, что текущий спринт и все его истории построен на поломанном фундаменте. И мы можем хотеть поправить сам фундамент, при этом не вынуждая себя также править истории текущего спринта.
  • Может быть заинтересованные лица не хотят выпускать новые фичи в середине спринта.
  • Может быть это требует времени, чтобы сделать новый релиз из ствола, с новыми фичами и всем остальным, поэтому мы хотим просто поправить ошибку и выпустить поправленный релиз.
Ну и как нам это сделать?
  1. Создать ветку версии 1.0, представляющую из себя ствол, каков он был во время релиза 1.0.
  2. Наложить заплатку на ошибку в ветке 1.0.
  3. Мерджить от ветки релиза к стволу стразу после релиза (т.е. заплатка будет включена в последующие релизы).
[Image]

Заметив, что нам необязательно создавать ветку релиза 1.0, когда мы делаем релиз 1.0.0. Нам не нужно её создавать, пока не появится что-то, что должно быть сделано именно в этой ветке.

Большая картинка

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

В модели Главной Линии, ветка называется Линией Кода (т.е. ветка понимается как реализация Линии Кода). Иногда это еще называют потоками.

Родитель Линии Кода (т.е. Лини Кода, от которой берет начало данная) называется её Базовой Линией. Главная Линия - это Линия Кода, у которой нет Базовой Линии.

Так по примеру, приведенному выше, можно заключить что:
  • Ствол это наша Главная Линия. У него ведь нет родителя, так?
  • Ствол является базовой линией всех остальных линий кода (релиз 1.0, работа команды А, работа команды Б).
Вот еще более сложный пример:
[Image]

На картинке показано:
  • Линия кода проекта Х идет от главной линии. Проект сейчас уже завершен, поэтому ветка закрыта.
  • У команды А есть активная рабочая ветка, идущая от главной линии.
  • У команды А также есть текущий spike, идущий от рабочей ветки.
  • Ветка релиза 2.3 закрыта, т.к. 2.3 уже больше не выпускается и его не нужно сопровождать.
У каждой линии кода есть относительный firmness уровень относительно базовой линии, т.е. каждая линия кода более firm или менее firm (мягче), чем её базовая линия.
  • Firm линия кода стабильна, хорошо протестированная, изменения редки, и близка к релизу.
  • Мягкая линия кода нестабильна, не на 100% покрыта тестами, изменения часты, и далека от релиза.
Нарисуем линии кода так, что firm линии кода будут ответвлятся вверх, а мягкие линии кода - ответвляться вниз. Тогда, взглянув на картинку выше, можно заключить что:
  • Релиз 2.3 firmer чем главная линия.
  • Рабочая ветка команды А мягче, чем главная линия.
  • Сучок команды А мягче, чем её рабочая ветка.
Такая форма начертания, какая использована выше, бывает полезна чтобы показать истории веток, но она может оказаться слишком нагруженной, если у нас уже слишком много веток. Есть более ясный формат, показывающий только существующие линии кода и откуда они идут.
[Image]

Я предлагаю вам изобразить ваши ветки в таком формате и пивешать их на стену! Это бывает очень полезно при обсуждении проблем интеграции.

Здесь есть важное правило - все изменения кода происходят по линиям! Т.е. не должно быть кода, который мерджится прямо из ветки команды А в ветку команды Б, это вызовет много видов затруднений. Вместо этого, изменения команды А должны сначала попасть в главную линию, а затем в ветку команды Б.

Все что выше главной линии называется релизной линией кода, что означает линии кода, которые firmer, чем главная линия.

Все что ниже главной линии называется линией кода разработки (или рабочей линией кода), что означает линии кода, которые мягче, чем главная линия.

Золотое правило сотрудничества:
- Всегда принимать стабилизирующие изменения.
- Никогда не принимать дестабилизирующие изменения.

Так что это значит в терминах различных типов линий кода?
[Image]

Это картинка всего лишь способ в цвете показать что:
  • Любое изменение в релизной линии кода должно быть немедленно смерджино вниз в её базовую линию, вплоть до главной линии.
    • Например: в релизе 2.4.2 поправили ошибку. Её нужно сразу же смерджить в верку релиза 2.4, а затем смерджить в главную линию.
  • Релизная линия кода никогда не должна получить изменения от её базовой линии.
    • Пример: В главною линии поместили новый код. Он не должен попасть в релиз 2.3 и 2.4.
  • Изменение производится последовательно от базовой линии до линии разработки.
    • Пример: Любое изменение в главной линии должно быстро попасть вниз - в команду А и команду Б, и из ветки команды А в сучок команды А.
  • Изменения текут от линии разработки в её базовую линию только в стабильных точках.
    • Пример: команда Б мерджит в главную линию только когда история завершена и протестирована.
Когда бы ни были произведены любые изменения в линии кода и её базовой линии, может понадобиться некоторое слияние. Т.к. в процессе слияния кода потенциально могут возникнуть ошибки, мы хотим делать её в более мягкой ветке из данных двух. После того как слияние завершено и протестировано, мы можем скопировать смердженый код обратно в firmer линию кода.

Если придерживать нашего соглашения рисовать firm линии кода выше, чем мягкие линии кода, то можно получить простое правило:

Правило: мерджи вниз, копируй вверх.

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

Продолжение...
Метки: , ,

Когда мы создаем дополнительные ветки?

vlisivka

2010-03-02 22:50 (UTC)

> Когда мы создаем дополнительные ветки?
> Как можно реже.

Как можно чаще. Мы используем собственную систему для контроля веток в сабверсии (Savana: http://savana.codehaus.org/gettingstarted.html ), и у нас политика — отдельная ветка на каждый тикет в Треке.

Re: Когда мы создаем дополнительные ветки?

anton_nix

2010-03-03 05:04 (UTC)

Как можно чаще означает, что вы создаёте ветку для каждого коммита =)

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

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

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

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

Re: Когда мы создаем дополнительные ветки?

vlisivka

2010-03-03 08:03 (UTC)

Да, мы создаём отдельную ветку для каждого комита в ствол: разработчик создаёт ветку, комитит туда свои изменения, пропускает через тесты, правит, тестирует на виртуальном удалённом чистом хосте, правит, отправляет на peer review, правит, тестирует, правит, отправляет на peer review, интегрирует в development или staging ствол, тестирует, готовит документацию по изменениям, отправляет на ручное тестирование, отправляет менеджеру тикет на закрытие.

У меня уже был опыт, когда я поправил один символ и завалил билд. :-)

Re: Когда мы создаем дополнительные ветки?

anton_nix

2010-03-03 15:56 (UTC)

Спасибо за информацию! Значит у нас примерно одинаковый процесс разработки =)

Вы читаете anton_nix