Ветки в 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
.
Тема про ветки в git
огромная, поэтому все темы охватить в одной статье нереально.
В последующих статьях будем раскрывать темы более глубоко.
Хотите оптимизировать свой бизнес, нужен сервис, сайт или интеграция.
Бесплатно расчитаю время разработки, предложу решение вашей задачи.