Пренаписване на история с Git Rebase

Руски (пуски) превод от Сергей Жук (можете да видите и оригиналната статия на английски)

Основният работен поток на Git изглежда така: правите задача в отделен клон, след което го обединявате в основния клон, когато приключите. Това прави git merge основен инструмент за обединяване на клонове. Това обаче не е единственият инструмент, който Git предлага.

история
Обединяване на клонове чрез сливане.

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

пренаписване
Обединяване на клонове с git rebase

Това служи на същата цел като git merge, свързване на ангажименти от различни клонове. Но има две причини, поради които можем да изберем да сменим вместо сливане:

  • Резултати от изместване в линейна история на проекта.
  • Това ни дава възможност да изчистим историята на местните ангажименти.

В тази статия ще разгледаме тези два често използвани случая за git rebase. За съжаление предимствата на git rebase ни водят до компромис. Ако се използва неправилно, това може да бъде една от най-опасните операции, които можете да извършите в хранилището на Git. По този начин трябва внимателно да прецените опасностите при преместване на клонове.

Необходимите условия

1. Shift, за да получите линейна история

Първият случай на употреба, който ще разгледаме, включва различна история на проекта. Помислете за хранилище, където master е продължил, докато работите по проблем в друг клон.

пренаписване

За да натиснете разклонението на характеристиките към главния клон, трябва да изпълните следните команди:

Това ще премести разклонението на характеристиките от текущата му позиция в края на главния клон. .

rebase

Има две възможни опции кога може да ви потрябва. Първо, вашата задача засяга нови ангажименти от капитана и сега те ще бъдат достъпни за нея. На второ място, ако задачата е затворена, тогава тя може бързо да бъде обединена в главния клон. И в двата случая смяна ще доведе до линейна история, докато git merge ще доведе до незадължителни коммити за сливане.

Например, помислете какво се случва, ако използвате сливане вместо shift.

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

история
Обединяване на ангажименти по-горе.

Същото може да се види и при сливане в другата посока. Без да се използва смяна, обединяването на клон на характеристика в главния клон също изисква ангажиране за сливане. Въпреки че това изглежда като смислен ангажимент (представлява отделна, завършена задача), крайният резултат е история, пълна с вилици:

история
Обединяване на завършена задача с помощта на сливане

Ако направите смяна преди сливането, Git може да изтласка главния клон до края на функцията. Можете да видите линейната история на напредъка на проекта, като използвате командата git log - комитите от разклонението на характеристиките са спретнато групирани върху комитите от master. Това не е задължително случаят, когато клонове се обединяват с коммита на сливане.

история
Shift преди сливане

Разрешаване на конфликти

Когато стартирате git rebase, Git взема всеки ангажимент от клона и ги пребазира един по един на ново място. Ако някой от тези фиксира промени същите редове като ангажиментите нагоре по веригата, това ще доведе до конфликти.

rebase

Командата git merge ви позволява да разрешите всички конфликти в края на обединяването, което е една от основните цели на създаването на ангажимент за сливане. Всичко това обаче се случва малко по-различно, когато се използва смяна. Конфликтите се разрешават след всеки ангажимент. По този начин, ако git rebase открие конфликт, процедурата за пребазиране се спира и се показва предупредително съобщение:

Визуално така изглежда историята на проекта, когато git rebase открие конфликт:

история

За да разрешите конфликта, отворете файла с конфликти (в нашия пример readme.txt), намерете засегнатите редове и направете ръчно необходимите промени. След това кажете на Git да разреши конфликта, като извърши промените във файла:

Имайте предвид, че това е по същия начин, по който конфликтите се разрешават с помощта на git merge. Но имайте предвид, че все още сме в средата на процеса на смяна и не забравяйте за останалите ангажименти. Последната стъпка е да кажете на Git да продължи с смяната, използвайки опцията --continue .

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

Ако не искате да разрешите конфликта, можете да използвате флаговете --skip или --abort. Последното е особено полезно, ако не знаете какво се случва и просто искате да се върнете безопасно.

2. Shift за почистване на локални фиксирания

Досега използвахме само git rebase за преместване на клонове, но това е много по-мощен инструмент. Чрез посочване на флага -i може да се стартира интерактивна сесия за смяна. Интерактивното преместване ви позволява да дефинирате как точно ще се движи всеки ангажимент. Това прави възможно изчистването на историята на дадена задача, преди да я споделите с други разработчици.

Да приемем например, че сте приключили работата в разклонението на характеристиките и сте готови да го обедините в master. За да стартирате интерактивна сесия за смяна, изпълнете следната команда:

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

Ако трябва да промените реда на фиксиране, просто разменете редовете на места. Ако трябва да промените съобщението за фиксиране, използвайте командата reword. Ако искаме да комбинираме две фиксирания в една, променяме командата за избор на squash. Това ще прехвърли всички промени от този ангажимент в горната. Например, ако обединим втория ангажимент в списъка с горния, тогава клонът на характеристиките след запазване ще изглежда така:

история
Свиване на втория ангажимент с интерактивен тласък.

Командата за редактиране е особено мощна. Когато се постигне определен ангажимент, Git спира процедурата за смяна, точно както когато възникне конфликт. Което прави възможно промяната на съдържанието на фиксацията с помощта на командата git commit --amend или добавяне на нови фиксирания с помощта на стандартните команди git add/git commit. Всички нови ангажименти ще станат част от новия клон.

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

3. Опасности от срязване

Сега, когато имате идея за git rebase, можете да говорите за това кога не трябва да се използва. Вътрешно в Git, натискането всъщност не премества ангажименти в новия клон. Вместо това създава нови, които съдържат промените, които искате. Имайки предвид това, можем да представим процеса на смяна по следния начин:

rebase

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

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

Имайте предвид това, че никога не трябва да премествате ангажименти, които са били вкарани в публичното хранилище, докато не сте сигурни, че никой не ги използва в работата си в момента.

Заключение

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

Имайте предвид, че превключването е задължително допълнение към инструмента ви за Git. Все още можете да правите каквото искате с простата стара команда за git commit. Той е много по-безопасен, защото избягва възможността за пренаписване на цялостната история. Ако обаче разбирате рисковете, можете да получите много по-чиста интеграция на клонове с git rebase в сравнение с обединяването на ангажименти.