Пост

Ветки в git

Суть ветвления в git.

Ветки в git

Ветки

В прошлой статье мы поняли как git хранит изменения.

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

Ветки позволяют вести разработку сразу в нескольких направлениях.

Они могут создаваться совершенно по разным причинам.

Например:

  • Ветка может отражать состояние проекта stable, development, production.
  • Можно разрабатывать одновременно и новую и старую версию проекта в отдельных ветках, и показывать их заказчику.
  • Считается, что для каждой функциональности нужно заводить отдельную ветку.
  • Если проект большой каждую задачу или модуль можно делать в отдельной ветке.
  • Чисто эстетически удобно вести разработку независимо.

Ветка по умолчанию

Ветка существует с самого рождения репозитория, имя может быть любым, но при инициализации она называется master или main.

Название можно легко поменять, при создании репозитория, или в конфигурации.

1
2
3
4
5
# Глобальное название ветки по умолчанию для всех репозиториев
git config --global init.defaultBranch main
# Или создать ветку по умолчанию с любым названием
git init --initial-branch=test-branch
git init -b abracadabra-branch

Переименовать ветку

Переименовать ветку не сложно. Достаточно указать старое имя и новое имя ветки

1
git branch -m test-branch main

Как именовать ветку

  • Веткам можно давать иерархические имена вроде test/8.4/branch-my-test/diff
  • Ветка не может заканчиваться символом /, тогда мы получаем ошибку fatal: 'test/' is not a valid branch name
  • В имени ветки не может быть точки в названии части, например /.file/test/.a
  • Так же в имени не могут быть символы -, .., ~, ^, :, ?,*,[

git сам проверяет корректность ветки, и не даст создать ее с недопустимым названием.

Работа в ветках

Ветки позволяют разделять работу с кодом и работать с ним в нескольких направлениях.

Имя ветки всегда соответствует последнему коммиту в ней, что является просто указателем на коммит, активной ветки.

То есть имя ветки является динамическим показателем который перемещается в процессе разработки.

Например, три независимые ветки.

1
2
3
Коммит1 Коммит2 - ветка one
Коммит1 Коммит2 Коммит3 - ветка two
Коммит1 Коммит2 Коммит3 Коммит4 Коммит5 - ветка three

По факту git не отслеживает от какого коммита происходит ветка, но общий коммит откуда началась история есть всегда.

По любой ветке можно воссоздать линию истории проекта.

Отличие веток и тегов

Тег - это временная закладка или постоянный указатель на определенную версию продукта. То есть - это статичный объект всегда указывающий на коммит.

Ветка - указывает на каждый коммит, который мы делаем. Имя ветки перемещается вместе с линией разработки, то есть не является статичной величиной.

Важно не использовать одинаковые имена для тегов и веток.

Разработчик сам решает, что объявить тег или ветку, если ссылка статическая - это тег, если динамическая - это ветка.

Создать ветку

git поддерживает сложную структуру ветвления. При создании новой ветки она всегда основывается на уже созданном в репозитории коммите.

Ветки можно добавлять и удалять множество раз.

Базовая команда для создания ветки

1
git branch name_b [start]

Можно не указывать стартовую точку ветки [start], тогда она встанет на последний коммит текущей ветки, то есть туда, где мы сейчас стоим.

Команда git branch просто создает имя ветки и никак не переключает на него. Но чтобы начать работать в ветке на нее нужно переключиться, но об этом позже.

К примеру, у меня три коммита, из которых коммит 4953530 родительский.

Далее я создал 6 имен веток и просто присвоил их на определенный коммит, 5 веток стоят на последнем коммите, а 1 на предыдущем.

1
2
3
* bb7baf8 (HEAD -> main, branch-5, branch-4, branch-3, branch-2, branch-1) other commit 2
* ab7306b (branch-6) other commit
* 4953530 added file

Выводить такую историю удобно командой git log --graph --pretty=oneline --abbrev-commit --all --decorate.

Ветку branch-6, я создал командой, где стартовой точкой указал коммит

1
git branch branch-6 ab7306bf38057f495c85aaf97506f366d3db2ea6

Имена веток

Получить имена веток можно той же командой git branch. Только одна ветка может быть связана с рабочим каталогом, это ветка со *.

В данном случае - это main.

1
2
3
4
5
6
7
8
git branch
  branch-1
  branch-2
  branch-3
  branch-4
  branch-5
  branch-6
* main

Если нужно получить список веток с последнем коммитом в каждой, используется флаг -v.

1
2
3
4
5
6
7
8
git branch -v
  branch-1 bb7baf8 other commit 2
  branch-2 bb7baf8 other commit 2
  branch-3 bb7baf8 other commit 2
  branch-4 bb7baf8 other commit 2
  branch-5 bb7baf8 other commit 2
  branch-6 ab7306b other commit
* main     bb7baf8 other commit 2

Мы здесь видим только локальные ветки, но ветки могут быть и удаленные, об этом в отдельной статье.

Переключение веток

Для переключения на ветку используется команда git checkout.

1
git checkout branch

Переключатся можно из любой ветки на любую, при этом рабочий каталог с файлами тоже будет изменен.

Из предыдущего примера переключимся на ветку branch-5, и посмотрим результат.

1
2
3
4
git checkout branch-5
* bb7baf8 (HEAD -> branch-5, main, branch-4, branch-3, branch-2, branch-1) other commit 2
* ab7306b (branch-6) other commit
* 4953530 added file

Теперь на branch-6, и тоже посмотрим результат

1
2
3
4
git checkout branch-6
* bb7baf8 (main, branch-5, branch-4, branch-3, branch-2, branch-1) other commit 2
* ab7306b (HEAD -> branch-6) other commit
* 4953530 added file

Как видим указатель HEAD смотрит в рабочий каталог.

При переключении веток происходит следующее:

  • Если в ветке на которую мы переключаемся есть файлы, но их нет в текущей ветке, они будут добавлены в рабочий каталог.
  • Если в ветке на которую мы переключаемся нет файлов из текущий ветки, они будут удалены из рабочего каталога.
  • Состояние всех файлов и каталогов в ветках приводится к состоянию, в котором он находился на момент коммита.

Это все хорошо, переключаемся туда-сюда, но что делать если у нас есть незафиксированные изменения.

То есть стоя на ветке, поменяли файл, но не зафиксировали его, пробуем переключится на другую ветку и получаем ошибку.

Переключение не произойдет.

1
2
3
4
5
git checkout branch-6
error: Your local changes to the following files would be overwritten by checkout:
        file
Please commit your changes or stash them before you switch branches.
Aborting

Узнать, что не дает переключится, поможет команда git diff.

1
2
3
4
5
6
7
8
9
10
11
git diff file

diff --git a/file b/file
index 1e5fb43..cfdf15a 100644
--- a/file
+++ b/file
@@ -1 +1 @@
-что то поменяли 1
\ No newline at end of file
+что то поменяли 2
\ No newline at end of file

То есть в целевой ветке - это файл выглядит так, а у нас по-другому.

git по умолчанию пресекает случайное удаление или измнение данных, без запроса на это

Выход из этой ситуации - сделать коммит в текущей ветке и переключится на целевую.

С версии git 2.23.0 появилась возможность переключать ветки с помощью git switch branch-5, которая как раз создана для этой цели.

Но не всегда переключение веток удачно происходит, иногда возникают конфликты слияния, но об этом в отдельной статье.

Создать и переключится

Можно также создать ветку и сразу на нее переключится, для этого используется команда git checkout -b

1
git checkout -b new-branch

Что по сути равнозначно выполнению двум командам

1
2
git branch new-branch
git checkout branch

Про HEAD

Как говорил выше, при переключении на ветку мы переходим на ее последний коммит, но мы можем переключиться на любой коммит.

Если ветка и HEAD будут указывать на разные коммиты, у нас получится состояние detached HEAD.

Например, я переключаюсь на коммит, той же командой git checkout, который без ветки

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
git checkout 4953530266f980fb6cad99145c266845219bc7e9

Note: switching to '4953530266f980fb6cad99145c266845219bc7e9'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 4953530 added file

Переключение произошло, но если просмотреть git status, увидим сообщение

1
2
git status
HEAD detached at 4953530

Таким образом у нас получилась ситуация, где мы перемотали историю на нужный нам коммит.

Вернуться к последнему коммиту в ветке можно командой git switch -.

Удаление ветки

Удалить ветку можно командой git branch -d

1
git branch -d my-branch

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

Так же ветку нельзя удалить, если она не полностью слита, есть коммиты которых нет в других ветках.

Пример разветвленного репозитория

В качестве пример на скрине ниже посмотрим на ветки в репозитории фреймворка symfony.

img-description Ветки в репозитории symfony

Тема про ветки в git огромная, поэтому все темы охватить в одной статье нереально.

В последующих статьях будем раскрывать темы более глубоко.

Авторский пост защищен лицензией CC BY 4.0 .

Хотите оптимизировать свой бизнес, нужен сервис, сайт или интеграция.

Бесплатно расчитаю время разработки, предложу решение вашей задачи.