Backend Java Developer
Backend Java Developer

Почти каждая система контроля версий (СКВ) в какой-то форме поддерживает ветвление. Используя ветвление, вы отклоняетесь от основной линии разработки и продолжаете работу независимо от неё, не вмешиваясь в основную линию. Во многих СКВ создание веток — это очень затратный процесс, часто требующий создания новой копии каталога с исходным кодом, что может занять много времени для большого проекта.

Это вторая статья из курса по обучению Git. Остальные статьи курса:

Ветки в Git, как и коммиты, невероятно легковесны. Ветка в Git — это простой перемещаемый указатель и ничего более. Вот почему многие фанаты Git повторяют мантру:

делай ветки сразу, делай ветки часто

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

По умолчанию, имя основной ветки — main. Как только вы начнёте создавать коммиты, указатель main будет всегда указывать на последний коммит.

Посмотрим, что такое ветки на практике. Создадим новую ветку с именем newImage.


git branch newImage

Вот и всё. Мы создали новый указатель для ветки newImage, который указывает на последний коммит в main. Загвоздка в том, что мы остались на ветке main.

Создаем новую ветку newImage

Команда git branch позволяет не только создавать ветки, но и просматривать существующие. Ветка, на которой вы находитесь помечается звездочкой.


git branch

* main
  newImage

Если мы попробуем сделать изменения, то они произойдут в ветке main, а не в новой ветке newImage.

Сообщим Git, что хотим переключиться на другую ветку:


git checkout newImage
Переключено на ветку «newImage»

Вот так! Наши изменения будут записаны в новую ветку, которая никак не повлияет на разработку в ветке main. Изменим файл file.txt и сделаем коммит.


echo "new branch" >> file.txt
git add file.txt
git commit -m "Четвертый коммит"

[newImage 378501d] Четвертый коммит
1 file changed, 1 insertion(+)

Новый коммит в ветку newImage

Чтобы понять, почему мы это называем ветками, переключимся на ветку main и сделаем еще один коммит там.


git checkout main
echo "change main" >> three-file.txt
git add three-file.txt
git commit -m "Пятый коммит"
[main 60e062b] Пятый коммит
1 file changed, 1 insertion(+)

Ветвление в Git

Четвертый и Пятый коммиты имеют одного и того же родителя - третий коммит. Но они не зависят друг от друга. Изменения, которые будут вносится в ветку newImage никак не повлияют на разработку в ветке main. Поэтому и рекомендуется на каждую задачу создавать отдельную ветку, а потом вливать ее в общую ветку разработки.

Напоследок вот совет, как создать новую ветку и переключиться на неё с помощью одной команды:


git checkout -b your_branch_name

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

Первый способ объединения изменений, который мы рассмотрим - это git merge - слияние или просто мердж.

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

Вот у нас есть две ветки main и newImage. Мы сделали какую-то работу в ветке newImage, допустим это наш четвертый коммит. Теперь необходимо влить эти изменения в ветку main.

Мы уже находимся в ветке main, посмотрим, что наш файл file.txt не содержит изменений, которые мы сделали ранее в ветке newImage.


cat file.txt
12345
67890

Втащим все изменения из ветки newImage в ветку main:


git merge newImage

Merge made by the 'recursive' strategy.
file.txt | 1 +
1 file changed, 1 insertion(+)

Git merge

Мы создали коммит, который имеет сразу двух родителей. Проверим, что изменения появились в файле file.txt в ветке main.


cat file.txt

12345
67890
new branch

А также посмотрим log, убедимся что появился новый коммит:


git log -2

commit b5c01a39ed365c8c61ba7becbb84b6a45cd96052 (HEAD -> main)
Merge: 60e062b 378501d
Author: uPagge 
Date:   Tue Jun 15 22:20:47 2021 +0300

    Merge branch 'newImage'

commit 60e062b14597415fbea93ed73746db7d14c161ce
Author: uPagge 
Date:   Tue Jun 15 22:16:11 2021 +0300

    Пятый коммит 

Второй способ объединения изменений в ветках - это rebasing. При ребейзе Git по сути копирует набор коммитов и переносит их в другое место.

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

Посмотрим, как это работает:

  • Создадим новую ветку bugFix от ветки main
  • Сделаем commit в bugFix
  • Вернемся в main
  • Сделаем коммит в main
  • Сделаем rebais из bugFix в main

git checkout -b bugFix
Переключено на новую ветку «bugFix»
echo "bugFix" >> file.txt
git add file.txt
git commit -m "Коммит в ветке bugFix"
[bugFix 7feb311] Коммит в ветке bugFix
1 file changed, 1 insertion(+)
git checkout main
Переключено на ветку «main»
echo "main" >> new-file.txt
git add new-file.txt
git commit -m "Коммит в ветке main"
[main 3a59d58] Коммит в ветке main
1 file changed, 1 insertion(+)

Пока мы не сделали rebase посмотрим log. У нас тут только коммиты из ветки main.


git log --oneline

3a59d58 (HEAD -> master) Коммит в ветке main
b5c01a3 Merge branch 'newImage'
60e062b Пятый коммит
378501d (newImage) Четвертый коммит
b64191a Третий коммит
b66f9c7 Второй коммит
06f7fc0 Первый коммит

Теперь делаем rebase и снова смотрим log. Также проверим файл file.txt.


git rebase bugFix
Сначала перематываем указатель текущего коммита, чтобы применить ваши изменения поверх него…
Применение: Коммит в ветке main
git log --oneline
8868e84 (HEAD -> main) Коммит в ветке main
7feb311 (bugFix) Коммит в ветке bugFix
b5c01a3 Merge branch 'newImage'
60e062b Пятый коммит
378501d (newImage) Четвертый коммит
b64191a Третий коммит
b66f9c7 Второй коммит
06f7fc0 Первый коммит
cat file.txt
12345
67890
new branch
bugFix

Git Rebase
Git дописал копию коммита C7 за коммитом C6 и перенес туда указатель

Удалим ветку bugFix и снова проверим log:


git branch -d bugFix
Ветка bugFix удалена (была 7feb311).
git log --oneline
8868e84 (HEAD -> master) Коммит в ветке main
7feb311 Коммит в ветке bugFix
b5c01a3 Merge branch 'newImage'
60e062b Пятый коммит
378501d (newImage) Четвертый коммит
b64191a Третий коммит
b66f9c7 Второй коммит
06f7fc0 Первый коммит

Коммит остался (строка 5), пропал только указатель на ветку в коммите 7feb311.

Напоследок вот вам шпаргалка по отличию Merge от Rebase:

Сравнение merge и rebase
Сравнение Merge и Rebase

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

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

Комментарии