Ветки в Git

От создания до командной работы: разбираем два сценария, именование веток, Pull Request, Merge и полный цикл разработки с анимациями в терминале.

Есть два принципиально разных сценария создания ветки. Второй — это обычная практика разработки, с ней вы столкнётесь в 99% случаев. Первый используется редко, но знать о нём полезно.

Вариант 1. Создать полностью пустую ветку (без истории)

Такая ветка не содержит ни одного файла и ни одного коммита из main. Она начинается с чистого листа — как будто вы только что создали новый репозиторий, но внутри уже существующего.

Последовательность команд

~/projects/my-repo — zsh

История после создания orphan-ветки

A B C main X new-branch нет связи
Orphan-ветка не имеет общей истории с main

Когда используют

⚠️
В обычной разработке почти никогда не используют. Если вы не уверены — вам нужен второй вариант.

Вариант 2. Создать ветку как копию main

Это именно тот вариант, который используется практически всегда. Новая ветка начинается с того же коммита, на котором находится main, и дальше живёт своей жизнью.

Создаём ветку от main и делаем коммит

~/projects/my-repo — zsh

Сразу после создания ветки

A B C main feature/login HEAD
Обе ветки указывают на один коммит

После коммита в новой ветке

A B C D main feature/login
main остался на месте, feature/login ушёл вперёд

Пушим ветку

$ git push -u origin feature/login
Enumerating objects: 5, done.
remote: Create a pull request for 'feature/login' on GitHub by visiting:
remote: https://github.com/you/repo/pull/new/feature/login

После этого можно создавать Pull Request (или Merge Request в GitLab).

Именование веток: почему feature/login?

Вы могли заметить, что в примерах ветка называется feature/login. Это не правило Git — это соглашение, которое используют почти все команды. Git разрешает практически любые имена: dev, my_branch, ivan, test123 — всё будет работать.

Структура названия

Название состоит из двух частей, разделённых символом /:

feature/login │ │ │ └── что именно делаем │ └──────── тип работы

Популярные префиксы

feature/ Новая функциональность
bugfix/ Исправление ошибки
hotfix/ Срочная правка в продакшене
refactor/ Изменение кода без новой функциональности
docs/ Изменения документации
test/ Добавление тестов
chore/ Технические задачи (Docker, CI/CD, зависимости)

Зачем нужен символ "/"

Для Git feature/login и feature-login почти одинаковы. Но человеку гораздо удобнее видеть структуру. Сравните:

❌ Без "/": login, payment, profile, docker, readme, bug1, bug2, bug3
✓ С "/": feature/login, feature/payment, feature/profile, bugfix/login, bugfix/docker, docs/readme, chore/docker

Сразу видно, какая ветка для чего. GitHub и GitLab тоже группируют такие ветки визуально, поэтому их проще искать.

Примеры названий

В реальных проектах

Очень часто ветки называют по номеру задачи из Jira:

feature/PROJ-125-login bugfix/PROJ-241-auth-error

Сразу понятно, к какой задаче относится код.

Для личных проектов

Если вы работаете один, достаточно простой схемы:

feature/login feature/docker feature/parser bugfix/auth bugfix/nginx refactor/api docs/readme
💡
Важно запомнить: название ветки никак не влияет на работу Git. Для Git это просто строка. Эти две команды абсолютно равнозначны: git switch -c feature/login и git switch -c banana. Обе создадут ветку. Разница только в том, что feature/login сразу говорит разработчикам: «в этой ветке разрабатывается авторизация», а banana не несёт никакой полезной информации.

Что происходит внутри Git

Когда вы создаёте новую ветку командой git switch -c feature/login, Git не копирует файлы. Он просто создаёт новый указатель на существующий коммит.

До и после создания ветки

ДО: A B C main / HEAD ПОСЛЕ: A B C main feature/login HEAD
Ветка — это просто указатель на коммит (несколько байт)

Что выбрать

Практически всегда используйте второй вариант:

$ git switch -c имя_ветки # или старый синтаксис $ git checkout -b имя_ветки

Именно так работают команды в большинстве проектов: клонируют репозиторий, создают ветку от main (или develop), делают изменения, затем отправляют ветку в удалённый репозиторий и создают Pull Request. Первый вариант (--orphan) нужен только для специальных случаев, когда новая ветка должна иметь полностью независимую историю.

Pull Request и Merge на простом примере

Это один из самых важных моментов в Git. Многие путают Git и GitHub/GitLab.

Шаг 1. В репозитории есть только main

project/ └── file1.txt → "Привет"
A main
A — первый коммит

Шаг 2. Клонируем проект

$ git clone repo.git
Cloning into 'repo'...
remote: Enumerating objects: 3, done.

Шаг 3. Создаём свою ветку

$ git switch -c dev
Switched to a new branch 'dev'
A main dev HEAD
Ветки абсолютно одинаковые

Шаг 4. Вносим изменения

Добавляем новый файл file2.txt со словом "Мир" и меняем file1.txt — добавляем второе слово:

project/ ├── file1.txt"Привет Git" (было: "Привет") └── file2.txt"Мир" (новый файл)

Шаг 5. Коммитим

$ git add .
$ git commit -m "Добавил второй файл"
[dev b2f3a1c] Добавил второй файл
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 file2.txt
A B main dev
Коммит B существует только в ветке dev

Шаг 6. Пушим

$ git push origin dev
Enumerating objects: 4, done.
To github.com:you/repo.git
* [new branch] dev -> dev

Теперь на GitHub появились две ветки. Но main вообще не изменился. Это очень важно понимать.

Что происходит дальше? Pull Request

Pull Request означает буквально: "Прошу забрать мои изменения."

Вы говорите владельцу проекта:

💡
Это не merge. Это только просьба. Merge произойдёт позже, после проверки.

На GitHub вы нажимаете кнопку "Create Pull Request". Что увидит другой разработчик?

file1.txt -Привет +Привет +Git + file2.txt +Мир

Ревьюер может написать комментарий: "Здесь ошибка", "Добавь ещё один тест" или "Всё отлично".

После проверки — Merge

Если всё хорошо, нажимается кнопка "Merge Pull Request". И только теперь происходит merge — объединение двух веток.

ДО MERGE: A B main B dev ПОСЛЕ MERGE: A B B' main
Теперь обе ветки содержат одинаковую историю

Обычно после merge рабочую ветку удаляют:

A B B' main
Ветка dev исчезла — она больше не нужна

Почему нельзя сразу пушить в main?

Представьте, что в компании работают 20 разработчиков. Если каждый будет писать сразу в main, получится хаос:

Все одновременно. Никто ничего не проверяет. В итоге главный проект может перестать работать.

Поэтому используют такую схему:

main │ ├── feature/login ├── feature/payment ├── feature/profile └── feature/search

Полный цикл разработки

Многие новички думают, что Pull Request и Merge — это одно и то же. На самом деле это разные этапы.

🌿 Создал ветку
💻 Написал код
💾 Commit "Я сохранил свою работу"
📤 Push "Отправил на сервер"
📨 Pull Request "Посмотрите, можно добавить?"
🔍 Проверка кода Code Review
🔀 Merge "Изменения добавлены в main"
🗑️ Удаление рабочей ветки
Запомните простой образ:
Commit — "Я сохранил свою работу."
Push — "Я отправил свою работу на сервер."
Pull Request — "Пожалуйста, посмотрите мою работу и решите, можно ли её добавить."
Merge — "Изменения действительно добавлены в основную ветку."

Командная работа: день 1 и день 2

Именно здесь начинается реальная командная работа, и это тот момент, который вызывает больше всего путаницы у новичков. Разберём весь цикл.

День 1. Первый разработчик

developer-1 — zsh

После merge в main теперь:

project/ ├── file1.txt → "Привет Git" └── file2.txt → "Мир"
A B C main
main после merge первого разработчика

День 2. Второй разработчик добавляет file3

Другой разработчик берёт уже новый main. Он создаёт свою ветку feature/admin, добавляет file3.txt со словом "Админка" и делает коммит. После его merge в main появляется новый коммит.

A B C D main
main после merge второго разработчика (появился file3.txt)

Что происходит у первого разработчика?

На его компьютере до сих пор старый main. Он вообще ничего не знает про новый коммит на сервере.

⚠️
Локальный main не обновляется автоматически. Нужно сделать это вручную.

Синхронизация с сервером

Шаг 1. Получаем изменения с сервера

developer-1 — zsh

Важно понимать: git fetch ничего не меняет в ваших файлах. Он только говорит Git: "На сервере появился новый коммит".

ПОСЛЕ git fetch: A B C D локальный main origin/main ПОСЛЕ git pull: A B C D локальный main
Файл file3.txt появился и у вас

Шаг 2. Обновляем свою рабочую ветку

А что с веткой dev? Она осталась старой — каждая ветка это снимок истории на момент её создания.

A B C D main dev ← не обновилась автоматически
dev осталась в прошлом

Теперь нужно обновить dev. Переходим в неё и объединяем изменения из main:

$ git switch dev
Switched to branch 'dev'
$ git merge main
Updating a1b2c3d → e4f5g6h
Fast-forward
file3.txt | 1 +
1 file changed, 1 insertion(+)
A B C D main dev
Ветка dev получила новый файл file3.txt

Шаг 3. Продолжаем работу

Теперь разработчик делает изменения — например, создаёт file4.txt или меняет file3.txt:

project/ ├── file1.txt → "Привет Git" ├── file2.txt → "Мир" ├── file3.txt"Админка\nНастройки" (добавили строку) └── file4.txt"Новый модуль" (новый файл)
$ git add .
$ git commit -m "Добавил настройки админки"
$ git push origin dev

Открываем новый Pull Request → после merge в main появляется ещё один коммит.

Конфликты слияния

Представим: в main файл file3.txt содержит слово "Админка". Вы обновили ветку dev из main. Потом решили изменить "Админка" на "Панель администратора".

Но в это время другой разработчик уже изменил тот же файл в main: "Админка" → "Административная панель".

A B C E main D dev ⚠ КОНФЛИКТ
Один и тот же участок файла изменили два человека

Когда вы выполняете git merge main, Git видит: один и тот же участок файла изменили два человека. Сам решить он уже не может. Появляется merge conflict.

file3.txt <<<<<<< HEAD +Панель администратора ======= -Административная панель >>>>>>> main

Git попросит вручную выбрать, какой текст оставить, либо объединить оба изменения.

Как обычно работают в командах

На практике цикл выглядит так:

1️⃣ Создал ветку от main
2️⃣ Пишешь код
3️⃣ Commit
4️⃣ Push
5️⃣ Pull Request
Пока идёт проверка, в main могут появиться новые изменения
6️⃣ Обновляешь свою ветку из main (git merge main или git rebase main)
7️⃣ Исправляешь возможные конфликты
8️⃣ Push
9️⃣ Merge Pull Request
🔟 Удаляешь рабочую ветку
🔄 Переходишь на main → git pull
Создаёшь новую ветку для следующей задачи
💡
Последний пункт — важная привычка. В большинстве команд не продолжают бесконечно работать в одной и той же ветке dev. После слияния Pull Request рабочую ветку обычно удаляют, обновляют локальный main (git pull) и создают новую ветку от актуального main для следующей задачи, например feature/user-profile или bugfix/login-error. Так история остаётся чище, а вероятность конфликтов уменьшается.

Шпаргалка: что делать каждый день

# Утро: синхронизируемся с сервером
$ git switch main
$ git pull
# Создаём новую ветку под задачу
$ git switch -c feature/название-задачи
# Работаем, коммитим, пушим
$ git add .
$ git commit -m "Описание изменений"
$ git push -u origin feature/название-задачи
# Создаём Pull Request на GitHub
# Ждём ревью → merge
# После merge: возвращаемся в начало цикла
$ git switch main
$ git pull

Основные команды Git — краткий список

Шпаргалка самых важных команд. Сохраните себе — пригодится.

📦 Настройка и начало работы

git init Создать новый репозиторий в текущей папке
git clone <url> Скачать репозиторий с сервера к себе
git config --global user.name "Имя" Задать имя автора для всех коммитов
git config --global user.email "mail" Задать email автора для всех коммитов

🔍 Статус и история

git status Показать изменённые файлы и текущую ветку
git log Показать историю коммитов
git log --oneline Компактный вид истории (один коммит — одна строка)
git diff Показать, что изменилось в файлах

💾 Сохранение изменений

git add <файл> Подготовить файл к коммиту (добавить в индекс)
git add . Подготовить все изменённые файлы сразу
git commit -m "сообщение" Сохранить подготовленные изменения с описанием
git commit --amend Исправить последний коммит (изменить сообщение или файлы)

🌿 Ветки

git branch Показать список локальных веток
git branch <имя> Создать новую ветку (без переключения)
git switch <имя> Переключиться на другую ветку
git switch -c <имя> Создать новую ветку и сразу переключиться на неё
git branch -d <имя> Удалить локальную ветку

🔀 Объединение и синхронизация

git merge <ветка> Влить изменения из указанной ветки в текущую
git rebase <ветка> Перенести коммиты текущей ветки на верх другой
git fetch Скачать изменения с сервера, не трогая файлы
git pull Скачать и сразу применить изменения с сервера (fetch + merge)

📤 Отправка на сервер

git push Отправить свои коммиты на удалённый сервер
git push -u origin <ветка> Отправить ветку и связать её с удалённой
git push origin --delete <ветка> Удалить ветку на удалённом сервере

🛟 Откат и временное хранение

git stash Временно спрятать незакоммиченные изменения
git stash pop Вернуть спрятанные изменения
git reset --soft HEAD~1 Отменить последний коммит, сохранив изменения
git checkout -- <файл> Отменить изменения в файле (вернуть к последнему коммиту)
🚀
Минимальный набор для старта:

git status,
git add .,
git commit,
git push,
git pull,
git switch -c
Освойте их — и вы уже сможете работать в большинстве проектов.