
Вчера на Хабре вышла замечательная статья с очень красивым посылом – Know your tools. Но тема была практически не раскрыта. А особенно меня поразило то, как статью про костыли и базовые функции Гита, позитивно восприняло сообщество. Плюсы лились. Я же поставил заслуженный минус, пробежался по комментариям и нашёл из сотни всего 2 штуки, упоминающих то, о чём сегодня пойдёт речь.
Я предполагаю, что описанными в предыдущей статье приёмами разработчики и без того пользуются ежедневно. Но когда приходится иметь с чем-то дело так часто, невольно задумываешься об оптимизации. И общепринятой оптимизацией работы с Гитом является использования Zsh с плагинами.
Посплю сегодня поменьше, зато вы узнаете как работать с Гитом со скоростью ниндзя, пользуясь различными хаками, которые многие годы собирало и нарабатывало для нас сообщество.
Подготовка
В среде разработчиков стандартом альтернативы Bash является Zsh. А в среде пользователей Zsh стандартом является использование Oh-my-zsh. Таким образом, установив этот комплект, мы из коробки получим повышение продуктивности работы с консолью – в нашем случае с Гитом.
Самая большая фишка Zsh, что он есть и для Linux, и для Mac.
Устанавливаем Zsh и Oh-my-zsh по инструкции одной командой:
brew install zsh zsh-completions && sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"Поскольку задача – оптимизировать взаимодействие с Гитом, добавим к Zsh пару плагинов. Откройте файл ~/.zshrc и добавьте к списку plugins:
plugins=(git fastgit)Итого:
- git– набор алиасов и вспомогательных функци;
- fastgit– улучшенное автодополнение для Гита.
И последний штрих:
brew install tigО нём поговорим дальше.
Варианты использования
Разбираться с Гитом лучше всего на примерах решения конкретных задач. Далее рассмотрим задачи из ежедневной практики с вариантами удобного решения на примере некого репозитория с текстовыми файлами.
Создаём коммит
Начнём с самой базовой вещи – добавления коммита. Первым делом воспользуемся самой частой командой, которая поможет понять, что вообще происходит:
gsb # git status -sb
## master
 M b.md
?? d.mdАга, мы находимся в ветке master, изменили файл b.md и создали файл, который ещё не добавлен в индекс Гита. Коротко и ясно.
Добавляем все изменения в индекс:
gaa # git add --allПроверяем, что в индекс попало именно то, что нам нужно:
diff --git a/b.md b/b.md
index 698d533..cf20072 100644
--- a/b.md
+++ b/b.md
@@ -1,3 +1,3 @@
 # Beta
-Next step.
+Next step really hard.
diff --git a/d.md b/d.md
new file mode 100644
index 0000000..9e3752e
--- /dev/null
+++ b/d.md
@@ -0,0 +1,3 @@
+# Delta
+
+Body of article.Хм, в один коммит должны попадать изменения, решающие единственную задачу. Здесь же изменения обоих файлов никак не связаны между собой. Давайте пока исключим файл d.md из индекса:
gru d.md # git reset -- d.mdИ создадим коммит:
gcПишем название коммита и сохраняем. А следом создаём ещё один коммит для файла d.md:
gaa
gcmsg "Add new file"Здесь мы воспользовались алиасом для создания коммита вместе с названием в одну строчку.
А ещё мы можем...
… коммитить изменённые файлы из индекса одной командой:
gcam "Add changes" # git commit -a -m "Add changes"… смотреть изменения по словам вместо строк (очень полезно при работе с текстом):
gdw # git diff --word-diff… добавлять файлы по частям:
gapa # git add --patch… добавлять в индекс только файлы, уже находящиеся под наблюдением Гита:
gau # git add --updateИсправляем коммит
Название последнего коммита не объясняет сделанных нами изменений. Давайте переформулируем:
gc! # git commit -v --amendИ в открывшемся текстовом редакторе назовём его более понятно: "Add Delta article".
А ещё мы можем...
… более гибко пользоваться исправлением:
gcn! # git commit -v --no-edit --amend
gca! # git commit -v -a --amend
gcan! # git commit -v -a --no-edit --amend
gcans! # git commit -v -a -s --no-edit --amendНачинаем работать над новой фичей
Создаём новую ветку от текущей:
gcb erlangХотя нет, лучше напишем статью про Elixir:
gb -m elixir # git branch -m elixirВносим изменения в репозиторий и создаём коммит как уже умеем:
echo "# Elixir\nWunsh.ru – русскоязычное сообщество Эликсир-разработчиков." > e.md
gaa && gcmsg "Add article about Elixir and Wunsh.ru"Сливаем изменения
Теперь добавляем нашу новую статью об Эликсире в master. Сначала переключимся на основную ветку:
gcm # git checkout masterИ мерджим изменения:
gm elixir # git merge elixirУпс, а в master кто-то уже успел внести свои изменения. И вместо красивой линейной истории, которая принята у нас в проекте, создался ненавистный мердж-коммит.
Удаляем последний коммит
Ничего страшного! Нужно просто удалить последний коммит и попробовать слить изменения ещё раз.
git reset --hard HEAD~А вот и повод для контрибьюта в Zsh: никакого удобного сокращения для удаления последнего коммита не предусмотрено.
Решаем конфликты
Стандартная последовательность действий checkout – rebase – merge для подготовки линейной истории изменений выполняется следующими алиасами:
gco elixir # git checkout elixir
grb master # git rebase master
gcm # git checkout master
gm elixir # git merge elixirИ не забывайте, что можно дополнять названия веток клавишей Tab.
Отправка изменений на сервер
Сначала добавляем origin, а затем отправляем изменения напрямую в текущую ветку:
gra origin git@gitlab.com/...
ggpushВы также можете...
… отправить изменения на сервер с установкой upstream:
gpsup # git push --set-upstream origin $(git_current_branch)Получаем изменения с сервера
Работа кипит. Мы успели добавить новую статью f.md в master, а наши коллеги изменить статью a.md и отправить это изменение на сервер. Эта ситуация тоже решается очень просто:
gup # git pull --rebaseПосле чего можно спокойно отправлять изменения на сервер и никто никогда не узнает о нашем маленьком ребейзе.
Удаляем слитые ветки
Итак, мы успешно влили в master несколько веток, в том числе и ветку elixir из предшествующего примера. Они нам больше не нужны. Можно удалять:
gbda # git branch --no-color --merged | command grep -vE "^(\*|\s*(master|develop|dev)\s*$)" | command xargs -n 1 git branch -dОчень красивая и хитрая команда. Обычно я забываю очищать потерявшие актуальность ветки и эта изящная команда – настоящее спасение.
Создаём временный коммит
Работа над новой статьёй h.md про Haskell идёт полным ходом. Написана половина и нужно получить отзыв от коллеги. Недолго думая набираем:
gwip # git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify -m "--wip-- [skip ci]"И тут же создаётся коммит с названием Work in Progress, пропускающим CI и удаляющим "лишние" файлы.
Затем этот коммит можно отменить и вернуть файлы в исходное состояние:
gunwip # git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1А проверить, если в вашей ветке WIP-коммиты можно командой:
work_in_progressКоманда gwip – довольно надёжный аналог stash, когда нужно переключиться на соседнюю ветку. Но в Zsh есть много алиасов и для самого stash.
Прячем изменения
С этой командой нужно быть осторожным. Файлы можно спрятать, а затем неаккуратным действием удалить насовсем, благо есть reflog, в котором можно попытаться найти потерянные наработки.
Давайте спрячем файлы, над которыми работаем:
gsta # git stash saveА затем вернём их обратно:
gstp # git stash popИли более безопасным методом:
gstaa # git stash applyВы также можете ...
… посмотреть, что конкретно мы припрятали:
gsts # git stash show --text… воспользоваться сокращениями для связанных команд:
gstc # git stash clear
gstd # git stash drop
gstl # git stash listИщем баг
Инструмент git-bisect, который неоднократно спасал мне жизнь, тоже имеет свои алиасы. Начинаем с запуска процедуры "двоичного поиска ошибки" и сообщения Гиту о "плохом" коммите:
gbss && gbsbЗатем прыгаем на столько шагов, сколько будут гарантировать нам рабочее состояние приложения:
gco HEAD~20
gbsgА теперь остаётся продолжать отвечать на вопросы Гита фразами gbsb или gbsg, а после нахождения виновника сбросить процедуру:
gbsrИщем зачинщика беспредела
Даже с высоким процентом покрытия кода тестами, никто не застрахован от ситуации, когда приложение падает и любезно указывает на конкретную строчку с ошибкой. Или, например, в нашем случае мы хотим узнать, кто допустил ошибку во второй строчке файла a.md. Для этого выполните команду:
gbl a.md -L 2Сегодня к вечеру добавлю ещё несколько интересных алиасов и приёмов, которые пригодятся в ежедневном использовании Гита. Следите за обновлениями статьи.
Заключение
Не обязательно запоминать все описанные в статье команды. Запомните десяток основных. Уже их хватит, чтобы значительно оптимизировать процесс работы с Гитом. Остальные изучите ради интереса. Некоторые алиасы сделаны действительно очень нетривиально, но оказываются очень полезными на практике.
Также всегда полезно изучить профессионально подобранные команды Гита с ключами, которые не принято использовать при обычной работе с Гитом, но которые сильно упрощают работу и позволяют решить задачу точнее.
Теперь со спокойной совестью можно сказать: Know your tools. Конечно, если завтра кто-то не решит описать в третьей части свою версию эффективного использования Гита. А было бы интересно :)
Комментарии (7)
- Eldhenn31.08.2017 06:32+1- В ответ на статью о базовом использовании гита появилась статья о базовом использовании гита. Зато с zsh альясами!!!  - Lure_of_Chaos31.08.2017 07:08+2- Действительно. Не в обиду автору, но очень уж сие лицепредставление напоминает фаллометрию. 
 
 - Talkerbox31.08.2017 07:30+3- Кажется, статья описывает, как обмазать гит алиасами. И лишь немного дополняет тему самого Гита из предыдущей статьи. 
 - shybovycha31.08.2017 07:58+2- … более гибко пользоваться исправлением: 
 - gcn! # git commit -v --no-edit --amend gca! # git commit -v -a --amend gcan! # git commit -v -a --no-edit --amend gcans! # git commit -v -a -s --no-edit --amend
 - Что тут происходит? 
 - Вот сижу на работе, думаю, "дай посмотрю, может какие-то действительно интересные трюки найдутся", а тут — какой-то набор непонятных сокращений без внятных комментариев. 
 - shpaker31.08.2017 08:26+2- Какой-то ад буквенный. Не надо так. Возможно так и удобно пользоваться, но для туториала это как-то слишком за гранью. 
 
           
 
Druu
У ниндзи серьезные проблемы со скоростью печати, по-этому он использует невнятные однобуквенные сокращения? Особенно весело в этой одной букве ошибиться и сделать gstc вместо gsta.
Lure_of_Chaos
Но для начала придется хорошенько выучить эти алясы
и при этом не призвать демона.Не говоря уж о том, что в качестве подготовки нужно это все хозяйство доустанавливать. Это не проблема на домашнем компе,
имея черный пояспользуясь так н-ный год. Но вот если потребуется подшаманить где-нибудь через схху, вспомнит ли мозг,покалеченныйразбалованный алясами и прочими удобствами стандартные пути?