Как мне подойти к сложному слиянию

25

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

Как безопасно выполнить это слияние, сохранив важные изменения по обе стороны ветви?

Влад Спрейс
источник
Спасибо всем за отличную обратную связь. Я собираюсь попробовать git-imerge, и если это окажется грязным, я буду использовать новый подход ветвления!
Влад Спрейс
Кто-нибудь может объяснить, почему мы не можем использовать git cherry-pickздесь?
Сантош Кумар
1. Молитвы. 2. перебазировать. 3. тест. 4. объединить.
AK_
1
Я предпочитаю перебазировать в этой ситуации, так как это происходит коммитом. Это также позволит вам отключить новую функцию, прежде чем вы сделаете объединенный код доступным. YMMV.
Стивен

Ответы:

27

По сути, объединение двух (возможно, несовместимых) частей кода - это проблема разработки , а не проблема контроля версий . Команда Git merge может помочь в этом процессе, но это зависит от формы проблемы.

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

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

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

Кроме того, насколько зрелой была старая ветка? Это было в хорошем рабочем состоянии, или нет (или неизвестно)? Какая часть функции была закончена?

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

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


источник
+1 «Я мог бы подумать о создании нового форка из последних и ручного включения старой функции снова»
Мика
1
Первый ключевой вопрос: строит ли старая ветка? Это работает? Если нет, то будет очень сложно проверить ваше слияние.
22

Из моего ограниченного опыта работы с git я могу сказать, что иногда быстрее перезапустить ветвь функций снова, если мастер зашел слишком далеко от точки отсоединения.

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

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

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

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

GavinoGrifoni
источник
2
Определенно не правильный подход.
Энди
12
нет, это правильный подход - если у вас есть древняя ветка, и вы не знаете код, попытка слияния не будет очень успешной и будет очень рискованной. Определить изменения, которые были первоначально сделаны, выяснить, имеют ли они вообще отношение к новому коду, и затем применить их, чтобы иметь смысл - это способ сделать это. Это ручной подход, но в этих условиях единственный безопасный. Конечно, я все же сначала попытался бы выполнить слияние, просто чтобы посмотреть, что произойдет, и я бы проверил журнал, чтобы увидеть, сколько изменений произошло и в ветви - это может быть тривиально.
gbjbaanb
10
@DavidPacker: Я не думаю, что GavianoGrifoni предлагает выбросить всю работу за борт. Он предлагает перенести изменения из старой ветки вручную в текущую линию разработки, шаг за шагом. Это выбросит старую историю , не более.
Док Браун
3
@DavidPacker 1-й: ветке год устарел, 2-й: парень, которому поручено завершить его, вообще не знает кода. Учитывая эти 2 фактора, ручное повторное применение является единственным реалистичным способом решения этой задачи. Никто не предлагает простую копию пасты старой ветки.
gbjbaanb
5
@DavidPacker: конфликты слияний могут стать злом - если вам придется разрешить 500 из них одновременно, прежде чем вы снова получите программу в состоянии для компиляции и тестирования. Именно такую ​​ситуацию ожидает ФП. Если вы думаете, что можно эффективно использовать git, чтобы избежать ситуации "все или ничего", почему бы вам не отредактировать свой ответ и не сообщить оператору, как это можно сделать?
Док Браун
16

Git-Imerge предназначен именно для этой цели. Это инструмент git, который предоставляет метод для постепенного слияния. При постепенном слиянии вам нужно иметь дело только с коллизиями между двумя версиями, а не более. Кроме того, гораздо большее количество слияний может быть выполнено автоматически, так как отдельные наборы изменений меньше.

Джо
источник
6

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

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

Вместо этого начните с объединения с первого объекта, слияния обратно в основную линию после разделения устаревшей ветви. Получите, что слияние работает. Затем следующая функция слиться. И так далее. Многие из этих слияний будут сливаться без конфликтов. Еще важно убедиться, что текущая функциональность устаревшей ветви остается совместимой с направлением, по которому прошла магистраль.

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

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

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

Кроме того, это работает и для других систем контроля версий. Иногда мне приходилось объединять конкретную группу SVN-коммитов в ветку (выбор вишни) для одной функции, исправлять ветку для работы с этой функцией, а затем объединять следующую группу SVN-коммитов вместо того, чтобы просто делать svn оптом. слияния.

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

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

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


источник
+1 Это интересное потенциальное альтернативное решение, которое использует слияние для включения больших изменений. Однако я могу видеть обратную сторону: предположим, что у вас есть основные версии ABCDE, и вы хотите включить функциональную ветвь A1 в E. Может потребоваться много усилий, чтобы объединить код в BC и D. Например, что если D к E был большое изменение дизайна, которое сделало постепенные изменения в B, C и D не относящимися к делу? Кроме того, это снова зависит от того, насколько зрелой была функция в первую очередь. Полезный потенциальный подход, но его целесообразность должна быть рассмотрена перед началом.
1

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

Шаг 2. Если функция кажется в целом независимой и затрагивает в основном различные области кода, объединение, исправление конфликтов, тестирование, исправление и т. Д. Это удачный путь, вам в значительной степени хорошо идти. В противном случае перейдите к шагу 3

Шаг 3. Анализ конфликтных зон, понимание функционального воздействия и причин в деталях. Здесь легко могут возникнуть конфликты в бизнес-требованиях. Обсудите с БА, другими разработчиками в зависимости от ситуации. Почувствуйте сложность, связанную с устранением помех.

Шаг 4. В свете вышесказанного, решите, стоит ли стремиться объединить / выбрать вишню / даже вырезать-вставить только те части, которые не конфликтуют и перезаписывают конфликтующие фрагменты, ИЛИ переписывать ли весь элемент с нуля ,

Брэд Томас
источник
0

1. Переключитесь на ветку, которая используется в качестве основной ветки разработчика / релиза.

Это ветка, которая содержит последние изменения в системе. Может быть master, core, dev, это зависит от компании. В вашем случае это, вероятно, masterнапрямую.

git checkout master
git pull

Потяните, чтобы убедиться, что у вас есть последняя версия основной ветки разработки.

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

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

git checkout <name of the obsolete branch>
git pull origin <name of the obsolete branch>

3. Слияние основной ветки разработки с устаревшей веткой.

Перед выполнением следующей команды, убедитесь, что, набрав git branchили git statusвы находитесь в устаревшей ветви.

git merge master

Команда git mergeпопытается объединить содержимое из указанной ветви, в данном случае master, с веткой, в которой вы находитесь.

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

4. Исправить конфликты слияния, зафиксировать и подтолкнуть конфликт исправить

После исправления конфликта слияния во всех файлах, где есть, ставьте, фиксируйте и выдвигайте разрешение конфликта origin.

git add .
git commit -m "fixed the merge conflict from the past year to update the branch"
git push

Обычно вы можете вызвать git add .все файлы для коммита. При работе с конфликтами слияния вы хотите, чтобы все необходимые файлы были обновлены.

Дополнительное примечание

Разрешение конфликта слияния может быть утомительной работой. Особенно, если вы новичок в компании. Возможно, вы еще даже не обладаете необходимыми знаниями для разрешения всех конфликтов слияния.

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


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

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

Энди
источник
6
№ 4 потенциально является проблемой. Если за последний год было много изменений, могут потребоваться серьезные изменения старой функции. Выполнение этого с помощью слияния требует от вас значительных изменений в коде за один раз и надеется, что это сработает, что не является хорошей практикой разработки. Плюс кто знает, в каком состоянии была незавершенная функция? У вас может возникнуть большой беспорядок неработающего кода, и кто знает, было ли это из-за проблем с оригиналом или внесенных вами изменений?
Дэвид, пока этот стандартный подход работает, это нормально, и ОП должен сначала попробовать это. Но в описанной ситуации определенно есть риск получить слишком много конфликтов слияний, чтобы справиться с ними «все или ничего».
Док Браун
@ dan1111 То, что есть конфликты слияния, вполне нормально, и на самом деле их прохождение - это путь. Поскольку ветвь оставалась нетронутой в течение года, вы можете быть уверены, что это не так уж важно и не повлияет на большую часть системы. Таким образом, даже несмотря на то, что ветвь отстает на один год, вы можете получить всего 2 или даже ни одного конфликта слияния.
Энди
4
Предположение, что эта ветвь не важна, неоправданно. Это могло быть фундаментальное изменение дизайна, которое было заброшено и теперь снова принимается. Это может быть что угодно. Вы правы в том, что это может быть простым делом, и конфликтов может быть мало или вообще нет - в этом случае ваш ответ будет правильным. Но это не единственная возможность.
@ dan1111 Если кто-то еще не касался какого-либо места в отдельной ветке в течение года, это не отразится на системных изменениях. Это происходит из моего собственного опыта с устаревшими (6+ месяцев) ветками.
Энди