Найти тему

Итак, вы думаете, что знаете Git? Часть первая: старый добрый Git

Оглавление

Автор статьи Скотт Чакон — сооснователь 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 — не единственный фильтр:

  • через onbranch как включающий фильтр можно указать определённые названия ветки;
  • через hasconfig: remote.*.url можно включать файлы конфигурации, только если у текущего проекта есть удалённый сервер с определёнными URL.

Так что ставьте лайк, если у вас есть ключи для GitHub.org или что-то в этом роде. Подробности читайте в документации.

git blame и git log с диапазонами строк

Есть пара интересных опций git blame, о которых большинство людей не знают, а в существующих GUI они почти не реализованы.

Одна из них -L — диапазон строк. Если вы запускаете git blame в CLI, часто вы просто просматриваете весь файл и находите ту часть, которую ищете. Но если вы хотите отобразить только подраздел файла, то можно задать диапазон строк, например git blame -L 28,43 путь/к/файлу:


git blame -L
git blame -L

Чтобы дать 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 даст вам что-то вроде этого:

git log -L28,43:gitbutler-ui/src/lib/vbranches/types.ts
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 в плагине VS Code GitLens
git blame в плагине VS Code GitLens

Ок, выглядит хорошо. Большую часть этого кода, кажется, написал Кирил. Теперь давайте посмотрим на тот же блок с git blame -w -C -C -C:

git blame -C -C -C
git blame -C -C -C

Git следовал за этим куском кода от файла к файлу в течение нескольких переименований.

Кроме того, Кирил на самом деле владеет всего несколькими строками, большие его куски на самом деле написал Маттиас. Если захочется разузнать о них, гораздо лучше спросить Маттиаса, а не Кирила, как предполагает наш GUI.

git diff по словам вместо строк

Это невероятно вторично, а в некоторых графических интерфейсах есть приятные версии. Я нахожу GitHub лучше того, что собираюсь показать, ведь он аккуратно выполняет команду в GUI и в CLI. Но если вы запускаете git diff в CLI для строки с небольшим изменением, то можете изменить формат Git по умолчанию на слова, а не на строки, опцией--word-diff:

Нормальный, построчный git diff
Нормальный, построчный git diff
Особенно крутой git diff --word-diff
Особенно крутой git diff --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 навсегда запомнил конфликт

Затем, в следующий раз, когда вы столкнётесь с конфликтом, который решали раньше, — магия!

Автоматическое исправление
Автоматическое исправление

Что дальше?

Опять же, всё это уже давно есть в Git, но если вы чего-то не знали, то теперь знаете. Далее — новые штуки в Git.

Автор оригинала: Scott Chacon