Автор статьи Скотт Чакон — сооснователь GitHub и основатель нового клиента GitButler. Этот клиент ставит во главу угла рабочий процесс и удобство разработки, в том числе код-ревью, и не является просто очередной обёрткой над CLI git.
В первом посте из этой короткой серии по Git я хотел начать с вещей, уже существующих какое-то время. При этом кажется, что многие люди о них не знают или не умеют ими пользоваться. В них нет ничего нового, но я нахожу их полезными и, возможно, не совсем освещёнными. Я просто хочу рассказать о:
- условной конфигурации;
- git blame и git log с диапазонами строк;
- git blame с отслеживанием;
- git diff по словам вместо строк;
- запоминании разрешения конфликтов.
Условная конфигурация
Многие из вас, вероятно, знают, что в Git есть маленькое классное хранилище «ключ-значение», вызываемое командой git config. Его значения, которые подставляются при выполнении различных команд, Git проверяет в трёх местах.
Наверное, каждого пользователя Git при первой настройке попросили запустить что-то такое:
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
Команда добавляет значение user.name в файл ~/.gitconfig. Но также есть другие опции:
- --system, которой, возможно, никто не пользовался. Она записывает значение в общесистемный конфигурационный файл [прим. перев. — речь идёт о $(prefix)/etc/gitconfig];
- --local — по умолчанию. Она записывает значение в .git/config любого проекта, где вы находитесь прямо сейчас.
В поиске значения Git смотрит в таком порядке:
- локальное;
- глобальное;
- системное.
Однако есть секретное четвёртое место, которое Git может посмотреть. Если вы добавите в свою глобальную конфигурацию что-то примерно такое:
[includeIf "gitdir:~/projects/oss"]
path = ~/.gitconfig-oss
Git поищет значение в ~/.gitconfig-oss, только если проект, с которым вы сейчас работаете, находится в ~/projects/oss.
Итак, у вас могли бы быть:
- каталог work со значениями, относящимися к конкретной работе (адрес электронной почты в компании, ключ GPG-подписи и т. д.);
- каталог oss со значениями для проектов с открытым исходным кодом и т. д.
Но gitdir — не единственный фильтр:
- через hasconfig: remote.*.url можно включать файлы конфигурации, только если у текущего проекта есть удалённый сервер с определёнными URL.
Так что ставьте лайк, если у вас есть ключи для GitHub.org или что-то в этом роде. Подробности читайте в документации.
git blame и git log с диапазонами строк
Есть пара интересных опций git blame, о которых большинство людей не знают, а в существующих GUI они почти не реализованы.
Одна из них -L — диапазон строк. Если вы запускаете git blame в CLI, часто вы просто просматриваете весь файл и находите ту часть, которую ищете. Но если вы хотите отобразить только подраздел файла, то можно задать диапазон строк, например git blame -L 28,43 путь/к/файлу:
Чтобы дать Git шаблон для поиска начала блока и выполнить git blame только для этого блока, можно воспользоваться синтаксисом :. Так, в той же ситуации я могу получить такой же вывод, выполнив git blame -L : 'class LocalFile' gitbutler-ui/src/lib/vbranches/types.ts. Вместо 'class LocalFile' можно подставить имя функции или что-то ещё.
Другая вещь, которую можно сделать, чтобы увидеть похожую информацию по-другому, — запустить git log с похожими параметрами. Это даст вам все коммиты, которые в последний раз касались заданной области файла.
Например, git log -L28,43:gitbutler-ui/src/lib/vbranches/types.ts даст вам что-то вроде этого:
Вместо упорядочивания по строкам, опция -L как будто собирает все коммиты git blame, а затем показывает коммиты с кодом, в каждом из которых менялся заданный блок. В основном это те же данные, но в другом формате, больше похожем на рассказ, как этот код собирался воедино.
git blame с отслеживанием
Одна на самом деле не очень хорошая штука в работе с blame через GUI заключается в том, что CLI обладает гораздо более мощными инструментами, чтобы найти что-то ближе к реальной истории, стоящей за вашим кодом. Есть много ситуаций, где это действительно ценно.
Первая — игнорирование изменений пробелов. Некоторые GUI игнорируют их, но не все. Если вы просто пойдёте и внедрите файл prettierrc — бах, теперь вы владелец тонны строк кода. С опцией git blame -w эти типы изменений пробельных символов игнорируются.
Другая отличная опция, которая отслеживает перемещение кода между файлами в коммите, — это-C. Когда вы выполните рефакторинг функции из одного файла в другой, обычная команда git blame просто покажет вас как автора нового файла, но опция -C отследит движение кода и покажет последнего, кто изменил строки.
Любые из этих данных могут оказаться тем, что вы ищете, но я бы сказал, чаще всего возникает последняя ситуация. Если вы хотите, чтобы Git старался ещё усерднее (ищите движение в нескольких или во всех коммитах), то можете указать опцию -C до трёх раз.
Кроме того, ваш GUI не делает этого (скорее всего, я не могу говорить обо всех). Давайте посмотрим на вывод git blame из предыдущего примера в GitLens VS Code:
Ок, выглядит хорошо. Большую часть этого кода, кажется, написал Кирил. Теперь давайте посмотрим на тот же блок с git blame -w -C -C -C:
Git следовал за этим куском кода от файла к файлу в течение нескольких переименований.
Кроме того, Кирил на самом деле владеет всего несколькими строками, большие его куски на самом деле написал Маттиас. Если захочется разузнать о них, гораздо лучше спросить Маттиаса, а не Кирила, как предполагает наш GUI.
git diff по словам вместо строк
Это невероятно вторично, а в некоторых графических интерфейсах есть приятные версии. Я нахожу GitHub лучше того, что собираюсь показать, ведь он аккуратно выполняет команду в GUI и в CLI. Но если вы запускаете git diff в CLI для строки с небольшим изменением, то можете изменить формат Git по умолчанию на слова, а не на строки, опцией--word-diff:
Память о разрешении конфликта
Наконец, если вы часто выполняете git rebase или git cherry-pick и сталкиваетесь с одним и тем же конфликтом чаще одного раза, то можно включить функцию запоминания и разрешения конфликта. Если Git дважды и более раз увидит один и тот же конфликт, то решит его автоматически.
Эту функцию можно легко включить настройкой конфигурации rerere.enabled. Далее можно попросить Git настроить для вас автоматический стейджинг через rerere.autoUpdate:
git config --global rerere.enabled true
git config --global rerere.autoUpdate true
Затем, в следующий раз, когда вы столкнётесь с конфликтом, который решали раньше, — магия!
Что дальше?
Опять же, всё это уже давно есть в Git, но если вы чего-то не знали, то теперь знаете. Далее — новые штуки в Git.