Пошук уроків, статей та іншого контенту
Навчитеся знаходити конфліктні файли, вручну обирати потрібні зміни та завершувати або скасовувати merge.
Конфлікт виникає, коли Git не може автоматично об’єднати зміни з двох гілок. Найчастіше це трапляється, якщо:
у двох гілках змінено одні й ті самі рядки;
в одній гілці файл змінено, а в іншій — видалено;
два коміти перейменували або перемістили файли несумісним способом.
Наприклад, поточна гілка main і гілка feature містять різні зміни в одному рядку:
main: const port = 3000;
feature: const port = 8080;Git не може самостійно визначити, яке значення правильне, тому зупиняє merge і передає вибір розробнику.
Спочатку потрібно перейти в гілку, у яку додаються зміни:
git switch main
git merge featureЯкщо виник конфлікт, Git виведе повідомлення на кшталт:
CONFLICT (content): Merge conflict in config.js
Automatic merge failed; fix conflicts and then commit the result.Це означає, що merge ще не завершено. Робоче дерево перебуває у спеціальному стані: Git очікує, що ви розв’яжете конфлікти.
Використайте git status:
git statusПриклад результату:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
both modified: config.jsРядок both modified означає, що файл змінено в обох гілках.
Стан файлу також можна побачити у скороченому форматі:
git status --shortМожливі позначення:
UU — файл змінено в обох гілках;
AA — файл додано в обох гілках;
DD — файл видалено в обох гілках;
DU або UD — файл видалено в одній гілці та змінено в іншій.
Щоб переглянути лише файли з конфліктами, можна виконати:
git diff --name-only --diff-filter=UВідкрийте конфліктний файл у редакторі. Git вставляє в нього спеціальні маркери:
const config = {
<<<<<<< HEAD
port: 3000,
=======
port: 8080,
>>>>>>> feature
};Маркери мають таке значення:
<<<<<<< HEAD — початок змін із поточної гілки;
======= — роздільник між двома варіантами;
>>>>>>> feature — кінець змін із гілки, яку приєднують.
У цьому прикладі:
значення 3000 походить із поточної гілки main;
значення 8080 походить із гілки feature.
Маркери не є частиною правильного коду. Після розв’язання їх потрібно видалити.
Потрібно вирішити, який варіант залишити:
const config = {
port: 8080
};Або можна об’єднати зміни, якщо це має сенс:
const config = {
port: process.env.PORT || 8080
};Після редагування перевірте файл:
git diff -- config.jsПереконайтеся, що в ньому немає маркерів:
<<<<<<<
=======
>>>>>>>Потім додайте розв’язаний файл до індексу:
git add config.jsКоманда git add у цьому випадку не просто готує звичайні зміни до коміту. Вона повідомляє Git, що конфлікт у файлі розв’язано.
Перевірте стан:
git statusФайл більше не має відображатися в секції Unmerged paths.
Нижче наведено типовий сценарій від початку до завершення merge:
# Перехід у гілку, яка прийматиме зміни
git switch main
# Спроба об'єднати гілку feature
git merge feature
# Перегляд файлів із конфліктами
git status
git diff --name-only --diff-filter=U
# Після ручного редагування конфліктних файлів
git add src/config.js
# Перевірка, що конфліктів більше немає
git status
git diff --check
# Завершення merge
git commit -m "Merge branch 'feature' into main"Якщо конфліктних файлів кілька, потрібно відредагувати кожен із них і виконати git add для кожного:
git add src/config.js src/routes.js package.jsonПісля цього merge можна завершити.
Після завершення merge перевірте історію:
git log --oneline --graph --decorate -5Також варто запустити перевірки проєкту:
npm testКонкретна команда залежить від проєкту. Важливо перевірити не лише відсутність маркерів, а й те, що об’єднаний код працює правильно.
Команда git diff --check допомагає знайти деякі проблеми у змінах, зокрема зайві пробіли:
git diff --checkІноді конфліктний файл потрібно повністю залишити в одному з варіантів.
Під час merge поточна гілка називається ours. Якщо ви перебуваєте в main, то ours — це версія з main:
git restore --ours -- config.js
git add config.jsГілка, яку додають через git merge, називається theirs. У прикладі з git merge feature це версія з feature:
git restore --theirs -- config.js
git add config.jsПісля цього перевірте вміст файлу. Не слід використовувати ці команди без перевірки: вони замінюють увесь файл одним із варіантів і можуть видалити потрібні зміни.
Якщо в Git використовується старіша форма команд, можна зустріти такі варіанти:
git checkout --ours -- config.js
git checkout --theirs -- config.jsКоманда git restore є зрозумілішою для операцій із файлами, тому в нових сценаріях краще використовувати її.
Після того як усі конфлікти розв’язано та файли додано через git add, merge можна завершити одним зі способів.
git commitgit commitGit підготує повідомлення merge-коміту. Його можна залишити або відредагувати.
Також можна одразу вказати повідомлення:
git commit -m "Merge branch 'feature' into main"git merge --continuegit merge --continueЦя команда перевіряє, чи всі конфлікти розв’язані, і продовжує перервану операцію merge. У типовому випадку Git відкриє редактор для підтвердження повідомлення коміту.
Обидва підходи завершують один і той самий процес. Перед завершенням переконайтеся, що всі конфліктні файли додано до індексу.
Якщо зміни складно об’єднати або ви зрозуміли, що почали merge не тієї гілки, його можна скасувати:
git merge --abortКоманда повертає робоче дерево та індекс до стану, який був до початку merge.
Після скасування перевірте стан:
git statusЯкщо Git не може виконати git merge --abort, це може бути пов’язано з локальними змінами, які існували ще до початку merge. У такому разі не видаляйте файли навмання. Спочатку збережіть потрібні зміни окремим комітом або іншим безпечним способом, після чого повторіть операцію.
Під час незавершеного merge команда git status явно повідомляє про наявність unmerged paths.
Звичайна змінена, але не додана до індексу:
M config.jsФайл, який уже підготовлено до коміту:
M config.jsФайл із нерозв’язаним конфліктом:
UU config.jsНе намагайтеся завершити merge, якщо вивід містить UU, AA, DD, DU або UD.
Короткий алгоритм розв’язання конфліктів:
Перевірити стан репозиторію через git status.
Знайти всі конфліктні файли.
Відкрити кожен файл і знайти маркери конфлікту.
Вибрати потрібні зміни або об’єднати їх вручну.
Видалити всі маркери <<<<<<<, =======, >>>>>>>.
Перевірити код і виконати тести.
Додати розв’язані файли через git add.
Перевірити, що нерозв’язаних файлів не залишилося.
Завершити merge через git commit або git merge --continue.
Якщо merge потрібно скасувати, виконати git merge --abort.
Іноді після розв’язання одного конфлікту розробник одразу виконує git commit. Завжди перевіряйте весь список через:
git statusКод із маркерами може бути синтаксично некоректним. Перед комітом перевірте пошуком:
grep -R -n -E '<<<<<<<|=======|>>>>>>>' .У деяких операційних системах або середовищах зручніше виконати пошук у редакторі.
ours і theirsours — це поточна гілка, у якій запущено git merge.
theirs — це гілка, яку приєднують.
Наприклад, після:
git switch main
git merge featureours — main;
theirs — feature.
git add до редагуванняgit add позначає файл як розв’язаний, але не перевіряє, чи правильно ви обрали зміни. Спочатку відредагуйте файл, перевірте його вміст і лише потім додавайте.
--ours або --theirsПовна заміна файлу може непомітно видалити корисні зміни. Використовуйте ці параметри лише тоді, коли справді потрібно залишити один із варіантів цілком.
Поки попередній merge не завершено або не скасовано, Git може блокувати інші операції. Спочатку виконайте:
git commitабо:
git merge --abortКонфлікт виникає, коли Git не може автоматично об’єднати зміни.
git status показує конфліктні файли та поточний стан merge.
Конфліктні ділянки позначені маркерами <<<<<<<, =======, >>>>>>>.
Після ручного редагування файл потрібно додати через git add.
Merge завершується командами git commit або git merge --continue.
Версію поточної гілки можна вибрати через git restore --ours, а версію гілки, яку приєднують, — через git restore --theirs.
Щоб повністю скасувати незавершений merge, використовуйте git merge --abort.
Перед комітом слід перевірити всі конфліктні файли та запустити тести.