Розв’язання конфліктів
Коли злиття, ребейз, cherry-pick чи revert зупиняється, банер повідомляє, що
саме зупинилося і між чим — «зливаємо feature/x у main», а не просто
«конфлікт».

Чому тут конфлікт
Чому тут конфлікт у шапці показує — окремо для кожного боку — коміти, які
чіпали цей файл відтоді, як гілки розійшлися. Це git log --merge, який git
має вже вічність і якого ніхто не знаходить.

Маркери кажуть, що саме зіткнулося. Це — хто змінив і навіщо, а зазвичай саме воно й вирішує, як розв’язати конфлікт. Порожньо там означає, що жоден бік не комітив зміну саме в цей шлях — зіткнення прийшло з перейменування або переміщення.
Три панелі
| Панель | Що це |
|---|---|
| Ліва | Наші — бік, на якому ви були, підписаний своїм комітом |
| Права | Їхні — бік, який приходить, підписаний своїм комітом |
| Середня | Результат: редагований, із номерами рядків, і саме він потрапляє в індекс |
Розмір усіх трьох панелей можна змінювати, а шапка результату несе два перемикачі вигляду:
| Перемикач | Що робить |
|---|---|
| Перенос | Переносить довгі рядки в панелях A і B замість прокручування. Панель результату тримає один ряд на рядок — від цього залежать її бічні маркери, — тож вона завжди прокручується |
| Пов’язано | Прокручує A, B і результат разом, по вертикалі й по горизонталі. Кількість рядків у них різна, тому вертикальна позиція підганяється пропорційно |
Перенос спочатку вимкнено, Пов’язано спочатку ввімкнено, і обидва запам’ятовують свій стан.
Як переміщатися
Відкривши файл, ви потрапляєте на його перший конфлікт, а не на початок файлу. Стрілки ⌃ / ⌄ у шапці результату — або Alt+↑ / Alt+↓ — проходять рештою конфліктів, прокручуючи всі три панелі до кожного з них.
Вибір
По рядку, по фрагменту або весь бік одразу — а ще ви можете взяти обидва боки фрагмента, коли правильна відповідь «залишити обидва». Навігатор конфлікт за конфліктом проводить вас по тому, що лишилося, тож випадково забути маркер ви не зможете.
Допомога ШІ
З увімкненим ШІ кнопка Розв’язати за допомогою ШІ пропонує варіант злиття в панелі результату. Вона ніколи нічого не застосовує самостійно: ви читаєте, редагуєте й індексуєте самі. Дивіться Можливості ШІ.
Файли проєктів Xcode
project.pbxproj конфліктує частіше за будь-який інший файл в iOS-репозиторії —
і майже ніколи тому, що хтось із кимось не погодився. Це один плоский словник
об'єктів із 24-значними шістнадцятковими ключами, тож додавання одного файлу
пише чотири записи: PBXBuildFile, PBXFileReference, рядок у children
групи-власника та рядок у фазі збірки цілі. Двоє, що додали по файлу, пишуть
вісім записів, які потрапляють в ті самі кілька рядків. Git бачить зіткнення;
розв'язувати нема чого.
Коли конфліктує саме project.pbxproj, редактор конфліктів читає всі три версії
як проєкти, а не як текст, і пропонує злити за структурою: зіставити
об'єкти за ідентифікатором, узяти кожне додавання з обох боків, об'єднати масиви
children і files та зупинитися на тому, що справді розійшлося. Смуга над
панелями каже, що додала кожна сторона і що — якщо щось — лишається вам.
Як і пропозиція ШІ, результат потрапляє в панель виводу й нічого не індексує. Ви читаєте його перед збереженням.

Чого він не робить
Він ніколи не вгадує налаштування, яке зрушили обидва. Якщо ви поставили
MARKETING_VERSION на 1.1, а вони — на 2.0, це рішення, і воно назване в
смузі — налаштування, ваше значення, їхнє — замість розв'язатися за вашою
спиною. Об'єкт, який не вдалося владнати, зберігає вашу версію точно, щоб
наполовину застосоване злиття ніколи не потрапило на диск.
Він відмовляється від файлу цілком, якщо хоч одна з трьох версій не
розбирається. project.pbxproj, який Xcode не відкриє, коштує дорожче за
ручне злиття, тож усе, що не можна прочитати впевнено, лишається звичайним
текстовим конфліктом, і про це сказано прямо.
Він не розпізнає два ідентифікатори, видані різним об'єктам. Рідкість, адже Xcode обирає їх випадково, — але якщо таке сталося, взяти будь-який бік означало б мовчки втратити чийсь файл, тож про це повідомляють, а не зливають.
Не merge=union
Ходяча рада для цього — *.pbxproj merge=union у
.gitattributes. Не варто. Union працює, доки єдині зміни —
незалежні додавання, а щойно двоє правлять те саме налаштування збірки, він
виводить обидва рядки й породжує файл, який Xcode відмовляється відкривати, —
саме тоді, коли ви найменше схильні уважно читати дифф. Структурне злиття дає ту
саму зручність без цієї відмови.
Lock-файли
Podfile.lock, Package.resolved, yarn.lock та їхня рідня фіксують граф
залежностей, який чийсь резолвер уже розв'язав. Половина одного розв'язку,
пришита до половини іншого, — це граф, якого ніхто не розв'язував: він може не
встановитися, а якщо встановиться, встановить те, чого не перевіряла жодна з
гілок.
Тож коли конфліктує саме lock-файл, смуга називає інструмент, якому він належить, пропонує тут-таки Лишити наше і Лишити їхнє, і дає команду, яка створить файл заново. Узяти один бік тут не компроміс — це і є весь метод, а правильним його робить перестворення.

Три панелі лишаються: вряди-годи ви таки хочете прочитати, що змінилося — впізнавану контрольну суму, очікувану версію. Саме від правки руками це й відмовляє.
Як уникати їх узагалі
Радар конфліктів підказує, які гілки конфліктуватимуть, ще до того як ви почнете їх зливати.
Дозволити git запам’ятовувати (rerere)
Поребейзите довгоживучу гілку — і зустрічаєте той самий конфлікт щоразу.
rerere — reuse recorded resolution, «повторне використання записаного
розв’язання» — це відповідь git: він запам’ятовує, як ви владнали конфлікт, і
відтворює цю відповідь наступного разу, коли з’явиться точнісінько такий самий.
Налаштування → Загальні → Запам’ятовувати розв’язання конфліктів. Це
записує rerere.enabled у ваш глобальний конфіг git, тож командний рядок
поводитиметься так само.
Коли git відповів за вас, розв’язувач так і каже, замість показувати порожній екран «немає маркерів конфлікту», і пропонує Забути це розв’язання — що прибирає запам’ятоване і повертає конфлікт назад, щоб ви могли владнати його інакше.
Дві речі, про які варто знати:
Відтворене розв’язання не потрапляє в індекс, якщо ви не ввімкнете Автоматично індексувати відтворене розв’язання. Лишіть це вимкненим: сенс паузи саме в тому, що запам’ятована відповідь може бути хибною для цього конкретного злиття, а індексування не глянувши — це те, як вона потрапляє в коміт.
Саме тому відтворений файл лишається в розділі Конфліктні файли: git записав вміст, але індекс усе ще тримає його як незлитий, і владнати це може тільки індексування. Зрушує його Проіндексувати як є в розв’язувачі або Позначити всі розв’язаними у списку.
rerere розуміє не кожен конфлікт. Конфлікти типу «додано/додано» та «видалено/змінено» не мають прообразу, тож завжди повертаються сирими. Лічильник у Налаштуваннях показує, скільки їх насправді збережено, а Забути все спорожнює сховище.
Дивіться також: Радар конфліктів · Злиття та ребейз