[Перевод] Современные команды и фичи Git, которыми стоит пользоваться

3b64879f799e0181dec88e8fa4330c2e.png

Мы, разработчики ПО, пользуемся git каждый день, однако большинство из нас применяет только самые основные команды, например, add,  commit,  push и pull, как будто на дворе по-прежнему 2005 год.

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

Switch

git switch появившаяся в 2019 году, или, точнее, в версии Git 2.23, позволяет переключать ветви:

git switch other-branch
git switch -  # Переключение обратно на предыдудую ветвь, аналогично "cd -"
git switch remote-branch  # Непосредственное переключение на удалённую ветвь и её отслеживание

Это здорово, но мы уже давно можем переключать ветви в Git при помощи git checkout, зачем нужна отдельная команда?  git checkout — универсальная команда, она способна (среди прочего) выполнять проверку, восстанавливать конкретные файлы или даже конкретные коммиты, а новая git switch только переключает ветви. Кроме того,  switch выполняет дополнительные проверки работоспособности, не выполняемые checkout, например, switch прерывает операцию, если она приведёт к потере локальных изменений.

Restore

Ещё одна новая подкоманда/фича, добавленная в версии Git 2.23 — это git restore, которую можно использовать для восстановления файла до версии последнего коммита:

# Отмена внесённых в файл изменений, аналогично "git reset some-file.py"
git restore --staged some-file.py
# Отмена и сброс внесённых в файл изменений, аналогично "git checkout some-file.py"
git restore --staged --worktree some-file.py
# Откат файла к какому-то предыдущему коммиту, аналогично "git reset commit -- some-file.py"
git restore --source HEAD~2 some-file.py

Комментарии в приведённом выше примере объясняют работу различных вариантов git restore. В общем случае git restore заменяет и упрощает некоторые из способов использования слишком перегруженных фич git reset и git checkout. См. также сравнение revert,  restore иreset в этом разделе документации.

Sparse Checkout

Далее рассмотрим git sparse-checkout — чуть более сложную фичу, добавленную в Git 2.25, которая была выпущена 13 января 2020 года.

Допустим, у вас есть большой монорепозиторий, в котором микросервисы разбиты на отдельные папки; команды наподобие checkout и status из-за размера репозитория выполняются крайне медленно, но, возможно, вам на самом деле достаточно работать с одним поддеревом/папкой. Тогда на помощь придёт git sparse-checkout:

$ git clone --no-checkout https://github.com/derrickstolee/sparse-checkout-example
$ cd sparse-checkout-example
$ git sparse-checkout init --cone  # Конфигурируем git, чтобы он подбирал файлы только в корневой папке
$ git checkout main  # Checkout только файлов в корневой папке
$ ls
bootstrap.sh  LICENSE.md  README.md
$ git sparse-checkout set service/common
$ ls
bootstrap.sh  LICENSE.md  README.md  service
$ tree .
.
├── bootstrap.sh
├── LICENSE.md
├── README.md
└── service
├── common
│   ├── app.js
│   ├── Dockerfile
... ...

В приведённом выше примере мы сначала клонируем репозиторий без проверки всех файлов. Затем используем git sparse-checkout init --cone , чтобы сконфигурировать git так, чтобы он подбирал файлы только в корне репозитория. После выполнения checkout у нас будет только три файла, а не всё дерево. Чтобы затем скачать/выполнить checkout конкретной папки, мы используем git sparse-checkout set ....

Как уже говорилось, это может быть очень удобно при локальной работе с огромными репозиториями, но столь же полезно в CI/CD для повышения скорости работы конвейера, когда нам нужно только собрать/развернуть часть монорепозитория и нет необходимости проверять всё.

Подробное описание sparse-checkout представлено в статье.

Worktree

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

В таких случаях приходится или иметь несколько склонированных версий/ветвей репозитория, или приостанавливать/отменять работу над тем, что вы делаете в данный момент. Для решения таких проблем создали git worktree, выпущенную 24 сентября 2018 года:

git branch
# * dev
# master
git worktree list
# /.../some-repo  ews5ger [dev]
git worktree add -b hotfix ./hotfix master
# Подготовка рабочего дерева (нового "хотфикса" ветви)
# HEAD теперь находится на коммите, подписанном 5ea9faa.
git worktree list
# /.../test-repo         ews5ger [dev]
# /.../test-repo/hotfix  5ea9faa [hotfix]
cd hotfix/  # Чистое рабочее дерево, в котором можно вносить изменения и пушить их

Это позволяет нам одновременно выполнять checkout нескольких ветвей в одном репозитории. В примере выше у нас есть две ветви, dev и master. Допустим, мы работаем с фичей в ветви dev, но нас попросили срочно устранить баг. Вместо того, чтобы откладывать изменения и сбрасывать ветвь до исходной версии, мы создаём новое рабочее дерево в подпапке ./hotfix из ветви master. Затем можно перейти в эту папку, внести изменения, запушить их и вернуться к исходному рабочему дереву.

Более подробное описание можно прочитать в статье.

Bisect

git bisect, — не особо новая фича (Git 1.7.14, выпущенный 13 мая 2012 года), но большинство людей пользуется только фичами git , появившимися примерно в 2005 году, так что, думаю, её всё равно стоит показать.

На странице документации она описывается так:  git-bisect — использование двоичного поиска для поиска коммита, внёсшего баг:

git bisect start
git bisect bad HEAD  # Указываем поломанный коммит
git bisect good 479420e  # Указываем точно работающий коммит
# Деление пополам: после этого осталось протестировать 2 ревизии (приблизительно 1 этап)
# [3258487215718444a6148439fa8476e8e7bd49c8] Рефакторинг.
# Проверяем текущий коммит...
git bisect bad  # Если коммит не работает
git bisect good # Если коммит работает
# В зависимости от последней команды Git делит пополам левую или правую половину
# Продолжаем тестирование, пока не найдём виновника
git bisect reset  # Сброс до исходного коммита

Мы начинаем с запуска сессии деления пополам при помощи команды git bisect start, после которой мы указываем неработающий коммит (вероятнее всего, это HEAD) и последний работавший коммит или тэг. Имея эту информацию,  git выполняет check out коммита посередине между коммитами bad и good. В этой точке нам нужно протестировать, имеет ли эта версия баг; если версия работает, то мы должны использовать git bisect good, чтобы сказатьgit , что она работает, или git bisect bad, если нет. Мы продолжаем процесс, пока больше не останется коммитов и git не сообщит нам, в каком коммите возникла проблема.

Рекомендую изучить страницу документации, на которой есть ещё пара опций git bisect, в том числе визуализация, воспроизведение или пропуск коммитов.

Заключение

В поисках проблем, связанных с git, вы с наибольшей вероятностью наткнётесь на вопрос StackOverflow с ответом, имеющим пару тысяч голосов. Хотя этот ответ, вероятно, по-прежнему будет правильным, он вполне может оказаться устаревшим, потому что был написан десять лет назад. Уже может существовать более качественное, простое и удобное решение. Поэтому, если вы столкнётесь с проблемой с git, я рекомендую вам почитать в документации git о более новых командах, все они снабжены отличными примерами; или же изучить страницы man различных флагов и опций, добавленных за долгие годы разработки к старым добрым командам.

© Habrahabr.ru