Рефакторинг и параллельные ветки разработки
Скажем, у вас есть несколько ветвей обслуживания для существующих версий вашего программного обеспечения. Некоторые разработчики вносят непосредственные изменения в ветки обслуживания и периодически сливаются в багажник. Теперь идет обширный рефакторинг в кодеке магистральных каналов, запланированный на предстоящий крупный выпуск. Но это делает ветки обслуживания принципиально несовместимыми с кодом в багажнике, поскольку они могут зависеть от кода, который больше не существует.
Как вы справляетесь с этой ситуацией на практике?
Ответы
Ответ 1
Я бы счел обязанностью разработчика технического обслуживания ветки объединить соответствующее изменение в текущее состояние соединительной линии. Существует несколько возможностей:
- Код в соединительной линии не изменился, и патч применяется без конфликтов.
- Код в соединительной линии изменился, и исправление применимо, но с необходимым ручным слиянием.
- Код в соединительной линии полностью изменился, и патч не может применяться. Разработчик должен оценить, существует ли тот же дефект в соединительной линии, и при необходимости применить эквивалентное исправление.
Случаи 1 и 2 являются обычными путями развития технического обслуживания. Случай 3 - это случай, который вы рассматриваете, когда код соединительной линии не может принять исправление для обслуживания в любой форме. Если разработчик не может сам определить, может ли существовать одна и та же проблема в багажнике, тогда он должен ввести проблему в систему отслеживания проблем. Эта проблема заставит разработчиков соединительных линий учитывать причину патча в ветке обслуживания и может ли тот же самый дефект все еще существовать. Ввод новой проблемы для возможного дефекта в багажнике должен быть последним средством для разработчика обслуживания.
Одно из преимуществ того, что разработчики обслуживания пытаются применить исправления к обновленной магистрали, - это повысить их знакомство с новой базой кода. В конце концов, у них закончится работа по техническому обслуживанию и потребуется работать с новым багажником. По крайней мере, базовый уровень знакомства будет иметь большую пользу.
Ответ 2
Это, в конечном счете, вопрос о командной коммуникации, а не простой вопрос разветвления/слияния.
Первый шаг, как и во всех таких случаях, заключается в том, что у вас есть проблема. Это то, что вы сделали.
Затем вам нужно предупредить всю команду о проблеме.
Как только вы это сделали, я думаю, что есть два разных пути:
-
Если ветки обслуживания используются нечасто, скажем, что выпущенный код довольно зрелый и без ошибок, вы можете решить, что он заблокирован кодом. Каждый разработчик должен завершить работу над 32 октября и слить эти изменения обратно в багажник. Затем ветки должны быть либо закрытыми, либо замороженными. Затем работа может продолжаться в багажнике, и новое программное обеспечение может быть освобождено.
-
Если в ветких происходят частые или срочные изменения и исправления, эта проблема сложнее. Там все еще необходимо замораживание кода, или соединительная линия будет сбита несколько раз. Но здесь разработчикам все равно нужно исправлять ситуацию и предоставлять их клиентам. Я предлагаю, чтобы каждое изменение в ветвях после замораживания кода соединительной линии записывалось в базу данных отслеживания ошибок (обязательно в каждой ситуации) со специальным указанием, что это было зафиксировано в ветки N, но еще не слито с магистралью. Это требует тщательного ведения журнала, чтобы каждая соответствующая деталь запоминалась.
После того, как trunk будет реорганизован, но прежде чем он будет очищен, отполирован, помечен и выпущен, просмотрите базу данных ошибок, особенно элементы, зафиксированные в ветвях, а не туловище. Они все еще актуальны? Теперь пришло время изменить код, если это необходимо. Это может означать двойную работу в течение короткого времени, но, надеюсь, код теперь намного удобнее обслуживать.
После устранения всех известных проблем новая версия может быть выпущена, а старые ветки могут быть закрыты.
Ответ 3
Единственный ответ, который я смог придумать, - это создать ветку обслуживания-ствола непосредственно перед началом рефакторинга. Вы поддерживаете эту новую ветку, как если бы это был багажник, сменив изменения в ветвях выпуска и из них, как обычно. В дальнейшем вы должны быть осторожны в смешении изменений от старой и новой исходных баз.
Другой вариант - попробовать что-то вроде MolhadoRef (статья в блоге о MolhadoRef и SCM, ориентированном на Рефакторинг), если вы можете найти готовую для производства эквивалентную систему, которая соответствует вашим потребностям. Это, теоретически, рефакторинг-контроль источника. Я не заглядывал в это через некоторое время, но, в конце концов, я помню, что это было довольно далеко не просто чем-то вроде исследования и доказательств концепции.
Ответ 4
На практике вам может потребоваться дополнительная работа, чтобы ваши новые изменения были обратно совместимы.
-
Шаг 1: Запустите рефакторинг компонента. На каждом шаге сохраните старый интерфейс, но попросите его перенести вызовы на новую реализацию. Обратите внимание, что это можно сделать несколькими шагами по мере создания нового интерфейса /API. Единичные тесты должны быть в состоянии проверить, что переход от старого к новому работает правильно, но этот шаг, скорее всего, по-прежнему будет нести накладные расходы /QA.
-
Шаг 2: новая версия работает в режиме реального времени; убедитесь, что все об этом знают. На данный момент новые функции не добавлены в старую версию, и все новые (или измененные) вызывающие абоненты используют новую версию.
-
Шаг 3: Найдите все (используйте инструменты для этого), который вызывает старый интерфейс, и измените все, чтобы вызвать новый интерфейс. Это, вероятно, также приводит к большому количеству накладных расходов на тестирование /QA. Каждый вызывающий может быть зафиксирован/выпущен по одному за раз.
-
Шаг 4: На этом этапе новая версия в прямом эфире, и нет доступных абонентов, которые обращаются к старой версии. Удалите его безопасно.
Обратите внимание, что, когда API является общедоступным, и вы не контролируете людей, которые его называют (например, Microsoft, например), вы, возможно, никогда не сможете пройти шаг 2.
Этот процесс может быть медленным, и он требует много дисциплины, коммуникаций и тестирования. Но в тех случаях, когда альтернатива играет на догоняющую/интеграцию навсегда, это может быть разумным вариантом.
Ответ 5
Учитывая, что большая часть затрат на исправление ошибки воспроизводит проблему и тестирует исправление. Можете ли вы написать автоматизированный тест, который будет работать во всех ветвях, даже если исправление кода должно выполняться по-разному для каждой ветки?
Ответ 6
В тот момент, когда ваши ветки обслуживания больше не совместимы с основной стволом, настало время для создания новых ветвей. То есть, в начале большого проекта, вы убедитесь, что все ваши разработчики знают, что новые функциональные возможности поступают в основной багажник, чтобы они могли лучше выбирать, где реализовать исправления. Предположительно, если изменения кода, происходящие в основной соединительной линии, настолько значительны, чтобы сделать обслуживание не поддерживаемым, то обслуживание должно быть включено в основную магистраль.
Ответ 7
Создайте ветвь обслуживания и выполните ее как буфер между соединительной линии и ветвями версии.
Изменения в ветвях версии отправляются в ветку обслуживания, а затем прописываются в магистраль только в том случае, если они могут и наоборот.
Я не думаю, что есть серебряная пуля. Поскольку отрасли расходятся все больше и больше, они будут расти несовместимыми, и поэтому вам нужно подумать о том, как долго вы их поддержите. В противном случае вы можете устранить ошибки более одного раза, но несколько иначе для разных ветвей.
Ответ 8
Это может быть очень трудоемкое предложение, но первое, что приходит мне в голову, - это слияние всего на туловище. Все изменения объединяются обратно в багажник и сохраняют их все вместе. Тогда рефакторинг на багажнике, как вы хотите. Теперь у вас есть рабочий сундук со всеми исправлениями.
К сожалению, это будет означать, что любые исправления в ветвях поддержки должны будут быть выброшены вместе и в центральную часть ствола. Я понимаю, что это будет очень много работы, но я думаю, что это позволит реорганизовать все, и любые улучшения в ветвях поддержки будут принадлежать основной отрасли. Я могу быть наивным по этому поводу, но я действительно не работал над производственным проектом, а также не знаю точно, что в ветких поддержки. Я полагаю, что это позволит полностью обновить багажник, и все ваши улучшения обслуживания будут интегрированы в багажник.
Я полагаю, что делать это таким образом, чтобы максимизировать качество всех ваших веток и переформатировать ваш рефакторинг по всем ветвям, которые вы ответили бы после рефакторинга. Это было бы хорошим способом объединить вашу команду для всего слияния.
Ответ 9
Я вижу два отдельных способа решения этой проблемы:
1.
Значительные изменения в багажнике (например, основной рефакторинг) не должны выполняться в багажнике. Они должны быть сделаны в ветке и слиты обратно в багажник, когда они достаточно стабильны.
Периодически изменения в соединительной линии должны быть объединены с другими ветвями обслуживания. Причина только слияния рефакторинга в багажнике, когда он стабилен, заключается в том, что после этого они будут объединены в ветки обслуживания. Если, однако, нет возможности сделать эти изменения стабильными, тогда вариант 2 будет лучше.
После того как изменения в ветвях обслуживания были сделаны, они затем могут быть объединены обратно в магистраль.
2.
Создайте ветвь ветвей обслуживания (по одной ветки для каждого). Это будет использоваться для слияния магистрали с каждой ветвью обслуживания. (Обратите внимание, что использование внешних или внешних SVN должно использоваться для ограничения количества ветвей обслуживания).
Сделайте все свои рефакторинг в багажнике и объедините их в ветки ветвей обслуживания. Когда вы отпускаете или думаете, что соединительная линия стабильна, объедините эти ветки версий обслуживания обратно в соответствующие ветки. Затем они могут быть объединены обратно в багажник.
Фактически каждая ветвь обслуживания становится "вспомогательной магистралью".
Обратите внимание, что в этом сценарии подчеркивается компромисс между будущим обслуживанием и предварительным обслуживанием. Чем больше разностей и различий в вашем коде, тем больше требуется предварительное обслуживание. Хорошая часть заключается в том, что инкрементное обслуживание намного проще.
Ответ 10
Я могу только откликнуться на то, что говорили другие, подчеркивая настоящую боль в $$, которая может стать очередью патчей.
Если у вас есть предопределенное окно слияния (и железо), вы должны иметь дело с двумя неделями ада.
Ответ 11
У вас есть есть, что многие ветки работают?
Была ли работа над стволом только начата, когда это было сделано, потому что в плане проекта говорилось, что текущий релиз будет готов к отправке, поэтому он был отправлен?
У вас есть много веток по обслуживанию, потому что по какой-то причине клиенты отказываются обновляться до последней версии? Если так, обратитесь к причине.
У вас слишком много старых выпусков, потому что разрыв перед следующим основным выпуском слишком велик?
Вы взимаете плату с клиентов, которые не будут модернизировать больше для обслуживания, так как это будет стоить больше?
Ответ на комментарий:
Microsoft по-прежнему поддерживает Windows XP даже несмотря на то, что Vista отсутствует
Это правда, однако Microsoft не поддерживает Windows XP SP1, хотя XP SP3 отсутствует.
Это не черное и белое, даже если вы не можете остановить поддержку старой версии, вы можете уменьшить количество старых версий, которые вы поддерживаете. Проблема в том, что Sales/Support любит говорить "да", но развитие получает боль, поэтому вам нужно, чтобы ваши продавцы/поддерживали людей на стороне.
Ответ 12
Я думаю, что ваш лучший вариант - рефакторинг итеративный. Вместо того, чтобы делать все рефакторинг одним крупным выстрелом в частной ветке, делайте это по одной фазе за раз. Сделайте несколько наборов изменений на ветке, а затем, когда вы знаете, что они стабильны, объедините их в багажник. Разработчики, работающие в других отраслях, будут нести ответственность за постоянное обновление своего ветки с багажом.
Слияние небольшого набора изменений очень часто будет намного менее эффективным, чем слияние больших ветвей, которые немного отличаются. Чем чаще вы сливаетесь, тем меньше работы вам придется делать в конце.
Ответ 13
В нашем проекте мы не в основном исправляем изменения в ветвях поддержки версий. Если есть ошибка и
- это происходит как в соединительной линии, так и в основной ветке, мы фиксируем ее в соединительной линии, а затем объединяем изменение в ветку обслуживания (что может происходить чисто или требует больше работы, и в этом случае мы решаем, не лучше, если ошибка исправлена только в новой версии).
- это только в ветке обслуживания, вероятно, есть некоторый король исправления в багажнике, и мы переходим к сценарию номер один.
Ответ 14
Как указал Грег, существует несколько возможных сценариев.
Я бы добавил случай (2.5), где требуется ручное слияние, но поскольку вы перенесли метод из своего исходного местоположения и затем применили некоторые изменения, становится сложно слить, особенно если "базовый" код был также изменен в филиале "обслуживание". Это не так необычно, как кажется, на самом деле перемещение метода в другое место и применение небольшого исправления довольно распространено.
Мы разработали инструмент под названием Xmerge (cross-merge), который является первым шагом к слиянию с рефакторингом. Он еще не автоматичен, но он помогает справляться с жесткими слияниями, связанными с перемещенным кодом. Он описан здесь и уже интегрирован в Пластик SCM 2.7.
Мы работаем над: автоматическим обнаружением движения, а также возможностью "перекрестного слияния" по отношению к нескольким целевым файлам (вы перемещаете код в другой файл, что также довольно часто).