Як мені підійти до складного злиття


25

Ось угода, я приєднався до нової компанії, і мене попросили закінчити роботу у галузі, яку не торкалися майже рік. Тим часом головна галузь постійно зростала. В ідеалі я хотів би об'єднати всі зміни від головної гілки в гілку функцій і продовжити роботу звідти, але я не надто впевнений, як до цього підходити.

Як безпечно виконати це злиття, зберігаючи важливі зміни з обох боків гілки?


Дякую всім за чудові відгуки. Я збираюся подати git-imerge, і якщо це виявиться безладним, я застосую новий підхід!
Влад Спріс

Хтось може пояснити, чому ми не можемо використовувати git cherry-pickтут?
Сантош Кумар

1. Молитви. 2. ребаза. 3. тест. 4. злиття.
AK_

1
Я вважаю за краще відмовлятися в цій ситуації, оскільки це буде виконуватись зобов'язаннями. Це також дозволить вам скосати нову функцію, перш ніж зробити доступним об'єднаний код. YMMV.
Стівен

Відповіді:


27

По суті, як поєднувати два (можливо, несумісні) фрагменти коду - це проблема розвитку , а не проблема контролю версій . Команда Git merge може допомогти в цьому процесі, але це залежить від форми проблеми.

Порівнювати обидві версії з базовою спочатку має найбільш сенс. Це дасть вам уявлення про найкращу стратегію для досягнення цього шляху. Ваш підхід може бути різним залежно від характеру та перекриття змін у кожній галузі.

Уявіть ідеальний сценарій: ви дізнаєтесь, що основна гілка та функціональна гілка модифікують лише взаємовиключні частини коду, щоб ви могли просто здійснити всі зміни та бути корисними.

Звичайно, це майже точно не буде, але питання полягає в тому, наскільки далеко від цього ідеального сценарію він не буде? тобто наскільки змішуються зміни?

Крім того, наскільки зрілою була стара галузь функції? Був він у хорошому робочому стані, чи ні (чи невідомо)? Скільки було закінчено?

Якщо відповідний код у головній гілці за останній рік сильно змінився або функція не в дуже зрілому стані, я можу розглянути можливість створення нової вилки останньої та вручну знову включити стару функцію. Це дозволить вам скористатися поступовим підходом до його роботи.

Якщо ви зробите безладний злиття безлічі коду, і він не працює, налагодити це буде досить важко. Якщо за останній рік основна галузь сильно змінилася, можливо, знадобляться значні зміни в дизайні функції, щоб вона працювала. Не було б доцільним вносити ці зміни за допомогою "вирішення конфліктів", оскільки для цього потрібно внести всі зміни одразу і сподіватися, що вони спрацюють. Ця проблема ускладнюватиметься можливістю помилок у старій частково готовій гілці.


+1 "Я можу розглянути можливість створення нової вилки останніх і вручну включити стару функцію знову"
mika

1
Перше ключове питання: чи будується стара філія функції? Він працює? Якщо ні, то перевірити ваше злиття буде дуже важко.
Móż

22

У моєму обмеженому досвіді git я можу сказати, що іноді швидше знову перезапустити гілку функції, якщо майстер зайшов занадто далеко від точки відключення.

Об’єднати дві гілки, не знаючи історії за кодом (враховуючи, що ви щойно приєдналися до проекту), справді важко, і я маю надію, що навіть розробник, який слідкував за проектом з самого початку, швидше за все, зробить деякі помилки при злитті.

Це, звичайно, має сенс, якщо гілка функції не є величезною, але ви можете просто тримати відкриту стару гілку функції , знову відгалужуватися від головного та вручну вводити зміни, які складають цю функцію. Я знаю, що це найбільш ручний підхід, але він дозволяє вам повністю контролювати у разі відсутності або переміщення коду.

Парне програмування зі старшим у цьому випадку було б найкращим сценарієм, що допоможе вам краще познайомитися з кодом.
Це навіть може виявитися більш швидким, якщо врахувати конфлікти злиття та час тестування!

Я якось припускав, що принаймні спроба зробити злиття - це, очевидно, найкраще. Якщо це не вдається або виявляється занадто важким, то спробуйте збирати вишню, якщо це піде не так, рушайте ручним шляхом.


2
Однозначно не правильний підхід.
Енді

12
ні, це правильний підхід - якщо у вас є стародавня гілка, і ви не знаєте коду, спроба злиття не буде дуже успішною, і це буде дуже ризиковано. Визначити зміни, які були вперше внесені, дослідити, чи вони навіть стосуються нового коду, а потім застосувати їх, щоб мати сенс - це спосіб це зробити. Це ручний підхід, але в цих умовах єдиний безпечний. Звичайно, я б все-таки спробував об'єднати спочатку, лише щоб побачити, що відбувається, і я перевірив би журнал, щоб побачити, скільки змін відбулося і на гілці - може бути тривіальним.
gbjbaanb

10
@DavidPacker: Я не думаю, що GavianoGrifoni пропонує кинути всю роботу за борт. Він пропонує перенести зміни зі старої гілки вручну в поточну лінію розвитку, поетапно. Це викине стару історію , не більше.
Doc Brown

3
@DavidPacker 1-е: гілка застаріла, 2-й: хлопець, якому доручено закінчити, код взагалі не знає. Враховуючи ці 2 фактори, ручне повторне застосування - єдиний реалістичний спосіб підійти до завдання. Ніхто не пропонує простої копії-вставки перегляду наконечника старої гілки.
gbjbaanb

5
@DavidPacker: Конфлікти злиття можуть стати злими - якщо вам доведеться вирішити 500 з них одразу, перш ніж ви знову отримаєте програму у складеному та тестованому стані. Такої ситуації, на яку очікує ОП. Якщо ви вважаєте, що можливо використовувати Git ефективно, щоб уникнути цієї ситуації "все-чи нічого", чому б вам не відредагувати свою відповідь і не сказати ОП, як це можна зробити?
Doc Brown

16

git-imerge розроблений саме для цієї мети. Це інструмент git, який забезпечує метод поступового злиття. Поступово об'єднуючись, вам потрібно боротися лише зі зіткненнями між двома версіями, ніколи більше. Крім того, значно більша кількість злиття може виконуватися автоматично, оскільки окремі набори змін менші.


6

Спроба з’єднати голову магістралі на відстояну гілку року може бути вправою розладу та поглиблення вм'ятини на столі лобом.

Основна лінія не потрапила туди, де вона знаходиться за один хід протягом місяців. Він також мав розробку та випуски. Спроба довести все це до кінця в одному монолітному злитті може бути надзвичайною.

Натомість почніть з об’єднання з першої функції об'єднання назад в основну лінію після розщеплення гілки. Отримайте , що злиття працювати. Потім наступна функція зливається. І так далі. Багато з цих функцій злиття злиються без конфлікту. Ще важливо переконатися, що поточна функціональність застарілої гілки залишається сумісною з тим напрямом, в який пройшла основна лінія.

Ви можете відмовитися від голови несвіжої гілки для злиття в інших змінах. Це більше про те, щоб переконатися, що комісії та історія, коли хтось озирається на неї, є чіткими та повідомляють, яка роль та політика кожної галузі. Відстояла гілка була особливою гілкою. Той, над яким ви працюєте, - це галузь накопичення та примирення.

Багато з цього буде простішим, якщо старі гілки функцій або випусків все ще існують там і є легкодоступними (у деяких місцях існує політика очищення назв гілок, які є старшими за певну дату, щоб список гілок не був непосильним ).

Важливим у всьому цьому є переконатися, що ви протестуєте та виправляєте після успішного об’єднання кожної частини історії основної лінії на свої місця. Хоча щось може зливатися без конфліктів, це просто означає, що код не конфліктував. Якщо спосіб доступу до застарілої функції був знятий або видалений, можливо, доведеться виправити після успішного злиття.

Це може бути використане і для інших систем управління версіями. Іноді мені доводилося об'єднувати певну групу команд svn у гілку (вишневий вибір) для однієї функції, виправити гілку для роботи з цією функцією, а потім об'єднати наступну групу SVN-коммітів, а не просто робити оптовий svn злиття.

У той час, як тут можна зробити вишню, і це дозволяє вносити конкретні комісії, це має деякі недоліки, які можуть ускладнити процес. Вибір вишні не відображатиме інформацію про вибране вами зобов'язання (ви можете додати його до повідомлення про виконання). Це ускладнює фактичне відстеження комісій в історії.

Крім того, це означає, що ви не збираєтеся ефективно відтворювати майстра на застарілу гілку - ви збираєтесь, можливо, неповні функції - і ці функції можуть бути відтворені поза порядком.

Ключова причина, по якій слід об'єднатись із історичних зобов’язань, щоб оволодіти несвіжою гілкою, - це вміти зберігати, давайте назвати це «майбутня історія» несвіжої гілки у стані, на який можна міркувати. Ви можете чітко побачити злиття історії з усталеною гілкою та виправлення для реінтеграції функціоналу. Функції додаються в тому ж порядку, як і вони були для освоєння. І коли ви закінчите, і, нарешті, зробіть злиття від начальника майстра на несвіжу гілку, ви знаєте, що все об'єднано, і ви не пропускаєте жодних комісій.


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

1

Крок 1. Дізнайтеся про код, проаналізуйте його архітектуру та зміни, які були внесені на обох гілках з часу останнього загального предка.

Крок 2. Якщо ця функція виявляється широко незалежною і торкається в основному різних областей коду, злиття, виправлення конфліктів, тестування, виправлення тощо. Це щасливий шлях, який ви дуже добре пройти. В іншому випадку перейдіть до кроку 3

Крок 3. Проаналізуйте зони конфлікту, детально зрозумійте функціональний вплив та причини. Тут легко можуть виникнути конфлікти в бізнес-вимогах. Обговоріть з BA, іншими розробниками, як це доречно. Отримайте відчуття складності, пов'язаної з вирішенням втручання.

Крок 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 - це потенційно проблема. Якщо за останній рік було багато змін, можливо, знадобляться значні зміни в старій функції. Якщо зробити це об'єднанням, потрібно в один раз внести серйозні зміни в код і сподіватися, що він працює, що не є хорошою практикою розробки. Плюс хто знає, яким був стан незавершеної функції? У вас може виникнути величезна безлад непрацюючого коду, і хто знає, чи це було через проблеми з оригіналом або зміни, які ви внесли?

Девіде, поки цей стандартний підхід працює, це добре, і ОП повинен спробувати це в першу чергу. Але, безумовно, існує ризик отримати занадто багато конфліктів злиття в описуваній ситуації, щоб вирішити їх таким чином «все або нічого».
Doc Brown

@ dan1111 Про те, що існують конфлікти злиття, це цілком нормально, і насправді пройти через них - це шлях. Оскільки галузь залишалася недоторканою протягом року, ви можете бути впевнені, що це не так важливо і не вплине на велику частину системи. Тож навіть незважаючи на те, що філія відстає на рік, ви можете отримати лише 2 конфлікти, що зливаються.
Енді

4
Припущення про те, що ця галузь є неважливим, є невиправданим. Це могло бути принциповою зміною дизайну, яка була відмовлена ​​і тепер знову збирається. Це може бути що завгодно. Ви маєте рацію, що це може бути простою справою, а конфліктів може бути мало або взагалі немає - у цьому випадку ваша відповідь буде правильною. Але це не єдина можливість.

@ dan1111 Якщо хтось рік не торкався місця функції в окремій гілці, він не збирається так сильно замислюватися над змінами системи. Це випливає з мого власного досвіду роботи із застарілими (6+ місяців) галузями.
Енді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.