Кога използвате git rebase вместо git merge?

Когато се препоръчва използването на git rebase срещу git merge ?

Трябва ли отново да се обединя след успешно рестартиране?

1330
29 апр. Coocoo4Cocoa се определя на 29 април. 2009-04-29 23:26 '09 в 23:26 ч. 2009-04-29 23:26
@ 15 отговора

Кратка версия

  • Обединяване приема всички промени в един клон и ги обединява в друг клон в едно фиксиране.
  • Rebase казва, че имам нужда от точка, където съм разклонена, за да се преместя към нова отправна точка.

Кога използвате един от тях?

сливам

  • Да предположим, че създавате клон, за да развиете една функция. Когато искате да върнете тези промени към главния, вероятно ще се нуждаете от сливане (не искате да запазите всички междинни ангажименти).

Rebase

  • Вторият сценарий би бил, ако започнете да правите някакво развитие, а след това друг предприемач е направил несвързана промяна. Вероятно ще искате да извадите и след това да ребаза, за да базирате промените си върху текущата версия от репо.
1018
29 апр. Отговор, даден от Rob Di Marco на 29 април. 2009-04-29 23:38 '09 в 23:38 2009-04-29 23:38

Това е просто, с ребаза казвате да използвате друг клон като нова база за вашата работа.

Ако имате, например, master клон и създавате клон, за да приложите нова функция, да речем, вие го наричате " cool-feature , тогава, разбира се, основният клон е основата за вашата нова функция.

Сега в даден момент искате да добавите нова функция, която реализирате в master клон. Можете просто да превключите към управление и сливане на клона с функцията cool-feature :

 $ git checkout master $ git merge cool-feature 

но това добавя нов фалшив ангажимент, ако искате да избегнете историята на спагети, можете да преместите :

border=0
 $ git checkout cool-feature $ git rebase master 

и след това я обединете в master :

 $ git checkout master $ git merge cool-feature 

Този път, тъй като темата на темата има същия главен ангажимент и се поема с новата функция, сливането просто ще бъде бързо напред.

316
05 февр. отговорът е даден от Aldo 'xoen' Giambelluca 05 Feb. 2012-02-05 09:28 '12 в 9:28 2012-02-05 09:28

За да допълвам собствения си отговор , споменат от TSamper ,

  • Преместването често е добра идея преди сливането, защото идеята е да интегрирате в клона си работата на клон B , с който ще се слеете.
    Но отново, преди да се слее, разрешавате всеки конфликт във вашия клон (т.е. „Повторно оформяне“, както е в „повтарям работата си в клона си, започвайки от последната точка на клон B )
    Ако е направено правилно, последващото сливане с вашия клон към клон B може да бъде бързо напред.

  • въздействието на сливането директно върху дестинацията B , което означава, че сливането ще бъде по-тривиално, в противен случай клон B може да бъде дълъг, за да се върне в стабилно състояние (времето, когато разрешите всички конфликти)


точката на сливане след преинсталиране?

В случая, когато опиша, преинсталирам B на моя клон, за да мога да възпроизвеждам работата си от по-късен етап от B , но оставайки в моя клон.
В този случай сливането все още е необходимо, за да може моето „преиграване“ да работи върху B

Друг сценарий ( описан например в Git Ready ) е да пренесете работата си директно в B чрез ребаза (която спестява всички ваши добри ангажименти или дори ви дава възможност да ги пренаредите чрез интерактивно пренасочване).
В този случай (където сте преинсталирали, ако сте в клон B) сте прав: не се изисква допълнително обединяване:

По подразбиране дърво Git, когато не сме се слили и не сме построили отново

2019

258
29 апр. отговорът е даден VonC 29 апр. 2009-04-29 23:44 '09 в 23:44 2009-04-29 23:44

Много от отговорите тук предполагат, че обединяването превръща всичките ви ангажименти в едно и затова предлага да използвате rebase, за да запазите вашите ангажименти. Това е неправилно. И лоша идея, ако вече сте направили вашите ангажименти .

Сливането не унищожава вашите ангажименти. Обединяване спестява история! (просто погледнете gitk) Rebase пренаписва историята, което е лошо нещо след като сте кликнали върху него.

Използвайте сливане - не ребаза, ако вече сте кликнали.

Тук Линус (авторски git) ще поеме . Наистина е добре да се чете. Или можете да прочетете моята собствена версия на същата идея по-долу.

Възстановяване на клонове на главния сървър:

  • съдържа погрешно схващане за това как са създадени коммити.
  • замърсява капитана с куп междинни ангажименти, които може да не са били добре тествани
  • наистина могат да въведат прекъсвания за изграждането на тези междинни ангажименти поради промените, които са направени, за да се справят помежду им, когато първоначалната нишка е била създадена и когато е била преинсталирана.
  • трудно да се намерят добри места в магистърската процедура.
  • Принуждава времевите отметки да се ангажират да не съвпадат с хронологичния им ред в дървото. По този начин ще видите, че коммитирането А предхожда фиксирането на В в master, но ангажимент B първоначално е написано от автора. (Какво?!)
  • Това създава повече конфликти, тъй като индивидуалните ангажименти в даден отрасъл могат да включват конфликти за сливане, които трябва да бъдат индивидуално разрешени (историята разказва за случилото се във всяка транзакция).
  • - пренаписване на историята. Ако клонът, който трябва да се преинсталира, е бил натиснат някъде (споделен с някой друг, различен от вас), тогава сте повредили всеки, който има този клон, откакто сте пренаписали историята.

За разлика от това, сливането на темата на темата в капитана:

  • запазва историята на създаването на нишките, включително всички сливания от водещата към нишката на темата, за да я запази актуална. Наистина получавате точна представа за кой код е работил разработчикът, когато са построили.
  • master е основно клон за сливане, и всеки от тези обединяващи се ангажименти обикновено е „добри моменти” в историята, които са безопасни за проверка, защото където клонът на темата е готов за интеграция.
  • всички отделни фиксирания на темата на темата се запазват, включително факта, че те са в темата за темите, така че подчертаването на тези промени е естествено и можете да го разположите, когато е необходимо.
  • конфликтите за сливане трябва да се разрешават само веднъж (в точката на сливане), следователно промените в междинния запис, направени в темите на темата, не трябва да се разрешават самостоятелно.
  • може да се направи няколко пъти гладко. Ако интегрирате тематичен клон за периодично обучение, хората могат да продължат да създават клон на тема и той може да продължи да се обединява независимо.
161
04 февр. Отговорът е даден от Андрю Арнот на 04 февруари. 2014-02-04 01:17 '14 в 1:17 2014-02-04 01:17

TL; DR

Ако имате съмнения, използвайте сливане.

Кратък отговор

Единствените разлики между ребаза и сливане са:

  • Получената дървовидна структура на историята (като правило, забележима само при гледане на фиксиращ график) се различава (единият има клони, а другият няма).
  • Обикновено сливането създава допълнителен ангажимент (например възел в дървото).
  • Сливането и повторното инсталиране ще се справят по различен начин с конфликтите. Rebase ще представлява конфликтите, които възникват в момента, в който сливането ги представя наведнъж.

Така че краткият отговор е да изберете ребаз или сливане въз основа на това, което искате да изглежда вашата история.

Дълъг отговор

Има няколко фактора, които трябва да се вземат предвид при избора на транзакция за използване.

Дали филиалът ви прави промени с други разработчици извън екипа ви (например, с отворен код, публичен)?

Ако да, не преинсталирайте. Rebase разрушава клона и тези разработчици ще имат счупени / непоследователни хранилища, ако не използват git pull --rebase . Това е добър начин бързо да разстроите другите разработчици.

Колко квалифициран е вашият екип за развитие?

Rebase е разрушителна операция. Това означава, че ако не го приложите правилно, може да загубите перфектната работа и / или да прекъснете последователността на други хранилища на разработчици.

Работих по екипи, в които разработчиците дойдоха от времето, когато компаниите можеха да си позволят специален персонал да се разделят и сливат. Тези разработчици знаят малко за Git и не искат да знаят много. В тези команди не бих рискувал да препоръчвам рестартиране по някаква причина.

Самата нишка ли е полезна информация?

Някои команди използват модел за всеки клон, където всеки клон е функция (или фикс, или спомагателна функция и т.н.). В този модел клонът помага да се идентифицират съвкупности от свързани ангажименти. Например, можете бързо да върнете функция, връщайки сливането на този клон (честно, това е рядка операция). Или сравнете функцията, като сравните два клона (по-общо). Rebase би унищожило клона и щеше да е трудно.

Работих и с екипи, които използваха модел за всеки разработчик (всички бяхме там). В този случай самият клон не предава никаква допълнителна информация (коммитирането вече има автор). Няма да има вреда при рестартиране.

Може би искате да върнете сливането по някаква причина?

Възвръщаемостта (както в случая на анулиране) на ребида е значително сложна и / или невъзможна (ако ребазата има конфликти) в сравнение с връщането на сливането. Ако смятате, че има шанс, че искате да се върнете, използвайте сливането.

Работите ли в екип? Ако е така, съгласен ли си да приемеш всичко или нищо на тази тема?

Операциите за рестартиране трябва да бъдат изтеглени, като се използва подходящото git pull --rebase . Ако работите самостоятелно, можете да си спомните какво трябва да използвате в подходящото време. Ако работите в екип, ще бъде много трудно да се помири. Ето защо повечето работни потоци на отстъпките препоръчват да се използва rebase за всички сливания (и git pull --rebase за всички кликвания).

Общи митове

Комбинирайте историята на унищожаването

Ако приемем, че имате следното сливане:

  B -- C / \ A--------D 

Някои хора ще посочат, че сливането "унищожава" историята на коммитирането, защото ако трябва да погледнете в дневника само на основния клон (AD), ще пропуснете важните съобщения за корекция, съдържащи се в B и C.

Ако случаят беше такъв, нямаше да има такива въпроси . По принцип ще видите B и C, освен ако изрично не ги помолите да не виждат (използвайки първи родител). Много е лесно да се опитате сами.

Rebase позволява по-безопасно / по-просто сливане

И двата подхода се сливат по различен начин, но не е ясно, че той винаги е по-добър от другия и може да зависи от работния процес на разработчика. Например, ако разработчик има тенденция да прави редовни (например, те могат да изпълняват два пъти на ден, когато се движат от работа към дома), тогава може да има много ангажименти за даден клон. Много от тези ангажименти може да не приличат на крайния продукт (склонен съм да реорганизирам подхода си веднъж или два пъти за всяка функция). Ако някой друг е работил по подобна област от кода и са се опитали да променят промените ми, това може да бъде доста досадна операция.

Отново по-студено / по-секси / по-професионално

Ако ви харесва псевдоним rm до rm -rf да "спестите време", може да се наложи да преинсталирате.

Моите два цента

Винаги мисля, че някой ден ще срещна сценарий, в който Git rebase е страхотен инструмент, който решава проблем. Както ми се струва, аз се сблъсках със скрипт, където Git reflog е чудесен инструмент, който решава проблема ми. Работя с Git вече пет години. Това не се случи.

Безсмислените истории никога не са били проблем за мен. Никога не съм чел историята на извършеното като вълнуващ роман. В повечето случаи имам нужда от история, въпреки това ще използвам w20> wame или Git bisect. В този случай, присъствието на сливането е наистина полезно за мен, защото ако сливането въведе проблем, който има значима информация за мен.

Актуализация (4/2017)

Чувствам се задължен да спомена, че аз лично се отказах от използването на ребаза, въпреки че общите ми съвети все още си струва. Наскоро много си взаимодействах с проекта „ Материал 2 “. Те използват rebase, за да запазят много чиста история на корекциите. Това ми направи много лесно да видя, че този дефект е фиксиран и дали този ангажимент е включен в освобождаването. Той служи като отличен пример за правилното използване на пренасочването на повиквания.

143
13 апр. отговор, даден Пейс 13 април 2016-04-13 05:16 '16 в 17:16 2016-04-13 05:16

Обединяване на средства: създайте нов нов ангажимент, който обединява промените ми с моята цел.

Rebase означава: създайте цяла поредица от ангажименти, като използвате текущия ми набор от ангажименти като съвети. С други думи, разберете как ще изглеждат моите промени, ако започна да ги правя от момента, в който се възстановя. Следователно, след преинсталиране, може да се наложи да проверите отново промените си и по време на преинсталирането, може да имате няколко конфликта.

Като се има предвид това, защо трябва да преинсталирате? Само за историята на развитието е ясно. Да предположим, че работите върху функция X и когато приключите, обединявате промените си. Сега получателят ще има един ангажимент, който ще каже нещо като низ "Добавена функция X". Сега, вместо да се сливате, ако преинсталирате и след това слеете, историята на развитието на дестинацията ще съдържа всички индивидуални ангажименти в една логическа прогресия. Това значително улеснява анализа на промените. Представете си как можете да го намерите, за да видите историята на развитието, ако 50 разработчици през цялото време съчетават различни функции.

Въпреки това, ако вече сте кликнали върху клона, върху който работите, не трябва да го възстановявате, а да го обединявате. За клонове, които не са били избутани нагоре по веригата, преинсталирайте, тествайте и слейте.

Друг път, когато искате да преинсталирате, трябва да се отървете от ангажиментите от вашия клон преди да щракнете нагоре. Например: Команди, които въвеждат някакъв код за отстраняване на грешки на ранен етап, докато други записват, че изчистват този код. Единственият начин да направите това е да изпълните интерактивно рестартиране: git rebase -i <branch/commit/tag>

АКТУАЛИЗАЦИЯ: Също така искате да използвате rebase, когато използвате Git, за да взаимодействате със система за контрол на версиите, която не поддържа нелинейна история (например разрушителна операция). Когато се използва мостът git -svn, много е важно промените, които сте обединили отново в субверсия, да представляват последователен списък от промени през последните промени в линията. Това може да се направи само по два начина: (1) Ръчно пресъздаване на промени и (2) Използване на командата rebase, която се изпълнява много по-бързо.

UPDATE2: Друг начин да мислите за пренасочването е, че ви позволява да съвпадате с вида на вашия стил на развитие със стила, възприет в хранилището, към което се ангажирате. Нека се каже, че обичате да изпълнявате малки малки парченца. Имате едно поправка, за отстраняване на печатна грешка, едно поправка, за да се отървете от неизползвания код и т.н. Когато завършите това, което трябва да направите, имате дълга поредица от ангажименти. Позволете ми да кажа, че хранилището, което правите, насърчава големите ангажименти, така че за работата, която правите, ще очаквате едно или две ангажименти. Как да вземете линията си за коммитиране и да я компресирате до очакваното? Вие ще използвате интерактивна обработка и скуош, за да направите малките си ангажименти да се превърнат в по-малки парчета. Същото е вярно, ако е било необходимо обратното - ако вашият стил е няколко големи ангажирания, но репо изисква дълги редове от малки ангажименти. Вие също ще използвате rebase за това. Ако сте се обединили вместо това, сега сте преместили стила си на поемане в основното хранилище. Ако има много разработчици, можете да си представите колко трудно би било да се следва една история с няколко различни стила на фиксация след известно време.

UPDATE3: Does one still need to merge after a successful rebase? Да, да. Причината е, че ребидът основно включва "превключване". Както казах по-горе, тези ангажименти се изчисляват, но ако имате 14 корекции от точката на разклонението, тогава, при условие, че вашето транспониране не работи, ще бъдете 14 поемат напред (от момента, в който сте нулирали) след ребаза е направено. Преди да преинсталирате, имате клон. След това ще имате клон със същата дължина. Все още трябва да се обедините преди да публикувате промените си. С други думи, ребаза толкова пъти, колкото искате (отново, само ако не сте натиснали промените нагоре). Обединяване само след рестартиране.

66
05 февр. отговорът е даден от Carl 05 Feb. 2012-02-05 09:47 '12 в 9:47 2012-02-05 09:47

преди сливане / ребаза:

 A <- B <- C [master] ^ \ D <- E [branch] 

след git merge master :

 A <- B <- C ^ ^ \ \ D <- E <- F 

след git rebase master :

 A <- B <- C <- D' <- E'