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

Автор оригинала Скотт Чакон — сооснователь GitHub и основатель нового клиента GitButler. Этот клиент ставит во главу угла рабочий процесс и удобство разработки, в том числе код-ревью, и не является просто очередной обёрткой над CLI git.

В первом посте из этой короткой серии по Git я хотел начать с вещей, уже существующих какое-то время. При этом кажется, что многие люди о них не знают или не умеют ими пользоваться. В них нет ничего нового, но я нахожу их полезными и, возможно, не совсем освещёнными. Я просто хочу рассказать о:



Условная конфигурация

Многие из вас, вероятно, знают, что в 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 путь/к/файлу:

6f1342c785f23ee9a4d406af0e545a2f.png
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 даст вам что-то вроде этого:

1ce29c312b89d66616da05a1a9a8cccf.png

Вместо упорядочивания по строкам, опция -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:
8f0654ec1aa7bb70904716b365a802ab.png
git blame в плагине VS Code GitLens

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

8a7e7de2f717739307c2cbba4bc8422b.png
git blame -C -C -C

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

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


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

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

b7c6d3a63782e355370b34068c6ce0b2.png
нормальный, построчный git diff

3dde6648ccec2a481a0f48fd105d6d8a.png
особенно крутой 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

8aa78c2296c71963a11808dd4ff5b2b9.png
Git навсегда запомнил конфликт

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


Что дальше?

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


Пока я оставляю ссылку на оригинальное продолжение. Дальше будет интереснее!

© Habrahabr.ru