Стратегии слияния 1 год разработки в Visual Studio

32

У меня есть клиент, который настаивал на том, чтобы мы полностью отделили нашу новую разработку от основных веток на весь 2016 год. У них было 3-4 другие команды, работающие над приложением в различных областях. Многочисленные большие изменения были внесены (переключение, как делается внедрение зависимостей, очистка кода с помощью ReSharper и т. Д.). Теперь мне пришло в голову объединить main с нашей новой веткой разработчиков, чтобы подготовиться к продвижению наших изменений по цепочке.

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

Есть ли подход, который я могу использовать, чтобы мне было легче?

Чтобы уточнить, я много раз выражал озабоченность этим подходом. Клиент был и знает о трудностях с этим. Поскольку они выбрали нехватку персонала QA (1 тестер на 4 разработчика, никакого автоматического тестирования, небольшое регрессионное тестирование), они настаивали на том, чтобы мы держали нашу ветвь изолированной от изменений в основной ветке под предлогом, что это уменьшит потребность в нашем тестер, чтобы знать об изменениях, вносимых в другом месте.

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

user258451
источник
63
Нет. У вас есть две отдельные ветви, которые активно развивались в течение года. Слияние будет сосать.
17 из 26
2
Какова степень изменений, которые внесла ваша команда? Может быть более эффективно идентифицировать эти изменения и затем вручную повторно применить их к текущей основной кодовой базе.
kdgregory
2
Это 2015 или 2016 год? Если его 2015 его 2 года, а это значит, что он будет вдвойне сосать.
Дэвид говорит восстановить Монику
1
Почему клиента волнует, что работа, которую вы выполняете для него, находится в отдельной ветке в вашей системе контроля версий?
Ixrec
17
Что бы вы ни делали, убедитесь, что вы выставляете счета каждый час.
Шон МакSomething

Ответы:

37

Был бы простой способ отделить вашу новую разработку от основной ветки, не приводя вас к этой неудачной ситуации: любые изменения из ствола должны были бы ежедневно сливаться в вашу ветку разработки . (Был ли ваш клиент действительно настолько близоруким, что не мог предвидеть, что когда-нибудь ваш филиал должен вернуться обратно в основную линию?)

В любом случае, лучший подход - ИМХО попытаться повторить то, что должно было произойти из первых рук:

  • определить семантику изменений в основной строке за 1 день после создания ветки. Примените их к своей текущей кодовой базе так хорошо, как можете. Если это было «локальное изменение», оно должно быть простым, если это был «сквозной рефакторинг», такой как переименование широко используемого класса, применить его семантически эквивалентным образом к вашей текущей кодовой базе. Надеемся, что в течение этого года не было никаких противоречивых сквозных изменений в кодовой базе в «вашей» ветке, в противном случае это может стать настоящим дразнителем
  • проверить результат (я уже говорил, вам нужен хороший набор тестов для этой задачи)? Исправить все ошибки, обнаруженные тестом
  • Теперь повторите этот процесс для изменений в основной строке для дня 2, затем дня 3 и так далее.

Это может сработать, когда команды строго соблюдают классические правила контроля версий («только коммитить скомпилированные, протестированные состояния» и «регистрировать рано и часто»).

После 365 повторений (или 250, если вам повезет, и вы можете связать работу для изменений выходных), вы почти закончите (почти, потому что вам нужно добавить количество изменений, которые произойдут с основной линией в течение периода интеграции ). Последний шаг - снова объединить обновленную ветку dev в ствол (чтобы вы не потеряли историю ствола). Это должно быть легко, потому что технически это должна быть только замена затронутых файлов.

И да, я серьезно, вероятно, нет ярлыка для этого. Может оказаться, что «ежедневные порции» иногда бывают слишком маленькими, но я бы не ожидал, что, скорее всего, ежедневные порции могут оказаться слишком большими. Я надеюсь, что ваш клиент платит вам очень хорошо за это, и что это настолько дорого для него, что он извлечет уроки из своей неудачи.

Я должен добавить, что вы можете попробовать это также с измененными сторонами - реинтеграция изменений из вашей ветки небольшими порциями в основную линию. Это может быть проще, когда в вашей ветке dev было гораздо меньше изменений, чем в транке, или большинство изменений произошло в новых исходных файлах, которые в настоящее время не являются частью транка. Это можно рассматривать как «портирование» функции с продукта A (ветка dev) на несколько иной продукт B (текущее состояние транка). Но если бы большинство сквозных рефакторингов было выполнено на основной линии, и они влияют на ваш новый код (коллизии слияния 6500, кажется, являются некоторым доказательством этого), возможно, будет проще, как я описал вначале.

Док Браун
источник
9
Если вы продолжаете разработку соединительной линии во время реинтеграции, я предлагаю вам сначала разветвить наконечник ствола и продолжить разработку. В противном случае вы эффективно объединяете прошлое и будущее одновременно. Но я полагаюсь на Дока Брауна на любые пространственно-временные разрывы, естественно.
Радар Боб
1
@radarbob: то, что вы предлагаете, имеет смысл только в том случае, если OP интегрируется из dev в trunk, но не тогда, когда он решает объединиться из trunk в dev, как я описал вначале. Если OP изо дня в день передает изменения из внешней линии в свою ветку разработки (начиная с изменений, произошедших 365 дней назад), не имеет значения, будет ли продолжаться разработка в внешней линии. Ему просто придется продолжать эту тактику, пока он не достигнет настоящего (предполагается, что он может интегрировать и тестировать изменения этих 3-4 команд за один день менее чем за один день).
Док Браун
Цитата: «Я должен добавить, что вы можете попробовать это также с измененными сторонами - реинтеграция изменений из вашей ветки в ежедневные связки в основную линию». Мое чувство пауков перегорает. Я чувствую потенциальный каскад «гармонического резонансного искажения» с конфликтующими интеграциями изменений.
radarbob
Это хороший совет. См. Редактирование, чтобы обратиться к нескольким вещам здесь.
user258451
1
@ user258451: значит, у вас были разные команды QA для ствола и новой ветки разработчиков, которые не хотели общаться друг с другом? Великий Скотт: - ((
Док Браун
14

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

  • Возьмите копию оригинала в нерабочем состоянии
  • Разница между необработанным и последним
  • Сломать любые общие элементы
    • Например, все изменения имени функции, затем изменения параметров и т. Д.
    • Игнорируйте пробелы в diff, если стандарты изменились, иначе вы будете тратить много времени на подсчет пробелов
  • Сначала сфокусируйтесь на основной функциональности

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

Ключ должен продолжать идти.

Редактировать:

Предупреждение: этот подход будет означать, что история управления версиями станет «испорченной», так как вы потеряете свидетельство слияния ветвлений с ветвями, а также историю не слитых ветвей.

Благодаря комментариям от «Джека Эйдли» и «17 из 26»

Эрдрик Айронроуз
источник
1
Основная проблема этого подхода заключается в том, что он уничтожит запись изменений, оставленных в системе контроля версий.
Джек Эйдли
По сути, если во время слияния сделать все те же изменения во второй раз, у вас все равно останется журнал изменений, он будет в том же порядке, что и при слиянии, а не в том порядке, в котором они были сделаны во время разработки. Не идеально, но лучше, чем ничего. Кроме того, у вас все еще будет исходное состояние без изменений, если оно будет храниться в режиме контроля версий.
Эрдрик Айронрос Роуз
У вас будет журнал изменений, но у вас не будет исторических свидетельств того, что изменения были объединены от ветви к ветви. Это было бы огромной проблемой в TFS, которая предлагает вам только необработанные наборы изменений на выбор при объединении из ветви в ветвь.
17 из 26
@ 17of26 Хотя я согласен с тем, что вы можете восстановить некоторые записи об изменениях, 17 из 26 верен, что эта запись не будет полной или точной. Возможно, этот подход достаточно прост, чтобы сделать эту потерю записи приемлемым компромиссом, учитывая плохую ситуацию, в которой они сейчас находятся. Тем не менее, я думаю, что это важный недостаток, который нужно признать независимо от того, что они решат.
Джек Эйдли
1
@ Jack Aidley Я определенно согласен, что это довольно проблематично, поэтому я добавил немного к своему ответу, чтобы поразмышлять. Я надеюсь, что все в порядке?
Эрдрик Айронроуз
8

Несколько лет назад у нас был клиент с одинаковыми требованиями по отделению филиалов. Так мы и сделали.

Мы никогда не сливали их филиал обратно. У них там была своя уникальная версия. Мы взяли с них дополнительную плату за изменения, так как по существу у нас было два главных ствола вместо одного основного ствола и ответвлений.

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

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

Джон Рейнор
источник
Эта стратегия возможна только в том случае, если разные направления развития ориентированы на разных клиентов. Или, если варианты использования, в которых участвует продукт, позволяют использовать две разные линии продуктов параллельно, неинтегрированным образом. Насколько я понимаю, OP описывает ситуацию, когда новая линия разработки нацелена на того же клиента, что и тот, кто использует транк, и неясно, может ли параллельное использование двух линий продуктов иметь какой-то смысл для его случая.
Док Браун
1

Это не будет весело, но насколько болезненным это будет, зависит от характера изменений и от того, насколько они изолированы.

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

Инструмент слияния довольно тупой, потому что он смотрит только на текстовые различия и никак не понимает код. Если основная ветвь изменила имя класса, используемого в приложении, и ветвь функции использует старое имя в каком-то новом коде, тогда инструмент слияния не поймет, что имя класса также следует изменить в новом коде. Но если вы выполните рефакторинг в ветви B, чтобы переименовать класс, как в ветви A, он будет работать как в старом, так и в новом коде, и слияние пройдет гладко.

Во-вторых, вы должны проверить, насколько локализованы изменения в ветке разработки. Если изменения в ветви функций локализованы в нескольких областях, вам не нужно объединять незатронутый код, вы можете просто скопировать и перезаписать из основной ветви.

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

JacquesB
источник