Больше не нужно искать работу мечты — присоединяйтесь к команде Клауда

Git checkout: как работать с ветками

Миша Курушин
Миша Курушин
Технический писатель
29 февраля 2024 г.
1343
12 минут чтения
Средний рейтинг статьи: 5

Команда checkout в системе контроля версий Git отвечает за переключение между отдельными ветками репозитория.

Каждое переключение обновляет файлы в рабочем каталоге на основе тех данных, которые хранятся в выбранной ветке. При этом каждый последующий коммит автоматически добавляется в активную ветку, выбранную ранее с помощью команды checkout.

В этом руководстве будут рассмотрены возможные пути использования как команды git checkout, так и ряда других сопутствующих команд (git branch, git reflog, git remote show), которые позволяют взаимодействовать с ветками как локального, так и удаленного репозитория.

1. Создание репозитория

Сперва подготовим отдельный каталог для тестового проекта в Git:

mkdir project

После чего перейдем в него:

cd project

Наконец, выполним инициализацию репозитория Git:

git init

После этого нам станут доступны все команды по управлению как ветками, так и репозиторием в целом.

2. Создание файла и выполнение коммита

Чтобы понять, как переключение веток влияет на рабочий каталог (и репозиторий целикоv), мы подготовим импровизированный файл исходника проекта с тривиальным содержимым внутри:

sudo nano file_m

Наполнение файла будет следующим:

file in master

Давайте проверим состояние рабочего каталога:

ls

Существует только один файл:

file_m

Теперь проиндексируем изменения:

git add file_m

После чего выполним коммит:

git commit -m "First commit"

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

3. Создание новой ветки

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

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

Однако для начала давайте узнаем, на какой ветке мы находимся сейчас:

git branch

В консоли появится вывод с подсвеченной активной веткой master:

* master

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

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

git branch feature1

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

Мы можем убедиться в этом, снова проверив список существующих веток:

git branch

Можно заметить, что к списку добавилась ветка feature1, однако активной веткой (то есть помеченной с помощью зеленого цвета и символа звездочки) по прежнему является master:

  feature1
* master

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

4. Переключение на существующую ветку

Для того, чтобы вручную переключиться на уже существующую ветку, необходимо выполнить команду checkout, указав название ветки:

git checkout feature1

В консоли появится сообщение об успешном переключении:

Switched to branch 'feature1'

Снова проверим список существующих веток:

git branch

Как видно, активной веткой теперь является feature1:

* feature1
 master

Давайте снова проверим состояние рабочего каталога:

ls

В нем по-прежнему один файл, который был «унаследован» из ветки master:

file_m

Так как отдельная ветка feature1 нужна для модификации проекта, мы создадим еще один файл:

sudo nano file_f1

Его содержимое пусть будет таким:

file in feature1

Проиндексируем изменения:

git add file_f1

И снова сделаем коммит:

git commit -m "Commit from feature1"

Снова проверим рабочий каталог:

ls

Можно убедиться, что файлов теперь несколько:

file_m  file_f1

Теперь переключимся снова на главную ветку:

git checkout master

После этого в рабочем каталоге останется только один файл:

file_m

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

5. Переключение на новую ветку

Предположим, мы решили добавить в наш проект еще одну фичу, а значит, хотим выделить под нее новую ветку.

Сперва убедимся, что мы находимся на master:

git checkout master

А теперь попробуем переключиться на еще не созданную ветку feature2:

git checkout feature2

Закономерно, мы получим ошибку:

error: pathspec 'feature2' did not match any file(s) known to git

Однако команда checkout позволяет создавать новые ветки в момент переключения на них. Для этого необходимо добавить флаг -b:

git checkout -b feature2

В консоли появится сообщение об успешном переключении:

Switched to a new branch 'feature2'

По сути, команда checkout с флагом -b эквивалентна двум вызовам:

git branch feature2
git checkout feature2

Снова проверим список существующих веток:

git branch

Теперь у нас есть ветка feature2, которая стала активной сразу после своего создания:

  feature1
* feature2
 master

Новая ветка создается на основе той ветки (ее рабочего каталога и списка коммитов), которая была активной. Перед созданием ветки feature2 мы переключились на ветку master, а значит в рабочем каталоге должен быть только файл file_m, но не файл file_f1.

6. Удаление ветки

Удалить ветку, которая является активной, невозможно:

git branch -d feature2

Флаг -d указывает на запрос удаления указанной ветки. В консоли появится сообщение об ошибке:

error: Cannot delete branch 'feature2' checked out at '/root/project'

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

git checkout master

После чего выполнить непосредственно удаление:

git branch -d feature2

На этот раз в консоли появится сообщение об успешном удалении ветки:

Deleted branch feature2 (was 24c65ff).

Список существующих веток станет таким:

  feature1
* master

7. Создание ветки из другой ветки

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

Давайте убедимся, что мы находимся в ветке master:

git checkout master

На данный момент специальный указатель HEAD указывает на активную ветку master, которая, в свою очередь, является указателем на последний коммит этой ветки.

До этого мы создавали ветку feature2 из активной ветки master. Однако сейчас мы создадим ветку feature2 из ветки feature1 (а не из master) без явного переключения на нее — мы по-прежнему будем в master:

git checkout -b feature2 feature1

Теперь активной веткой является feature2. Проверим содержимое рабочего каталога:

ls

Как видно, состояние каталога такое же, как в feature1, а не в master:

file_m  file_f1

Мы также можем посмотреть историю коммитов:

git log

Как видно, ветка feature2 содержит как коммиты ветки master, так и коммиты ветки feature1:

commit fb1b1616c85c258f647df4137df535df5ac17d6c (HEAD -> feature2, feature1)
Author: root <root@2450302-yn55665.twc1.net>
Date:   Tue Feb 13 02:18:02 2024 +0300

    Commit from feature1

commit 24c65ffab574a5e478061034137298ca2ce33c94 (master)
Author: root <root@2450302-yn55665.twc1.net>
Date:   Mon Feb 12 23:30:56 2024 +0300

    First commit

8. Сброс ветки до состояния другой ветки

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

Например, мы можем сбросить ветку feature2 до состояние ветки master:

git checkout -B feature2 master

Обратите внимание, что используется флаг -B, а не -b.

В консоли появится соответствующее сообщение:

Reset branch 'feature2'

Проверим рабочий каталог:

ls

Как видно, в нем только один файл:

file_m

При этом список «унаследованных» коммитов ветки feature2 превратиться в список коммитов ветки master:

git log

В консольном выводе будет один единственный коммит — самый первый:

commit 24c65ffab574a5e478061034137298ca2ce33c94 (HEAD -> feature2, master)
Author: root <root@2450302-yn55665.twc1.net>
Date:   Mon Feb 12 23:30:56 2024 +0300
   First commit

9. Просмотр истории переключений

Переключение веток — это не просто операция чтения. Смена ветки вносит изменение в репозиторий, создавая новую запись в истории переключений.

По этой причине в Git есть специальная команда, выводящая полную хронологию переключения между ветками:

git reflog

Хронология операций выводится отображается снизу-вверх, то есть самые последние переключения находятся выше:

fb1b161 (HEAD -> feature2, feature1) HEAD@{1}: checkout: moving from master to feature2
24c65ff (master) HEAD@{2}: checkout: moving from feature1 to master
fb1b161 (HEAD -> feature2, feature1) HEAD@{3}: commit: Added the first feature
24c65ff (master) HEAD@{4}: checkout: moving from master to feature1
24c65ff (master) HEAD@{5}: checkout: moving from feature2 to master
24c65ff (master) HEAD@{6}: checkout: moving from feature1 to feature2
24c65ff (master) HEAD@{7}: checkout: moving from master to feature1
24c65ff (master) HEAD@{8}: commit (initial): First commit

10. Переключение на удаленную ветку

Добавление удаленного репозитория

Предположим, у нас есть удаленный репозиторий GitHub, с которым мы работаем через HTTPS-соединение:

git remote add repository_remote https://github.com/USER/REPOSITORY.git

Либо же мы могли получить к нему доступ через SSH:

git remote add repository_remote git@github.com:USER/REPOSITORY.git

В этом случае предварительно выполняется генерация SSH-ключа:

ssh-keygen -t rsa -b 4096 -C "GITHUB_ACCOUNT_EMAIL"

При этом публичный ключ (.pub), появившийся в каталоге /.ssh/known_hosts/, копируется в настройки аккаунта GitHub в раздел SSH Keys.

В нашем случае удаленным репозиторием выступит Nginx:

git remote add repository_remote https://github.com/nginx/nginx

Загрузка файлов из удаленной ветки

После добавления удаленного репозитория можно посмотреть список всех его веток:

git remote show repository_remote

Image1

Перед переключением на удаленную ветку нужно сперва извлечь подробную информацию об удаленном репозитории — ветки и теги:

git fetch repository_remote

Можно также указать сразу все удаленные репозитории:

git fetch --all

Теперь мы можем напрямую переключиться на удаленную ветку, получив ее файлы в рабочий каталог:

git checkout branches/stable-0.5

При этом в более старых версиях Git приходилось явно указывать название удаленного репозитория:

git checkout repository_remote/branches/stable-0.5

Теперь, если выполнить команду:

git branch

Можно увидеть указанную удаленную ветку в статусе активной:

* branches/stable-0.5
  feature2
  feature1
  master

Проверим состояние рабочего каталога:

ls

Теперь в нем присутствуют следующие каталоги:

auto  conf  contrib  docs  misc  src

Удаленную ветку, ровно как и локальную, можно удалить. Для этого ее сперва нужно сделать неактивной:

git checkout master

После чего выполнить само удаление:

git branch -D branches/stable-0.5

Теперь список веток проекта станет, как прежде:

  feature2
 feature1
* master

11. Переключение на коммит

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

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

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

git checkout feature2

Чтобы переключиться на конкретный коммит, вместо имени ветки в checkout указывается хеш (ID) коммита:

git checkout fb1b1616c85c258f647df4137df535df5ac17d6c

Чтобы узнать хэш, можно воспользоваться командой:

git log

В нашем случае история коммитов выглядит примерно так — отличаться могут только хэши:

commit fb1b1616c85c258f647df4137df535df5ac17d6c (HEAD -> feature2, feature1)
Author: root <root@2450302-yn55665.twc1.net>
Date:   Tue Feb 13 02:18:02 2024 +0300

    Commit from feature1

commit 24c65ffab574a5e478061034137298ca2ce33c94 (master)
Author: root <root@2450302-yn55665.twc1.net>
Date:   Mon Feb 12 23:30:56 2024 +0300

    First commit

После переключения на коммит можно посмотреть, какая ветка является активной:

git branch

Теперь список веток приобрел следующий вид:

* (HEAD detached at fb1b1616c)
  feature2
  feature1
  master

Эта манипуляция приводит к состоянию отсоединенного указателя HEAD («detached HEAD»). Таким образом, все последующий коммиты не будут принадлежать ни одной из существующих веток.

Однако такой режим небезопасен — отсутствие конкретной ветки в указателе HEAD может привести к потере данных.

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

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

Отличие checkout от switch

В более поздних версиях (2.23 и выше) Git есть другая команда для работы с ветками — switch.

Эти команды довольно похожи, однако switch является более специализированным вариантом:

  • git switch — новая команда, которая в большей степени ориентирована на работу с ветками. Напротив, git checkout — старая команда, которая способна делать и другие «периферийные» задачи. Например, создавать новые в ветки в момент переключения или изменять содержимое рабочего каталога до состояние конкретного коммита.

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

Заключение

В этом небольшом руководстве мы подробно рассказали о том, что делает команда git checkout, основная функция которой — переключение между отдельными ветками репозитория.

Вот полный список функций, которые выполняет команда checkout:

  • Переключение между существующими локальными ветками

  • Создание новых локальных веток

  • Создание новых локальных веток на основе других веток

  • Сброс существующих локальных веток до состояния других веток

  • Переключение между существующими удаленными ветками (и загрузкой их файлов в рабочий каталог)

  • Переключение на конкретный коммит из локальной или удаленной ветки

После переключения на другую ветку, как правило, продолжается использование таких команд, как git add и git commit для индексации изменений и обновления состояния репозитория конкретно в этой ветке.

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

Больше информации о работе с Git можно найти в наших инструкциях и в официальной документации.

29 февраля 2024 г.
1343
12 минут чтения
Средний рейтинг статьи: 5
Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server