Merge, rebase и разбор конфликтов
Когда что применять и как читать конфликт, а не гадать.
Две стратегии
Вы работали в ветке, а main тем временем ушёл вперёд. Подтянуть изменения можно двумя способами.
Merge создаёт коммит слияния. История сохраняется как была, включая параллельность работы.
Rebase переносит ваши коммиты так, будто вы начали от текущего main. История становится линейной.
git switch feature
git merge main # merge-коммит
git rebase main # перенести свои коммиты поверх main
Какой выбрать
Правило, которое почти всегда работает:
- rebase — для своей ветки, которую никто больше не забирал;
- merge — для всего, что уже опубликовано.
Причина: 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, он не потерян.