Все мы - инженеры-программисты - используем git каждый день, однако большинство людей затрагивают только самые основные команды, такие как add, commit, push или pull, как будто это все еще 2005 год.

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

Switch

Новое с 2019 года, или точнее, введено в версии Git 2.23, это git switch, которое мы можем использовать для переключения веток:

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 у нас есть только 3 файла, а не все дерево. Чтобы затем загрузить/выполнить checkout определенного каталога, мы используем git sparse-checkout set ….

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

Рабочее дерево (Worktree)

Не редко случается, что одному и тому же приложению (репозиторию) приходится работать над несколькими функциями одновременно, или, возможно, поступает критическая ошибка, пока вы работаете над некоторым запросом на функцию.

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

git branch
# * dev
# master

git worktree list
# /.../some-repo  ews5ger [dev]

git worktree add -b hotfix ./hotfix master

# Подготовка рабочего дерева (новая ветка 'hotfix')
# HEAD теперь на 5ea9faa Signed commit.

git worktree list
# /.../test-repo         ews5ger [dev]
# /.../test-repo/hotfix  5ea9faa [hotfix]

cd hotfix/  # Чистое рабочее дерево, где вы можете внести свои изменения и отправить их

Эта команда позволяет нам иметь несколько ветвей одного и того же репозитория, проверенных одновременно. В приведенном выше примере у нас есть 2 ветки 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  # Укажите коммит, который, как вы знаете, работает
# Bisecting: 2 revisions left to test after this (roughly 1 step)
# [3258487215718444a6148439fa8476e8e7bd49c8] Refactoring.

# Протестируйте текущий коммит...
git bisect bad  # Если коммит не работает
git bisect good # Если коммит работает

# Git выполняет бисекцию левой или правой половины диапазона на основе последней команды
# Продолжайте тестирование, пока не найдете виновника

git bisect reset  # Сбросить на исходный коммит

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

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

Заключение

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


Автор: Мартин Хейнз