Гайд по Git : Часть 2 : Ветки и слияние веток

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

· 5 минуты на чтение
Гайд по Git : Часть 2 : Ветки и слияние веток

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

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

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

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

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

Спонсор поста

Пример работы с ветками

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

$ git branch newImage

Команда создания новой ветки

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

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

$ git branch

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

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

$ git checkout newImage

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

Теперь изменения будут сохраняться в ветке newImage и не затронут ветку main. Например, давайте изменим файл file.txt и сделаем коммит:

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

Результат:

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

Теперь, чтобы увидеть, как работают ветки, переключимся обратно на ветку 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(+)

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

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

$ git checkout -b your_branch_name

Merge

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

Первый способ объединения изменений, который мы рассмотрим — это команда git merge. Слияние (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

Мы создали коммит, который имеет двух родителей. Теперь проверим, что изменения из ветки newImage появились в файле 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

    Пятый коммит 
Спонсор поста 3

Rebase

Второй способ объединения изменений из разных веток — это rebase. При выполнении ребейза Git фактически копирует набор коммитов и переносит их в другое место.

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

Создадим новую ветку bugFix от ветки main:

$ git checkout -b bugFix
Переключено на новую ветку «bugFix»

Внесём изменения и сделаем коммит в ветке bugFix:

$ echo "bugFix" >> file.txt
$ git add file.txt
$ git commit -m "Коммит в ветке bugFix"
[bugFix 7feb311] Коммит в ветке bugFix
1 file changed, 1 insertion(+)

Теперь вернёмся в ветку main, сделаем изменения и коммит:

$ 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 посмотрим лог коммитов в ветке main:

$ git log --oneline

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

Теперь выполним rebase ветки bugFix на ветку main:

$ git rebase bugFix

Сначала перематываем указатель текущего коммита, чтобы применить ваши изменения поверх него...
Применение: Коммит в ветке main

После выполнения rebase снова проверим лог:

git log --oneline

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

Как видно, коммит из ветки bugFix теперь находится перед коммитом из ветки main, создавая линейную последовательность.

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

Также проверим содержимое файла file.txt:

$ cat file.txt

12345
67890
new branch
bugFix

Git перенёс копию коммита из ветки bugFix после коммита из ветки main и обновил указатель ветки.

Теперь можно удалить ветку bugFix, так как её изменения уже были применены:

$ 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 Первый коммит 

Коммит из ветки bugFix остался в истории, однако указатель на ветку был удалён.

Заключение

Мы рассмотрели работу с ветками в Git и процесс их слияния. В идеальном проекте все ветки стремятся быть объединёнными в основную ветку. Не забывайте создавать отдельные ветки от основной ветки разработки для каждой отдельной задачи. Это позволяет изолировать изменения и поддерживать чистоту истории проекта.

Struchkov Mark
Struchkov Mark
Задавайте вопросы, если что-то осталось не понятным👇