Переписування історії за допомогою Git Rebase

Російська (Українська) translation by Sergey Zhuk

Основний робочий процес Git виглядає так: ви робите завдання в окремій гілці, потім по завершенню зливаєте її в основну гілку. Це робить git merge невід'ємним інструментом для поєднання гілок. Однак це не єдиний інструмент, який пропонує Git.

переписування
Злиття гілок об'єднанням.

Альтернативою сценарію, наведеному вище, може бути об'єднання гілок за допомогою команди git rebase . Замість злиття гілок у спеціальному коміті, зсув переміщає всю гілку із завданням на кінець master гілки так, як показано нижче.

переписування
Злиття гілок за допомогою git rebase

Це служить тій самій меті, як і git merge , пов'язуючи коммиты з різних гілок. Але є дві причини, через які ми могли б вибрати зсув замість злиття:

  • Зрушення призводить до лінійної історії проекту.
  • Це дає можливість очистити історію від локальних коммітів.

У цій статті ми будемо розглядати ці два загальні випадки використання git rebase. На жаль переваги git rebase призводять нас до компромісу. При неправильному використанні може бути однією з найбільш небезпечних операцій, які можна виконувати в Git-репозиторій. Таким чином, потрібно уважно розглянути небезпеки при зсуві гілок.

Необхідні умови

1. Зрушення для отримання лінійної історії

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

історії

Щоб зрушити гілку feature на гілку master, потрібно виконати такі команди:

Це перенесе гілку feature з їїпоточного положення на кінець гілки master.

rebase

Є два можливі варіанти, коли вам це може знадобитися. По-перше, ваше завдання зачіпає нові комміти з master, і тепер вони будуть доступні. По-друге, якщо завдання закрите, то тепер його можна швидко злити поверх гілки master. В обох випадках зсув призведе до лінійної історії, тоді як git merge призведе до необов'язкових комітів злиття.

Наприклад, розглянемо, що станеться, якщо ви використовуватимете злиття замість зсуву.

Це створить додатковий коміт злиття у гілці feature. Більше того це буде відбуватися щоразу, коли ви хотіли б увімкнути комміти, що знаходяться вище вашої гілки. Зрештою, історія вашого проекту буде завалена безглуздими коммітами злиття.

історії
Злиття коммітів, що знаходяться вище.

Це ж можна побачити при злитті та в іншому напрямку. Без використання зсуву, злиття гілки feature у гілку master так само вимагає коміту злиття. Хоча і здається значним коммітом (він представляє окрему закінчену завдання), у результаті історія буде сповнена відгалужень:

rebase
Злиття закінченої задачі за допомогою merge

Якщо ви зробите зсув перед злиттям, Git зможе накласти гілку master на кінець feature. Побачити лінійну історію прогресу проекту можна за допомогою команди git log-комміти з гілки feature акуратно згруповані поверх комітів з master. Це не обов'язково той випадок, коли гілки зливаються разом із коммітом злиття.

допомогою
Зсув перед злиттям

Вирішення конфліктів

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

історії

Команда git merge дозволяє вирішити всі конфлікти в кінці злиття, що є однією з основних цілей створення комміту злиття. Однак все це відбувається трохи інакше при використанні зсуву. Конфлікти вирішуються після кожного комітету. Таким чином, якщо git rebase знаходить конфлікт, процедура зсуву припиняється і виводиться повідомлення з попередженням:

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

rebase

Для вирішення конфлікту слід відкрити файл з конфліктами (у нашому прикладі це readme.txt), знайти рядки, що зачіпаються, і вручну внести необхідні зміни. Потім повідомити Git, щоб конфлікт вирішено, зафіксувавши зміни у файлі:

Зверніть увагу, що це той же спосіб, яким вирішуються конфлікти при використанні git merge . Але необхідно пам'ятати, що ми все ще знаходимося в середині процесу зсуву, і не слід забувати про коміти, що залишилися. Останнім кроком буде повідомити Git, що можна продовжити зсув, використовуючи опцію --continue.

Коміти, що залишилися, по одному будуть переміщені, якщо знову виникнуть конфлікти, то слід повторити процес їх вирішення.

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

2. Зсув для очищення від локальних комітів

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

Наприклад, припустимо ви закінчили роботу у гілці feature і готові до зливання її в master. Щоб розпочати сесію інтерактивного зсуву, необхідно виконати таку команду:

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

Якщо потрібно змінити порядок коммітів, то просто міняємо рядки подекуди. Якщо потрібно змінити повідомлення комміту, використовуємо команду reword . Якщо хочемо з'єднати два комміти в один - міняємо команду pick на squash. Це перенесе всі зміни з цього комміту до того, що перебуває вище. Наприклад, якщо ми з'єднаємо другий коміт у списку з верхнім, то гілка feature після збереження буде виглядати наступним чином:

переписування
Стискаємо другий коміт за допомогою інтерактивного зсуву.

Команда edit є особливо потужною. При досягненні певного комміту Git зупиняє процедуру зсуву, так само, як при виникненні конфлікту. Що дозволяє змінити вміст комміта за допомогою команди git commit --amend або додати нові комміти за допомогою стандартних команд git add / git commit . Будь-які нові комміти стануть частиною нової гілки.

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

3. Небезпеки зсуву

Тепер, коли у вас є уявлення про git rebase, можна поговорити про те, коли його не слід застосовувати. Усередині Git зсув насправді не переміщає комміти на нову гілку. Натомість він створює нові, які містять потрібні зміни. Маючи це на увазі, можна уявити процес зсуву наступним чином:

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

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

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

Ім'я це на увазі, вам ніколи не слід робити зсув коммітів, які були залиті в публічний репозиторій, доки ви не будете впевнені, що ніхто їх зараз у своїй роботі не використовує.

Висновок

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

Зверніть увагу, що зсув є обов'язковим доповненням до інструментарію.Git. Ви все ще можете зробити все, що вам потрібно з простою старою командою git commit. Вона набагато безпечніша, оскільки дозволяє уникнути можливості переписування спільної історії. Однак якщо ви розумієте ризики, з git rebase можна отримати набагато чистішу інтеграцію гілок порівняно зі злиттям коммітів.