Ветки — причина, по которой Git победил: они дешёвые и мгновенные. Ветка позволяет работать над задачей в изоляции — сколько угодно коммитить и экспериментировать, не трогая рабочую версию, — а потом одним действием влить результат обратно. Весь командный процесс (задачи, ревью, релизы) построен на этом механизме.
Ветка — это указатель
Ментальная модель: история — цепочка коммитов, а ветка — передвижная закладка, указывающая на один из них. Новый коммит в ветке просто сдвигает закладку вперёд. Создать ветку = поставить ещё одну закладку — операция мгновенная, ничего не копируется.
git branch # список веток, * — текущая
git switch -c fix-cart-total # создать ветку и переключиться на неё
git switch main # вернуться на main
Специальная закладка HEAD отмечает, где вы сейчас. Переключение ветки меняет файлы в рабочей директории на снимок той ветки — поэтому Git попросит дочистить незакоммиченное перед переключением (или спрячьте его в git stash — карман для незавершённого).
Рабочий ритм: под каждую задачу — своя ветка от свежего main (fix-cart-total, feature-export-csv), в ней коммиты, после вливания ветка удаляется. Ветки — расходный материал, а не долгожители.
Слияние: fast-forward и merge-коммит
Влить ветку в main:
git switch main
git merge fix-cart-total
Возможны два сценария:
- Fast-forward. Пока вы работали, main не двигался. Тогда сливать нечего — Git просто передвигает закладку main вперёд на ваши коммиты. История остаётся прямой линией.
- Merge-коммит. Main успел уйти вперёд (коллеги вливали своё). Git создаёт специальный коммит с двумя родителями, объединяющий обе линии. История показывает ромб: разошлись — сошлись.
Оба исхода нормальны. Какой предпочитать и почему некоторые команды запрещают merge-коммиты — вопрос модели ветвления и rebase; пока достаточно понимать, что происходит.
Конфликты: не авария, а вопрос
Конфликт возникает, когда обе ветки изменили одни и те же строки по-разному. Git не угадывает, чья правка правильная, — он останавливается и спрашивает вас:
<<<<<<< HEAD
цена = сумма * 0.9; // ваша версия (текущая ветка)
=======
цена = сумма * 0.85; // версия вливаемой ветки
>>>>>>> fix-discount
Порядок действий без паники:
git statusпокажет конфликтующие файлы.- Открыть файл, найти маркеры
<<<<<<</>>>>>>>, решить по смыслу: оставить одну версию, другую или написать объединённую. Маркеры удалить. git add файл— пометить конфликт решённым.git commit— завершить слияние. Передумали —git merge --abortвернёт всё как было.
Два взрослых правила. Конфликт решается по смыслу задачи, а не механически: «оставить свою» — не стратегия, вы можете затереть чужой багфикс; сомневаетесь — спросите автора второй правки (blame покажет кого). И профилактика лучше лечения: короткие ветки и регулярное подтягивание main в свою ветку делают конфликты маленькими и редкими.
Где это помогает бэкендеру
Ветки — это ещё и навигация. Посмотреть, как выглядел код в проде — git switch v2.3.1 (по тегу релиза); проверить чужую работу до ревью — переключиться на её ветку; срочный фикс во время большой задачи — stash, ветка от main, фикс, обратно. Умение свободно ходить по веткам превращает Git из «сдать код» в машину времени проекта.
Коротко
- Ветка — передвижной указатель на коммит; создание мгновенно. Задача = ветка, влили = удалили.
- HEAD — где вы; переключение меняет файлы; незакоммиченное — в stash.
- Merge: fast-forward (main не двигался — прямая линия) или merge-коммит с двумя родителями (ромб).
- Конфликт — вопрос, а не авария: маркеры в файле → решить по смыслу → add → commit;
--abortотменяет. - Профилактика конфликтов: короткие ветки, регулярно подтягивать main.
Что почитать дальше
- Удалённые репозитории — push, pull и работа с сервером.
- Rebase и cherry-pick — альтернатива merge и перенос отдельных коммитов.
- Модели ветвления — как команды организуют ветки: git flow, GitHub flow, trunk-based.