Merge, rebase и разбор конфликтов

Когда что применять и как читать конфликт, а не гадать.

Две стратегии

Вы работали в ветке, а main тем временем ушёл вперёд. Подтянуть изменения можно двумя способами.

Merge создаёт коммит слияния. История сохраняется как была, включая параллельность работы.

Rebase переносит ваши коммиты так, будто вы начали от текущего main. История становится линейной.

git switch feature
git merge main      # merge-коммит
git rebase main     # перенести свои коммиты поверх main

Какой выбрать

Правило, которое почти всегда работает:

Причина: rebase создаёт новые коммиты с новыми хешами. Старые остаются у того, кто успел спуллить, и при следующем pull он получит и старые, и новые — история задвоится.

Отсюда правило: не делать rebase того, что уже видели другие.

Конфликт

Конфликт возникает, когда обе стороны изменили одни и те же строки. Git размечает файл:

<<<<<<< HEAD
timeout: 30
=======
timeout: 60
>>>>>>> feature/increase-timeout

Между <<<<<<< и ======= — версия той стороны, на которую вы накладываете. Между ======= и >>>>>>> — версия той, которую накладываете.

Важный нюанс: при rebase стороны меняются местами относительно интуиции. HEAD при rebase — это ветка, на которую переносят (main), а не ваша. Проверять, что где, надёжнее так:

git status           # покажет, в какой операции вы находитесь
git log --merge      # коммиты, которые привели к конфликту

Разрешение

Разрешить — значит привести файл к тому виду, каким он должен быть, и убрать все маркеры.

# отредактировали файл
git add file
git rebase --continue    # или git merge --continue

Если запутались, всегда можно отступить:

git rebase --abort
git merge --abort

Это возвращает репозиторий ровно в состояние до начала операции.

Если всё-таки сломали

git reflog

reflog хранит все положения HEAD за последние недели, включая те, что «потерялись» после rebase или reset. Находите нужную строку и:

git reset --hard HEAD@{5}

Пока коммит существует в reflog, он не потерян.