Введение в git для новичков. Часть 2. Ветки

01.08.2019

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

Ветвление

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

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

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

Создание новой ветки и переключение к ней

git checkout -b <feature_name>

$ git checkout -b feature_newbranch
Switched to a new branch 'feature_newbranch'
$ git status
On branch feature_newbranch
nothing to commit, working tree clean

После того как мы оказались в другой ветке, команда git commit будет создавать коммиты только в активной ветке.

Список веток можно посмотреть командой
git branch

$ git branch
* feature_newbranch
  master

Список различий между ветками:
git diff <source_branch> <target_branch>

$ git diff master
diff --git a/test b/test
index 9daeafb..cb3d5cc 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,1 @@
 index.html
+<li><a href="/login">Войти</a></li>

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

Когда фича готова, можно перенести все коммиты из специальной ветки в основную.
git checkout master
git merge <feature_name>

$ git checkout master
Switched to branch 'master'
$ git merge feature_newbranch
Updating 930da95..6d79967
Fast-forward
 index.html | 1 +
 1 file changed, 1 insertion(+)

И, если всё прошло успешно, специальную ветку можно удалить
git branch -d <feature_name>

$ git branch -d feature_newbranch
Deleted branch feature_newbranch (was 6d79967).

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

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

$ git merge branch_test
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

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

Список файлов по которым возникли конфликты можно посмотреть уже знакомой командой

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

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

git add <filename.html>

Если конфликт это просто результат проблемы раньше-позже, то можно попробовать решить его автоматически командами

git checkout --theirs <filename.html>
git add <filename.html>
или
git checkout --ours <filename.html>
git add <filename.html>

$ git checkout --theirs index.html
Updated 1 path from the index

Первая команда применит вариант из сливаемой ветки. Вторая - из активной.

Также есть возможность провести слияние сразу с автоматическим применением вариантов с нужной стороны:
git merge --strategy-option theirs
git merge --strategy-option ours

Копирование отдельных коммитов

Бывает так, что необхоимо повторить изменения одного или нескольких коммитов из другой ветки без их полного слияния. Сделать это можно командой
git cherry-pick <commit_id>

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

Отменить коммит созданный cherry-pick можно командой
git revert <new_commit_id>


В следующих частях мы рассмотрим работу с удалёнными репозиториями и более подробно расскажем о работе с локальными изменениями.