Давайте теперь узнаем о ветках Git!

Это четвертая статья из моей серии о концепциях Git для начинающих. Если вы не читали предыдущие, прочтите сначала:

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

Филиалы являются частью основных концепций, которые вы будете использовать ежедневно, поэтому важно четко понимать, что они собой представляют, как ими манипулировать, а также иметь четкое представление о том, как они «работают».

Поехали!

Какие есть ветки?

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

Говорим ли мы о Git, SVN или других системах контроля версий (VCS), всегда есть ветка по умолчанию или отправная точка. Как я уже упоминал во второй статье серии, для Git эта ветка по умолчанию называется master (но ее можно переименовать, если вы также считаете, что это #blacklivesmatter). В случае SVN эту ветвь обычно называют магистралью.

Когда мы создаем новый репозиторий, у нас есть только эта главная ветвь или основная строка кода. Мы можем добавлять в него коммиты, переделывать эти коммиты и т. Д., Как мы видели в предыдущей статье. Но наличие единственной ветки весьма ограничительно. Что, если вы хотите опробовать новые идеи? Или поработать какое-то время над чем-то на стороне, прежде чем интегрировать это с остальным? Филиалы - решение для этих и многих других случаев.

Ветви, иногда также называемые деревьями, представляют собой отдельные «версии» кодовой базы, которые могут развиваться независимо друг от друга, но также могут быть «объединены» вместе для интеграции изменений и создания новых реалий; точно так же, как когда персонажи из Slider уходят в другое измерение и разрушают хаос (или пытаются не делать этого и терпят неудачу). Каждая ветка имеет свою историю и коммиты.

Название, конечно же, относится к ветвям деревьев, которые разветвляются:

Разница с реальными деревьями состоит в том, что ветви в системе управления версиями могут присоединяться (или объединяться) с другими ветвями. Прямо как дистрибутивы linux:

В приведенном выше примере, взятом из официальной документации Git и читаемом слева направо, мы можем увидеть, как ветки могут быть созданы в какой-то момент и объединены позже. Давайте рассмотрим пример, чтобы лучше понять это.

Во-первых, в ветке master были созданы три коммита: C0, C1 и C2. Затем была создана ветвь под названием «iss53» (или альтернативная реальность, если хотите) на основе состояния кода в C2. Затем в этой ветке iss53 были созданы новые коммиты C3 и C5. Как видите, метка ветки «iss53» прикреплена к последней фиксации C5. Я еще вернусь к этому, но это представляет собой то, что называется вершиной ветви.

Фиксация C4, которая была добавлена ​​в главную ветвь сразу после C2, вообще не повлияла на ветвь «iss53». Этого просто не произошло в этой отдельной реальности.

Наконец, в C6 в главную ветвь был добавлен специальный коммит, называемый «слияние», слияние изменений, сделанных в ветке «iss53», с главной ветвью. Коммит C6 - это вершина основной ветки; также называется HEAD.

Если это недостаточно ясно, давайте попробуем провести аналогию. Представьте, что каждая фиксация представляет собой страницу в книге. Итак, вы создаете свой репозиторий и начинаете писать. Вы создаете C0 для титульной страницы, C1 для первой страницы и затем C2 для второй страницы. В этот момент вы понимаете, что у вас есть две идеи относительно того, что будет дальше, поэтому вы создаете новую ветку, в которой вы создаете C3 (стр. 3) и C5 (стр. 4) с одной версией истории. вы создаете C4 (стр. 3), который представляет собой другую версию истории. В конце концов, вы понимаете, что эти две истории на самом деле можно объединить и что вам не нужно разделять две истории. В этот момент вы объединяете ветвь «iss53» с альтернативной историей обратно в «главную» ветвь.

Я не буду сейчас вдаваться в подробности «слияния», но идея довольно проста: применить изменения, сделанные в одной ветке, к другой; адаптировать все, что необходимо в процессе.

Обратите внимание, что ветви необязательно объединять; они могут существовать сколько угодно долго; это не имеет значения. Более того, ветки продолжают существовать, даже если они уже были объединены в другие. Итак, вы можете сохранить две ветки и объединять одну в другую (или наоборот) столько раз, сколько хотите / нужно.

Например, нет ничего необычного в том, чтобы иметь ветки, соответствующие каждой среде, в которой развертывается приложение (например, DEV, ACCEPTANCE, PRODUCTION), и обновлять их при необходимости. Я расскажу вам больше о так называемых «моделях ветвления» в одной из следующих статей.

Тем не менее, я обычно предпочитаю недолговечные ветки, которые я выбрасываю после того, как они были объединены в основную ветку.

Преимущества филиалов

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

Без веток нам пришлось бы дублировать репозитории, и это было бы неуправляемым.

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

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

Почему ветки git хороши

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

Как я уже упоминал, большинство систем контроля версий поддерживают ветки. Но в некоторых из этих систем создание ветки или переключение с ветки на другую может быть медленным и сложным. Например, SVN, как известно, работает медленно с ветвями. С Git переключение с одной ветки на другую происходит невероятно быстро (почти мгновенно). Это связано с тем, как Git обрабатывает ветки. В Git ветки - это «не что иное», как помеченные указатели на определенные коммиты; зная, что каждая фиксация указывает на своего предшественника.

Кроме того, в некоторых системах слияние ветвей может быть затруднено. Опять же, с Git это действительно гладко (но не обязательно просто, в зависимости от того, что вы объединяете; представьте себе объединение исходных кодов Linux с исходными кодами Windows ..: p).

Поэтому при использовании Git не бойтесь создавать ветки. В этом отношении это совсем не похоже на SVN.

С помощью git, когда вы переключаетесь с ветки на другую (мы скоро узнаем, как это сделать), ваше рабочее дерево (то есть фактические файлы в вашей файловой системе) будет немедленно изменено, чтобы соответствовать содержимому нового извлеченного филиал.

Список существующих филиалов

Хорошо, хватит теории (пока). Поиграем немного с ветками!

Перечислить существующие ветки легко. Сделать это можно с помощью git branch команды: https://git-scm.com/docs/git-branch

Продолжайте и попробуйте следующее:

  • Создайте новый каталог и войдите в него: mkdir gitbranches && cd gitbranches (или с помощью mkcd, если вы читали мою статью о псевдонимах Bash: p)
  • Инициализируйте в нем новый репозиторий Git: git init
  • Перечислите существующие ветки: git branch

В этот момент вы подумаете, что я лжец, потому что на данный момент нет «главной» ветви. Но продолжайте:

  • Создайте текстовый файл: touch cover.txt
  • Добавьте файл в промежуточную область: git add --all (или git add -A, или git add .)
  • Зафиксировать: git commit -m 'C0: book cover'
  • Теперь снова перечислите существующие ветки: git branch

На этом этапе вы должны увидеть это:

$ git branch
* master

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

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

Создание ветки

Создание ветки также можно выполнить с помощью команды git branch <name> или git checkout -B <name>. Я в основном использую вторую команду, так как она также переключается на эту ветку после ее создания, что в целом более полезно.

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

touch p1.txt && git add . && git commit -m 'C1: Page 1'
touch p2.txt && git add . && git commit -m 'C2: Page 2'

После этого журнал репозитория должен выглядеть следующим образом:

$ git log --oneline
f10ff21 (HEAD -> refs/heads/master) C2: Page 2
4426512 C1: Page 1
7dda3ce C0: Cover

Теперь давайте создадим новую ветку iss53 (или что-то еще: p):

$ git branch iss53
Branch 'iss53' set up to track local branch 'master'.

Если вы сейчас перечислите существующие ветки, вы увидите, что наша новая ветка создана:

$ git branch
  iss53
* master

В следующих разделах мы увидим, как переключаться между ветвями.

Отслеживание филиалов

Важно понимать, что наша новая ветка «iss53» отслеживает «главную» ветвь.

На данный момент игнорировать это не «проблемно», но как только вы захотите подтолкнуть / потянуть изменения (что нам еще предстоит обнаружить), это понятие «отслеживания» станет фундаментальным.

Когда ветка настроена для отслеживания другой (будь то в том же репозитории или в удаленном), тогда эта ветка является источником / целью по умолчанию для таких операций, как git pull, git push, git status и т. Д.

Отслеживание ветвей можно настроить также с помощью команды git branch, но мы рассмотрим это позже.

Переключение между ветками

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

Идем дальше и переходи в ветку «iss53»:

git checkout iss53

Чтобы убедиться в этом, посмотрите на вывод git status:

$ git status
On branch iss53
Your branch is up to date with 'master'.
nothing to commit, working tree clean

Как видите, сейчас мы действительно находимся на ветке "iss53".

Более того, если вы посмотрите журнал, то увидите, что эта ветка действительно имеет точно такую ​​же историю, что и «главная» ветка (по крайней мере, на данный момент):

git log
commit f10ff21189d6ed2ca5548163b55a9e7a3d11d692 (HEAD -> refs/heads/iss53, refs/heads/master)
Author: Seb <[email protected]>
Date:   Tue Jul 28 16:05:12 2020 +0200
C2: Page 2
commit 44265122220956cfc5603d4ed8c503d213d01e4f
Author: Seb <[email protected]>
Date:   Tue Jul 28 16:03:12 2020 +0200
C1: Page 1
commit 7dda3ce83e536f21429e49f1e148f4acdc3a4c45
Author: Seb <[email protected]>
Date:   Tue Jul 28 15:48:29 2020 +0200
C0: Cover

Обратите внимание, что переключение между ветвями иногда невозможно. Это происходит, когда ваш рабочий каталог не чистый. Позже в этой серии мы обсудим функцию «тайника» в Git, которую вы можете использовать для решения этой проблемы.

ГОЛОВА и кончик ответвления

Чтобы отслеживать, какая ветка в настоящее время проверена, git сохраняет информацию в файле с именем «HEAD» и сохраняет ее в папке «.git» репозитория.

Теперь, когда вы перешли на ветку "iss53", взгляните на файл HEAD:

$ cat ./.git/HEAD
ref: refs/heads/iss53

Как видите, файл просто содержит ссылку на ветку. Вы можете узнать больше о том, что такое HEAD на StackOverflow.

Интересно, что ссылка на то, что файл HEAD указывает на то, что хранится в папке .git / Heads, которая содержит по одному файлу на ветку:

$ ls ./.git/refs/heads
total 16K
drwxrwxr-x 2 sebastien sebastien 4,0K jui 28 16:07 .
drwxrwxr-x 4 sebastien sebastien 4,0K jui 28 15:45 ..
-rw-rw-r-- 1 sebastien sebastien   41 jui 28 16:07 iss53
-rw-rw-r-- 1 sebastien sebastien   41 jui 28 16:05 master

Давайте посмотрим на этот файл "iss53":

$ cat ./.git/refs/heads/iss53
f10ff21189d6ed2ca5548163b55a9e7a3d11d692

А, что это? Ну, это просто (полный) хэш последнего коммита в ветке «iss53»:

$ git log --oneline -n 1
f10ff21 (HEAD -> refs/heads/iss53, refs/heads/master) C2: Page 2

Это начинает иметь смысл?

Итак, подведем итог:

  • HEAD указывает на файл заголовка текущей извлеченной ветки.
  • Ссылочный файл заголовка ветки указывает на последнюю фиксацию в этой ветке.
  • Каждая фиксация указывает на своего предшественника (т. Е. Родителя)

Теперь вы можете более четко понять, как работает команда git log; он «просто» следует по ссылкам из HEAD на первую фиксацию в истории.

Кстати, если вы снова посмотрите на историю репозитория, вы увидите, что «master» и «iss53» в настоящее время действительно указывают на одну и ту же фиксацию:

$ git log --oneline
f10ff21 (HEAD -> refs/heads/master, refs/heads/iss53) C2: Page 2
4426512 C1: Page 1
7dda3ce C0: Cover

Теперь часть (HEAD -> refs/heads/master, refs/heads/iss53) должна иметь для вас больше смысла!

Позже в этой серии эти знания о HEAD и подсказках веток станут гораздо более полезными; особенно для операций перезаписи истории.

Боковое примечание: когда вы создаете коммит, Git прикрепляет к нему метаданные. Часть этих метаданных относится к вам, автору коммита (и это зависит от вашей конфигурации Git), другая - это сообщение, которое вы установили, а третья - это ссылки 0-n на другие коммиты. Самая первая фиксация в репозитории не имеет родителя; нормальные коммиты имеют одну, а так называемые слитные коммиты имеют 2-n ссылок. Вскоре мы узнаем, как объединять ветки друг с другом.

Удаление локального филиала

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

git branch -d <name>

Обратите внимание, что это безопасная версия удаления; он предотвратит удаление, если есть не объединенные изменения (т. е. изменения, которые вы потеряете при удалении ветки).

Если вы действительно знаете, что делаете, вы также можете принудительно удалить:

git branch -D <name>

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

Переименование местного филиала

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

git branch -m <name>

Вывод

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

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

Попутно я рассказал о концепции HEAD git, которая окажется полезной позже, а также о концепциях ссылки, подсказки ветки и цепочки между коммитами.

Эти знания очень полезны как для новичков, так и для более продвинутых пользователей Git, поэтому их стоит изучить. Хотя имейте в виду, что есть еще кое-что, что нужно узнать о ветвях, но прежде чем мы перейдем к этому, нам нужно будет узнать, как взаимодействовать с удаленными репозиториями!

В следующей статье этой серии мы рассмотрим, как объединять ветки.

На сегодня все!

Понравилась эта статья? Нажмите кнопку «Нравится» ниже, чтобы увидеть больше и убедиться, что это видят и другие!

PS: Если вы хотите узнать массу других интересных вещей о программном обеспечении / веб-разработке, TypeScript, Angular, React, Vue, Kotlin, Java, Docker / Kubernetes и других интересных предметах, то не стесняйтесь возьмите копию моего книга и подписаться на мою рассылку !