Git кунг-фу

Ты познакомился с системой контроля версий Git. Умеешь клонировать репозитории, фиксировать изменения, использовать локальные ветки. Но как работать эффективнее и быстрее?

Вообще с Git'ом я предпочитаю работать в консоли по следующим причинам: портативность, сложность GUI клиентов или их отсутствие (при работе на сервере), в командной строке некоторые вещи делаются просто быстрее. Начинаем:

  • ускоряемся. Псевдонимы (aliases) в Git.

  • всё пропало. Восстановление утерянных коммитов.

  • бонус. Настройка терминала.

Псевдонимы (aliases) в Git

Я часто делаю опечатки, когда ввожу в Git длинные команды с параметрами. Поэтому использую псевдонимы (aliases) для тех команд, которые использую постоянно. Чтобы проще создавать псевдонимы, у меня тоже есть псевдоним:

git config --global alias.gconfig "config --global"

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

Так как я использую тайлинговый оконный менеджер awesome, то вызов gitk для просмотра истории ломает расположение окон. Поэтому я использую следующий псевдоним:

$ git gconfig alias.lg "log --graph --decorate --pretty=oneline --abbrev-commit --all"

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

$ git gconfig alias.cia "commit --amend -C HEAD"

При работе с тематическими ветками я рекомендую два следующих псевдонима:

$ git gconfig alias.wip \!"git add -A; git ls-files --deleted -z | xargs -0 -I {} git rm {}; git commit -m \"wip\""

$ git gconfig alias.unwip \!"git log -n 1 | grep -q -c wip && git reset HEAD~1"

Если мне необходимо быстро переключиться на другую ветку, я выполняю git wip. Git зафиксирует все изменения в коммите под названием “wip”. Когда я хочу продолжить работу дальше, то я ввожу команду git unwip. Похожую функциональность предлагает git stash, только он не создает явные коммиты и спрятанные изменения видны из любой ветки.

Желающие посмотреть на мой gitconfig целиком, могут увидеть его на Гитхаб.

Восстановление утерянных коммитов

Работая в локальных тематических ветках, можно нечаянно потерять коммит: например, жёстко сбросить ветку назад. Изменения еще не были отправлены на сервер, время паниковать? Нет.

Git записывает все изменения HEAD. Команда git reflog покажет их в хронологическом порядке. В моём репозитории для сайта это выглядит так:

4fd0b53 HEAD@{0}: commit (amend): Enhance paragraph 'Git aliases'
c3c9571 HEAD@{1}: merge recover: Fast-forward
54c9dae HEAD@{2}: reset: moving to HEAD~1
73795a8 HEAD@{3}: checkout: moving from recover to git-kung-fu
c3c9571 HEAD@{4}: checkout: moving from git-kung-fu to recover
73795a8 HEAD@{5}: checkout: moving from recover to git-kung-fu
c3c9571 HEAD@{6}: commit: Enhance paragraph 'Git aliases'
...

С помощью команды git show <commit hash> можно посмотреть, является ли искомый коммит нужным. Теперь можно создать временную ветку, указывающую на него, и слить её с основной тематической веткой.

Например, если бы я “потерял” коммит с хэшем c3c9571, то процесс восстановления выглядел бы следующим образом:

$ git branch recover c3c9571
$ git merge --ff recover
...
# после успешного слияния можно удалить вспомогательную ветку
...
$ git branch -d recover

Всегда используйте reflog, если хотите разобраться в том, что случилось с репозиторием.

Настройка терминала

О том, что существует переменная __git_ps1 для отображения имени ветки в консоли, знают многие. О том, что вывод можно сделать более информативным с помощью GIT_PS1_SHOWDIRTYSTATE и GIT_PS1_SHOWSTASHSTATE знают не все.

Сам же я использую костыль, подсмотренный на Хабре: отображаю название ветки зелёным, если репозиторий чист; иначе красным. Раньше парсил измененные, добавленные и удалённые файлы, но потом понял, что меня это только отвлекает. Кому интересен мой .bashrc, могут найти его в моём репозитории. Выглядит это так.

Удачи всем на пути к становлению мастером Git кунг-фу!