Пошук уроків, статей та іншого контенту
Зміните порядок локальних комітів і зрозумієте, як це впливає на залежності між змінами.
Git зберігає коміти як послідовність змін. Кожен коміт має батьківський коміт, тому зміна порядку означає не просте редагування списку, а повторне застосування комітів у новій послідовності.
Наприклад, початкова історія:
A -- B -- C -- D (HEAD)Потрібно поміняти місцями C і D:
A -- B -- D -- C (HEAD)Під час такої операції Git створює нові коміти. Тому хеші C і D зміняться, навіть якщо вміст файлів після всіх комітів залишиться таким самим.
Зміна порядку локальних комітів виконується за допомогою інтерактивного rebase:
git rebase -i HEAD~4HEAD~4 означає, що потрібно відкрити для редагування чотири останні коміти.
Після запуску команди Git відкриє файл приблизно такого вигляду:
pick 1a2b3c4 Add user model
pick 2b3c4d5 Add user service
pick 3c4d5e6 Add user tests
pick 4d5e6f7 Update README
# Rebase 0a1b2c3..4d5e6f7 onto 0a1b2c3
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# d, drop = remove commitКоміти розташовані від найстарішого до найновішого. Щоб змінити їхній порядок, потрібно змінити порядок рядків із pick.
Наприклад, щоб перемістити документацію перед тестами:
pick 1a2b3c4 Add user model
pick 2b3c4d5 Add user service
pick 4d5e6f7 Update README
pick 3c4d5e6 Add user testsПісля збереження та закриття редактора Git почне застосовувати коміти в новому порядку.
Уявімо, що локальна історія має такий вигляд:
* 8f4a1c2 Add API tests
* 6d2b9e1 Update README
* 3a7c5f0 Add user service
* 1b8d4e6 Add user modelКоміт Update README не залежить від коду, тому його можна перемістити перед тестами. Спочатку перевіримо історію:
git log --oneline --decorate -4Потім запустимо інтерактивний rebase для чотирьох останніх комітів:
git rebase -i HEAD~4У редакторі змінимо порядок:
pick 1b8d4e6 Add user model
pick 3a7c5f0 Add user service
pick 6d2b9e1 Update README
pick 8f4a1c2 Add API testsПісля завершення Git покаже нову історію:
git log --oneline --decorate -4Вона матиме ту саму логіку змін, але коміт документації буде розташований раніше за коміт тестів.
Повний типовий сценарій:
# Переконуємося, що робоче дерево чисте
git status
# Переглядаємо останні чотири коміти
git log --oneline -4
# Відкриваємо їх для зміни порядку
git rebase -i HEAD~4
# Перевіряємо результат
git log --oneline --decorate -4
# Перевіряємо стан робочого дерева
git status
# Запускаємо тести проєкту
npm testКоманда npm test у цьому прикладі є лише прикладом перевірки. У конкретному проєкті потрібно запускати команду, прийняту для його тестів.
Порядок комітів важливий, якщо пізніший коміт використовує зміни з попереднього.
Наприклад:
A: Add user model
B: Add user service that imports the model
C: Add tests for the serviceТут є природна залежність:
A → B → CЯкщо спробувати переставити B перед A, під час rebase можуть виникнути проблеми:
файл або функція з коміту A ще не існує;
імпорт не знаходиться;
тест або збірка не запускаються;
Git зупиняється через конфлікт;
коміт формально може застосуватися, але проміжний стан проєкту стане некоректним.
Тому перед зміною порядку потрібно перевірити, чи можна кожен коміт застосувати самостійно в новому місці.
Корисне правило:
незалежні зміни зазвичай можна переставляти без проблем;
зміни, що використовують файли, функції або структуру з попередніх комітів, мають залишатися після своїх залежностей.
Важливо перевіряти не лише фінальний стан, а й проміжні коміти. Фінальний код може працювати, навіть якщо один із проміжних комітів не був самодостатнім.
Якщо новий порядок створює конфлікт, Git призупинить rebase і покаже повідомлення про конфлікт.
Перевірити стан можна так:
git statusGit позначить конфліктні файли. Після ручного виправлення потрібно додати їх до індексу:
git add path/to/file.jsПотім продовжити rebase:
git rebase --continueЯкщо відкриється редактор повідомлення коміту, збережіть його або змініть за потреби.
Якщо стало зрозуміло, що вибраний порядок непридатний, операцію можна скасувати:
git rebase --abortЦе поверне гілку до стану, який був до початку rebase.
Якщо конкретний коміт більше не потрібен у цьому сценарії, його можна пропустити:
git rebase --skipПроте --skip варто використовувати лише тоді, коли ви точно розумієте, що зміни цього коміту вже є в іншому коміті або справді не потрібні.
Після зміни порядку перевірте:
Історію комітів:
git log --oneline --decorateВідмінності між поточним станом і потрібною базовою гілкою:
git diff main...HEADСтан робочого дерева:
git statusТести або інші перевірки проєкту.
Порівнювати коміти лише за їхніми хешами не потрібно: після rebase хеші змінюються. Важливіше перевірити порядок, вміст змін і працездатність проєкту.
Перед rebase переконайтеся, що немає незбережених змін:
git statusЯкщо робоче дерево не чисте, збережіть зміни окремим комітом або іншим безпечним для проєкту способом.
Зміна порядку комітів переписує історію. Тому її безпечно виконувати переважно для локальних комітів, які ще не використовують інші розробники.
Якщо коміти вже опубліковані у спільній гілці, після rebase локальна історія більше не збігатиметься з віддаленою. У такій ситуації не слід самостійно переписувати спільну історію.
Після rebase корисно перевірити, які коміти змінилися:
git log --oneline --left-right origin/feature...HEADУ списку інтерактивного rebase перший рядок — найстаріший коміт, а останній — найновіший.
pick oldest-commit
pick newest-commitНе потрібно читати цей список як звичайний список команд від нового до старого.
Якщо коміт використовує зміни іншого коміту, перестановка може спричинити конфлікт або зламати проміжний стан.
Спочатку переставляйте незалежні коміти. Для залежних змін перевіряйте, чи справді новий порядок має сенс.
Після конфлікту Git не повертається до звичайної роботи автоматично. Перевірте стан:
git statusДалі потрібно або виправити конфлікт і виконати:
git rebase --continueабо скасувати операцію:
git rebase --abortПісля зміни порядку комітів їхні хеші змінюються. Це нормальна поведінка rebase, а не ознака помилки.
Після переписування історії звичайний git push може бути відхилений. Не варто без узгодження виконувати примусове оновлення гілки, якою користуються інші розробники.
Для зміни порядку останніх комітів використовується git rebase -i.
У списку rebase потрібно переставити рядки з командами pick.
Коміти застосовуються від верхнього рядка до нижнього.
Залежний коміт має залишатися після коміту, який створює потрібні для нього зміни.
Якщо виник конфлікт, його можна виправити й продовжити rebase або скасувати операцію через git rebase --abort.
Rebase створює нові коміти з новими хешами, тому його слід обережно застосовувати до опублікованої історії.