Продолжаете ли вы разработку в ветке или в стволе?
Предположим, вы разрабатываете программный продукт с периодическими выпусками. Каковы лучшие практики в отношении ветвления и слияния? Отрезание веток периодического выпуска для широкой публики (или от того, кем является ваш клиент), а затем продолжение разработки в стволе, или рассмотрение ствола в качестве стабильной версии, периодическая пометка этого выпуска как релиза и выполнение экспериментальной работы в ветвях. Что думают люди, считается ли сундук "золотым" или "песочницей"?
23 ответа
Я пробовал оба метода с большим коммерческим применением.
Ответ о том, какой метод лучше, сильно зависит от вашей конкретной ситуации, но я напишу то, что показал мой общий опыт.
Лучший метод в целом (по моему опыту): багажник должен быть всегда устойчивым.
Вот некоторые рекомендации и преимущества этого метода:
- Закодируйте каждую задачу (или связанный набор задач) в отдельной ветке, и тогда у вас будет гибкость, когда вы захотите объединить эти задачи и выполнить выпуск.
- QA должен быть сделан на каждой ветви, прежде чем она будет объединена с транком.
- Проведя QA в каждой отдельной ветке, вы будете точно знать, что стало причиной ошибки.
- Это решение подходит для любого количества разработчиков.
- Этот метод работает, так как ветвление является почти мгновенной операцией в SVN.
- Отметьте каждый релиз, который вы выполняете.
- Вы можете разрабатывать функции, которые вы не планируете выпускать некоторое время, и решить, когда именно их объединить.
- За всю работу, которую вы делаете, вы можете получить выгоду от фиксации своего кода. Если вы работаете только из транка, вы, вероятно, будете часто сохранять свой код незафиксированным, а значит, незащищенным и без автоматической истории.
Если вы попытаетесь сделать обратное и выполнить всю свою разработку в стволе, у вас возникнут следующие проблемы:
- Постоянные проблемы со сборкой для ежедневных сборок
- Потеря производительности, когда разработчик совершает проблему для всех других людей в проекте
- Более длинные циклы выпуска, потому что вам нужно, наконец, получить стабильную версию
- Менее стабильные релизы
У вас просто не будет той гибкости, которая вам нужна, если вы попытаетесь сохранить стабильную ветвь и транк в качестве изолированной среды разработки. Причина в том, что вы не можете выбрать из ствола то, что хотите поместить в этот стабильный выпуск. Это было бы уже все смешано в багажнике.
В частности, один случай, который я бы сказал, чтобы выполнить всю разработку в стволе, - это когда вы начинаете новый проект. Могут быть и другие случаи в зависимости от вашей ситуации.
Кстати, распределенные системы контроля версий обеспечивают гораздо большую гибкость, и я настоятельно рекомендую перейти на hg или git.
Я работал с обоими методами, и я бы сказал, что разработка на магистральной линии и ответвления от стабильных точек как релизов - лучший путь.
Те люди выше, кто возражает, говоря, что вы будете иметь:
- Постоянные проблемы со сборкой для ежедневных сборок
- Потеря производительности, когда разработчик совершает проблему для всех других людей в проекте
вероятно, не использовали методы непрерывной интеграции.
Это правда, что если вы не выполняете несколько тестовых сборок в течение дня, скажем, раз в час или около того, они останутся открытыми для этих проблем, которые быстро задушат темпы разработки.
Выполнение нескольких тестовых сборок в течение дня быстро сворачивает обновления основной базы кода, чтобы другие могли использовать ее, а также предупреждает вас в течение дня, если кто-то сломал сборку, чтобы они могли исправить ее перед отправкой домой.
Как указывалось, только обнаружение неисправной сборки, когда ночная сборка для запуска регрессионных тестов не дает результатов, является чистой глупостью и быстро замедлит процесс.
Прочитайте статью Мартина Фаулера о непрерывной интеграции. Мы развернули нашу собственную такую систему для крупного проекта (3000kSLOC) в около 2000 строк Posix sh.
Я склонен использовать подход "ветвь релиза". Ствол летучий. По мере приближения времени выпуска я делаю ветку релиза, к которой я отношусь более осторожно. Когда это наконец будет сделано, я помечу / пометю состояние репозитория, чтобы я знал "официальную" выпущенную версию.
Я понимаю, что есть другие способы сделать это - это просто способ, которым я делал это в прошлом.
И то и другое.
Магистраль используется для большинства разработок. Но ожидается, что будут приложены все усилия, чтобы любая регистрация в багажнике не сломала его. (частично проверено автоматизированной системой сборки и тестирования)
Релизы хранятся в своем собственном каталоге, в них вносятся только исправления ошибок (а затем объединяются в транк).
Любая новая функция, которая собирается оставить транк в нестабильном или нерабочем состоянии, выполняется в отдельной ветке, а затем по завершении объединяется в транк.
Мне нравится и используется подход, описанный Хенриком Книбергом в " Контроль версий" для нескольких гибких команд. Хенрик проделал большую работу, объяснив, как работать с управлением версиями в гибкой среде с несколькими командами (работает и для одной команды в традиционных средах), и нет смысла перефразировать его, поэтому я просто выложу "шпаргалку" (которая самоочевидно) ниже:
Я люблю его, потому что:
- Это просто: вы можете получить это с картинки.
- Он работает (и масштабируется) без особых проблем слияния и конфликта.
- Вы можете выпустить "работающее программное обеспечение" в любое время (в духе agile).
И на случай, если это не было достаточно явным: разработка выполняется в "рабочей ветви (ветках)", транк используется для кода DONE (освобождаемого). Проверьте Управление версиями для нескольких Agile команд для всех деталей.
Хорошей ссылкой на процесс разработки, который поддерживает стабильность магистрали и выполняет всю работу в филиалах, является система разработки окончательного качества Divmod. Краткое резюме:
- Вся проделанная работа должна иметь билет, связанный с ней
- Новая ветвь создается для каждого тикета, где выполняется работа для этого тикета
- Изменения из этой ветви не объединяются обратно в магистральную магистраль без проверки другим участником проекта.
Для этого они используют SVN, но это легко сделать с любой из распределенных систем контроля версий.
Я думаю, что ваш второй подход (например, пометка выпусков и выполнение экспериментальной работы в ветвях, учитывая стабильность ствола) является лучшим подходом.
Должно быть ясно, что ветви наследуют все ошибки системы в тот момент, когда она разветвляется: если исправления применяются к стволу, вам придется переходить один за другим ко всем ветвям, если вы поддерживаете ветки как своего рода терминатор цикла освобождения. Если у вас уже было 20 выпусков, и вы обнаружили ошибку, которая восходит к первой, вам придется повторно применить исправление 20 раз.
Предполагается, что ответвления будут настоящими песочницами, хотя ствол также должен будет играть эту роль: теги будут указывать, является ли код "золотым" в тот момент времени, пригодным для выпуска.
Мы развиваемся на магистральной линии, если изменения не являются слишком значительными, дестабилизирующими или мы приближаемся к основному выпуску одного из наших продуктов, и в этом случае мы создаем временную ветвь. Мы также создаем постоянную ветку для каждого отдельного выпуска продукта. Я нашел документ Microsoft о руководстве по ветвлению весьма полезным. Учебное пособие Эрика Синка по ветвлению также интересно, и указывает, что то, что работает для Microsoft, может быть слишком тяжелым для некоторых из нас. Это было в нашем случае, мы фактически используем подход, который, по словам Эрика, делает его команда.
Это зависит от ваших ситуаций. Мы используем Perforce и, как правило, имеем несколько направлений развития. Магистраль считается "золотой", и вся разработка происходит в ветвях, которые объединяются с основной линией, когда они достаточно стабильны для интеграции. Это позволяет отклонить функции, которые не делают вырезки, и может предоставить солидную инкрементную возможность с течением времени, которую могут выбрать независимые проекты / функции.
Интеграция и отслеживание новых функций, внедряемых в магистраль, сопряжены со стоимостью интеграции, но вы все равно будете страдать от этой боли. Объединение всех разработчиков в ствол может привести к ситуации на Диком Западе, а ветвление позволяет вам масштабировать и выбирать точки, в которых вы хотели бы принять таблетки горькой интеграции. В настоящее время мы работаем с более чем сотней разработчиков в дюжине проектов, каждый с несколькими выпусками, использующими одни и те же основные компоненты, и это работает довольно хорошо.
Прелесть этого в том, что вы можете сделать это рекурсивно: большая ветвь функции может быть собственной магистралью с другими ветвями, если она выпадает. Кроме того, финальные выпуски получают новую ветку, чтобы дать вам место для стабильного обслуживания.
Мы используем ствол для основной разработки и ответвления для обслуживания релизов. Работает хорошо. Но тогда ветвления должны использоваться только для исправления ошибок, без каких-либо серьезных изменений, особенно на стороне базы данных, у нас есть правило, что только изменение схемы может происходить в основной магистрали, а не в ветке.
Попытка управлять поддержанием текущего производственного кода в соответствии с новой разработкой в лучшем случае проблематична. Чтобы смягчить эти проблемы, код должен перейти в строку обслуживания после завершения тестирования и готовности кода к отправке. Кроме того, основная ветвь должна ветвиться, чтобы помочь в стабилизации выпуска, сдержать экспериментальные усилия по разработке или разместить любые усилия по разработке, жизненный цикл которых распространяется на несколько выпусков.
Необслуживаемая ветвь должна создаваться только тогда, когда существует вероятность (или определенность) коллизий в коде, которыми трудно было бы управлять любым другим способом. Если филиал не решит логистическую проблему, он создаст ее.
Нормальная разработка релиза происходит в основном. Разработчики проверяют и выходят из основной линии для нормальной работы релиза. Работа по разработке исправлений для текущего производственного кода должна быть в ветке для этого выпуска, а затем объединена с основной линией после того, как исправление прошло тестирование и развернуто. Работа в отделениях, не связанных с техническим обслуживанием, должна координироваться в индивидуальном порядке.
Это зависит от размера ваших усилий по разработке. Несколько команд, работающих параллельно, не смогут эффективно работать над одним и тем же кодом (транком). Если у вас работает небольшая группа людей, и ваша главная задача - обрезать ветку, чтобы вы могли продолжить работу, возвращаясь к ветке для исправления ошибок в текущем производственном коде, который будет работать. Это тривиальное использование ветвления и не слишком обременительное.
Если у вас много параллельной разработки, вам понадобятся ветки для каждой из этих работ, но это также потребует большей дисциплины: убедитесь, что ваши ветки протестированы и готовы к слиянию. Планирование слияния, поэтому две группы не пытаются объединиться одновременно и т. Д.
Некоторые ветви разрабатываются так долго, что вам нужно разрешить слияния из магистрали в ветку, чтобы уменьшить количество неожиданностей при окончательном слиянии с магистралью.
Вам придется экспериментировать, если у вас большая группа разработчиков и вы почувствуете, что работает в вашей ситуации. Вот страница от Microsoft, которая может быть несколько полезной: http://msdn.microsoft.com/en-us/library/aa730834(VS.80).aspx
Если вы собираетесь работать с циклом выпуска, большая функция, вы выходите из ветки. В противном случае мы работаем в транке и разветвлении для каждой производственной версии, которую мы создаем.
Предыдущие производственные сборки в это время перемещаются в old_production_, а текущий выпуск продукта всегда является только производственным. Все, что знает наш сервер сборки о производстве, - это как развернуть производственную ветку, и мы запускаем эту сборку с помощью принудительного запуска.
Мы придерживаемся принципа ствола = текущий поток разработки, ветвь = релиз (ы). При выпуске клиенту мы разветвляем ствол и просто продолжаем вращать ствол. Вам нужно будет решить, сколько выпусков вы готовы поддерживать. Чем больше вы поддерживаете, тем больше слияний вы будете исправлять. Мы стараемся держать наших клиентов не более чем в двух выпусках за стволом. (Например, Dev = 1.3, поддерживаемые выпуски 1.2 и 1.1).
Вот дизайн SVN, который я предпочитаю:
- корень
- развитие
- ветви
- feature1
- feature2
- ...
- хобот
- ветви
- бета
- теги
- хобот
- релиз
- теги
- хобот
- развитие
Вся работа выполняется из разработки / транка, за исключением основных функций, которые требуют собственной ветки. После того, как работа протестирована на развитие / транк, мы объединяем протестированные проблемы в бета / транк. При необходимости код проверяется на бета-сервере. Когда мы готовы выложить некоторые изменения, мы просто объединяем соответствующие ревизии в release/trunk и внедряем.
Теги могут быть сделаны в бета-версии или в ветке релиза, чтобы мы могли отслеживать конкретный релиз как для беты, так и для релиза.
Такая конструкция обеспечивает большую гибкость. Это также позволяет нам оставлять ревизии в бета-версии / стволе, в то же время объединяя другие версии в выпуск / ствол, если некоторые ревизии не прошли тестирование в бета-версии.
Транк обычно должен быть вашим основным источником разработки. В противном случае вы будете тратить много времени на слияние новых функций. Я видел, как это происходит по-другому, и это обычно приводит к большим головным болям интеграции в последнюю минуту.
Мы помечаем наши релизы, чтобы мы могли быстро реагировать на производственные ситуации, не распространяя активную разработку.
Для меня это зависит от программного обеспечения, которое я использую.
Под CVS я бы просто работал в "транке" и никогда не тегировал / не разветвлял, потому что было очень больно делать иначе.
В SVN я делал бы свои "передовые" вещи в транке, но когда пришло время делать push на сервере, помечался соответствующим образом.
Я недавно перешел на git. Теперь я обнаружил, что никогда не работаю в багажнике. Вместо этого я использую именованную ветвь с песочницей "new-featurename", а затем объединяюсь с фиксированной веткой "current-production". Теперь, когда я думаю об этом, я действительно должен сделать ветки "release-VERSIONNUMBER", прежде чем вернуться к "current-production", чтобы я мог вернуться к более старым стабильным версиям...
Ствол, как правило, является основной линией развития.
Релизы разветвлены, и часто экспериментальная или основная работа выполняется над ветвями, а затем сливается обратно в магистраль, когда она готова к интеграции с основной линией разработки.
Это действительно зависит от того, насколько хорошо ваша организация / команда управляет версиями и какой SCM вы используете.
- Если то, что будет дальше (в следующем выпуске), может быть легко спланировано, вам лучше заниматься разработкой в стволе. Управление филиалами занимает больше времени и ресурсов. Но если следующий план не может быть легко спланирован (это происходит постоянно в крупных организациях), вы, вероятно, в конечном итоге закончите сбором вишен (сотни / тысячи), а не ответвлениями (несколько или десятки).
- С Git или Mercurial управлять ветвями намного проще, чем cvs и subversion. Я бы пошел на методологию стабильных стволовых / тематических веток. Это то, что использует команда git.git. прочитайте: http://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html
- С Subversion я впервые применил методологию разработки в багажнике. Когда дело дошло до даты релиза, было довольно много работы, потому что каждый раз мне приходилось выбирать коммиты (моя компания плохо разбиралась в планировании). Теперь я эксперт в Subversion и хорошо знаю, как управлять ветками в Subversion, поэтому я перехожу к методологии стабильных стволовых / тематических веток. Это работает намного лучше, чем раньше. Сейчас я пытаюсь понять, как работает команда git.git, хотя мы, вероятно, будем придерживаться Subversion.
Прочитайте это: http://oreilly.com/catalog/practicalperforce/chapter/ch07.pdf
Метод, который мы используем, - это подход Perforce, который подробно обсуждается в великой книге Лоры Вингер:
http://oreilly.com/catalog/9780596101855/index.html
В то время как книга ориентирована на перформанс (Wingerd - менеджер по продуктам Perforce), концепции можно применять к любой или ко всем VCS.
Подход к исполнению (и платформа) послужил нам очень хорошо. Он используется во многих фирмах (Google, Intuit и, как я слышал, сама Microsoft Windows).
Книга стоит того, чтобы ее прочитать.
ИМХО нет единого универсального ответа на вопрос о соглашении о подрывной деятельности.
Это действительно зависит от динамики проекта и компании, использующей его. В очень быстро меняющейся среде, когда выпуск может происходить так же часто, как каждые несколько дней, если вы попытаетесь неукоснительно пометить тегами и выполнить ветвление, вы получите неуправляемое хранилище. В такой среде подход "ветвление при необходимости" создал бы намного более поддерживаемую среду.
Кроме того, по моему опыту, с чисто административной точки зрения чрезвычайно легко переключаться между методологиями SVN, когда вы решите.
Я знаю, что лучше всего работают два подхода: ветвление при необходимости и ветвь каждой задачи. Это, конечно, своего рода полная противоположность друг другу. Как я уже сказал - все дело в динамике проекта.
@Brian R. Bondy: Обратите внимание, что это не решение, когда ваша команда достигает определенного количества задач / заданий, параллельно выполняемых в проекте.
После того, как отдел обеспечения качества вовлечен в qa, усилия, необходимые для обеспечения одной установки на каждую выполняемую ветвь, просто слишком велики. Подумайте SOA/ Клиенты / Серверы / Веб-сервисы / Базы данных, все из которых должны быть предоставлены для каждой ветви.
В этом решении также отсутствует этап интеграции.