← назад к разделу

Ветки — причина, по которой 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

Порядок действий без паники:

  1. git status покажет конфликтующие файлы.
  2. Открыть файл, найти маркеры <<<<<<</>>>>>>>, решить по смыслу: оставить одну версию, другую или написать объединённую. Маркеры удалить.
  3. git add файл — пометить конфликт решённым.
  4. 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.