Git ветки: создание, слияние и конфликты

Что такое ветка в Git

Ветка в Git — это просто текстовый файл в .git/refs/heads/, содержащий хеш одного коммита. Всё. Никакого копирования файлов, никаких дубликатов — только указатель.

Когда ты делаешь git commit, Git создаёт объект коммита и перезаписывает файл текущей ветки новым хешем. Создание ветки занимает микросекунды и не зависит от размера репозитория.

.git/refs/heads/main     → "a1b2c3d4e5f6..."
.git/refs/heads/feature  → "7g8h9i0j1k2l..."

HEAD — где ты сейчас

HEAD — специальный указатель, который всегда знает текущую ветку:

HEAD → main → a1b2c3

При переключении ветки Git обновляет HEAD и восстанавливает рабочий каталог до состояния целевого коммита. При новом коммите двигаются и HEAD, и текущая ветка вместе.

Создание и переключение веток

git branch feature          # создать ветку
git switch feature          # переключиться на ветку
git switch -c feature       # создать + сразу переключиться
git branch                  # список всех веток (* = текущая)
git branch -d feature       # удалить после merge
git branch -D feature       # удалить принудительно

git switch — современная замена git checkout. Checkout исторически делал слишком много разных вещей. switch занимается только переключением веток.

Как работает merge

Когда ветки сходятся, возникает два сценария:

Fast-forward

Если main не двигался, пока ты работал в feature:

До:   main → C1 → C2 → C3 ← feature
                         ↑
                        (обе точат на C3)

git switch main && git merge feature
После: main → C1 → C2 → C3 → C4 → C5 ← main, feature

Git просто перемещает указатель main вперёд — «перемотка». Новых коммитов не создаётся.

Три-точечный merge (merge commit)

Если main тоже получил новые коммиты, пока существовала feature:

До:
main:    C1 → C2 → C3 → C5
                    ↓
feature:           C3 → C4

После git merge feature:
main:    C1 → C2 → C3 → C5 → C6 (merge commit)
                    ↓         ↑
feature:           C3 → C4 ──┘

Создаётся merge-коммит (C6) с двумя родителями. История отражает, что работа шла параллельно.

Флаг --no-ff

git merge --no-ff feature -m "feat: добавил поиск"

Принудительно создаёт merge-коммит даже при fast-forward. Делает в истории явный «пакет» изменений — видно, где заканчивается одна задача и начинается другая.

Конфликты

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

<<<<<<< HEAD
  version: "2.0",
=======
  version: "2.1-beta",
>>>>>>> feature

Разрешение:

  1. Открыть файл, найти маркеры
  2. Оставить нужный вариант, убрать маркеры (<<<<<<<, =======, >>>>>>>)
  3. git add имя-файла
  4. git commit
git status          # покажет conflicted файлы
git merge --abort   # отменить merge, вернуться назад

VS Code и IntelliJ показывают конфликты графически: кнопки «Accept Current», «Accept Incoming», «Accept Both» прямо над каждым конфликтным блоком.

Типичный рабочий процесс

# Начинаем новую задачу
git switch main
git pull origin main            # берём последнее с сервера
git switch -c feature/search   # создаём ветку

# Работаем
git add .
git commit -m "feat: добавил строку поиска"
git commit -m "feat: добавил фильтрацию результатов"

# Перед merge — обновляем main в своей ветке
git fetch origin
git merge origin/main           # или git rebase origin/main

# Сливаем
git switch main
git merge --no-ff feature/search -m "feat: поиск"
git branch -d feature/search

# Отправляем
git push origin main

Советы

Называй ветки по смыслу. feature/user-auth, fix/login-crash, refactor/db-layer — сразу понятно, что внутри.

Мержи main в свою ветку, пока работаешь. Ветка живёт 3 дня — обновляй main каждый день. Маленькие конфликты лучше одного большого в конце.

Используй Pull Request. В командных проектах ветки не мержатся напрямую. Создаёшь PR/MR в GitHub/GitLab, коллеги смотрят diff и оставляют комментарии. После апрува — merge кнопкой.

Fast-forward vs merge commit. В личных проектах fast-forward даёт чистую историю. В командных — --no-ff позволяет понять, где была отдельная задача.

Команды для ежедневной работы

git branch                    # список веток
git switch -c feature/name    # создать и переключиться
git merge feature             # слить ветку в текущую
git merge --no-ff feature     # слить с merge-коммитом
git merge --abort             # отменить merge
git log --all --oneline --graph  # граф всех веток
git branch -d feature         # удалить ветку после merge

Что дальше

Интерактивные уроки по теме
Что такое ветки и зачем они нужны+90 XP →Слияние веток и конфликты+100 XP →Конфликты слияния+110 XP →
Готов учиться интерактивно?

Двигай слайдеры и наблюдай как работает математика

Начать учиться →