|

Волшебные файлы Git

Оригинал: Git’s Magic Files by Andrew Nesbitt.

Продолжение моего поста о расширении функциональности Git. Git ищет в вашем репозитории несколько специальных файлов, которые управляют его поведением. Это не файлы конфигурации в .git/, а зафиксированные файлы, которые перемещаются вместе с вашим кодом и влияют на то, как Git обрабатывает ваши файлы.

Если вы разрабатываете инструмент для работы с репозиториями git, например git-pkgs, вам нужно убедиться, что вы соблюдаете эти настройки.

.gitignore

Шаблоны файлов, которые git не должен отслеживать. Один шаблон на строку, поддерживает подстановочные знаки и маркеры каталогов.

node_modules/
*.log
.env
dist/

Git последовательно проверяет несколько файлов игнорирования: .gitignore в каждом каталоге, .git/info/exclude для локальных игнорируемых файлов и глобальный файл игнорирования по адресу ~/.config/git/ignore или в любом другом месте, куда указывает core.excludesFile . Глобальные игнорируемые файлы подходят для файлов, специфичных для конкретной операционной системы, таких как .DS_Store или Thumbs.db, которые не должны загромождать .gitignore.

Сопоставление с образцом поддерживает подстановочные знаки (*.log), маркеры каталогов (dist/), отрицание (!important.log), а также диапазоны символов. Шаблон ** соответствует вложенным каталогам.

.gitignore влияет только на неотслеживаемые файлы. Файлы, которые уже отслеживались до добавления в .gitignore, остаются в репозитории и отображаются в веб-интерфейсе каждого форджа в обычном режиме (git rm --cached удаляет их из списка отслеживаемых файлов). Веб-редакторы GitHub, GitLab, Forgejo и Gitea также позволяют создавать файлы, соответствующие шаблону игнорирования, и фиксировать их без каких-либо предупреждений. Менеджеры пакетов часто поставляются с собственными шаблонами игнорирования (node_modules/, vendor/, target/), которые нужно добавить в файл игнорирования.

Полный синтаксис шаблона см. в документации по .gitignore. GitHub поддерживает коллекцию шаблонов .gitignore для разных языков и фреймворков.

.gitattributes

Указывает git, как обрабатывать определенные файлы. Здесь вы настраиваете фильтры, драйверы сравнения, драйверы слияния, нормализацию окончания строк и переопределения для определения языка.

# Clean/smudge filters
*.psd filter=lfs diff=lfs merge=lfs

# Line ending normalization
*.sh text eol=lf
*.bat text eol=crlf

# Treat as binary
*.png binary

# Custom diff driver
*.json diff=json

# Merge strategy
package-lock.json merge=ours

# Language detection override for GitHub Linguist
vendor/* linguist-vendored
*.gen.go linguist-generated
docs/* linguist-documentation

Атрибут text указывает git на необходимость нормализации окончаний строк. Атрибут binary указывает git не выполнять сравнение или слияние, а просто выбрать одну из версий. Стратегия merge=ours всегда сохраняет вашу версию при возникновении конфликтов при слиянии.

GitHub Linguist считывает .gitattributes для переопределения определения языка. Помечайте продакшн-код как linguist-vendored, чтобы исключить его из языковой статистики. Помечайте сгенерированные файлы как linguist-generated, чтобы они не отображались в сравнениях. Помечайте документацию как linguist-documentation, чтобы исключить ее из статистики.

Как и .gitignore, git проверяет .gitattributes файлов в каждом каталоге и .git/info/attributes на наличие атрибутов, доступных только на локальном уровне.

Документация по gitattributes содержит информацию обо всех атрибутах. В документации GitHub Linguist перечислены конкретные атрибуты.

.lfsconfig

Конфигурация Git LFS, которая переносится вместе с репозиторием. Использует формат git config для установки URL-адреса конечной точки LFS, параметров передачи и других параметров LFS.

[lfs]
    url = https://lfs.example.com/repo
[lfs "transfer"]
    maxretries = 3

Git LFS автоматически считывает .lfsconfig при выполнении команд LFS. Это позволяет зафиксировать конфигурацию LFS, чтобы все, кто работает с репозиторием, использовали одни и те же настройки. Без этого разработчикам приходилось вручную настраивать локальную конфигурацию LFS.

LFS также использует .gitattributes для обозначения файлов, которые должны обрабатываться с помощью LFS (шаблон *.psd filter=lfs diff=lfs merge=lfs показан выше). Файл .lfsconfig содержит настройки, специфичные для LFS, например информацию о том, где находится сервер LFS. Если вы добавляете шаблоны файлов в LFS после того, как файлы уже зафиксированы, вам нужно запустить git lfs migrate для перезаписи истории и перемещения этих файлов в LFS.

Все доступные параметры описаны в документации по настройке Git LFS.

.gitmodules

Конфигурация для подмодулей git. Git создает этот файл при выполнении команды git submodule add и считывает его при выполнении команды git submodule update.

[submodule "vendor/lib"]
    path = vendor/lib
    url = https://github.com/example/lib.git
    branch = main

Для каждого подмодуля указывается путь, URL и, при необходимости, ветка для отслеживания. Файл находится в корневом каталоге вашего репозитория.

Подмодули позволяют встраивать другие репозитории Git в качестве зависимостей. При выполнении git clone содержимое подмодулей не загружается автоматически, вам нужно выполнить git submodule update --init --recursive или передать --recurse-submodules в команду клонирования.

Они плохо работают с управлением версиями (вы отслеживаете конкретный коммит, а не диапазон версий), создают вложенные .git-каталоги, и если их не обновлять, это приводит к путанице.

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

В документации по подмодулям git описан весь рабочий процесс. В документации по gitmodules рассказывается о формате файлов.

.mailmap

Сопоставляет имена авторов и адреса электронной почты с каноническими идентификаторами. Git использует это для git log, git shortlog и git blame вывода.

# Map old email to new email
Jane Developer <jane@company.com> <jane@oldcompany.com>

# Standardize name spelling
Jane Developer <jane@company.com> Jane Dev <jane@company.com>

# Fix both
Jane Developer <jane@company.com> <janed@personal.com>
Jane Developer <jane@company.com> J Developer <janed@personal.com>

Формат: Proper Name <proper@email.com> Commit Name <commit@email.com>. Git ищет записи, соответствующие автору коммита, и перезаписывает результат.

git shortlog -sn, git log и git blame используют mailmap для объединения коммитов по каноническим идентификаторам. Контрибьюторы GitHub этого не делают, а значит, в сети сохраняются дубликаты записей, даже если ваша mailmap настроена правильно.

Без функции mailmap участники, которые меняли адреса электронной почты или исправляли опечатки в своих именах, отображаются как несколько разных людей. С этой функцией все их коммиты объединяются под одним именем.

Документация по gitmailmap описывает формат файла. Вы можете поместить файл mailmap в .mailmap в корневом каталоге репозитория или настроить mailmap.file так, чтобы он указывал на другое место.

.git-blame-ignore-revs

Перечисляет коммиты, которые git blame следует пропустить. Укажите в этом файле SHA коммитов с массовыми изменениями форматирования, проверками линтинга или другими незначительными изменениями, и blame просмотрит их, чтобы найти значимые изменения.

# .git-blame-ignore-revs
# Ran prettier on entire codebase
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

# Migrated to ESLint flat config
b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1

Настройте git для использования этого файла с помощью git config blame.ignoreRevsFile .git-blame-ignore-revs. GitHub, GitLab (15.4+) и Gitea автоматически считывают этот файл без дополнительной настройки. Если вы укажете это в глобальной конфигурации git, git blame не будет работать в любом репозитории, где нет этого файла, поэтому вам нужно либо настроить его для каждого репозитория отдельно, либо оставить .git-blame-ignore-revs пустым в каждом репозитории, с которым вы работаете.

Это решает проблему, из-за которой форматирование всей кодовой базы с помощью git blame становится бесполезным. Благодаря этому файлу blame пропускает такие коммиты и показывает реального автора логики.

Формат файла прост: один SHA коммита в строке, # для комментариев. Подробнее см. в документации по git blame.

.gitmessage

Шаблон для сообщений о коммитах. Вы настраиваете его с помощью git config commit.template .gitmessage, и git предварительно заполняет этим содержимым редактор сообщений о коммитах.

# .gitmessage
# 
<type>: <subject>
#
# 
<body>
#
# 
<footer>
#
# Types: feat, fix, docs, style, refactor, test, chore

В отличие от других файлов, описанных в этом посте, .gitmessage требует ручной настройки для каждого клона. Каждому разработчику нужно запустить git config commit.template .gitmessage после клонирования. Некоторые команды автоматизируют этот процесс с помощью скрипта настройки или используют такие инструменты, как husky, для установки локальных конфигураций во время установки. Из-за этого дополнительного шага в большинстве проектов для проверки формата используются commit-msg хуки, а не шаблоны для написания кода.

В документации по git commit упоминаются файлы шаблонов. Перехватчик prepare-commit-msg — это альтернатива, которая позволяет генерировать динамические шаблоны.

Forge-Specific Folders

Git-форджи расширяют репозитории с помощью собственных волшебных папок: .github/, .gitlab/, .gitea/, .forgejo/, .bitbucket/. Это не функции git, но они работают по тому же принципу: конфигурация переносится вместе с кодом.

В этих папках вы найдете рабочие процессы CI/CD, шаблоны для задач и PR, файлы CODEOWNERS, в которых указаны пути к необходимым рецензентам, а также другие настройки, специфичные для Forge. Папки позволяют разработчикам добавлять функции, не засоряя корневую папку репозитория.

У Forgejo и Gitea есть резервные цепочки. Forgejo проверяет .forgejo/.gitea/.github/. Gitea проверяет .gitea/.github/. Это позволяет переопределить конфигурацию GitHub при размещении на нескольких платформах.

SourceHut использует .build.yml в корневом каталоге или .builds/*.yml для непрерывной интеграции без выделенного пространства имен папок.

Другие соглашения

.gitkeep — это соглашение, а не функция git. Git не отслеживает пустые каталоги. Если вы хотите, чтобы в вашем репозитории был пустой каталог, поместите в него файл .gitkeep, чтобы git было что отслеживать. Имя файла .gitkeep может быть любым.

.gitconfig с предлагаемой конфигурацией. Git не загружает их автоматически (из соображений безопасности), но в проектах они есть, и к ним прилагаются инструкции по запуску git config include.path ../.gitconfig или ручному копированию настроек. Такие файлы часто встречаются в монорепозиториях или проектах со специфическими настройками Git, которые необходимо стандартизировать.

.gitsigners или аналогичные файлы содержат ключи для подписи GPG/SSH, которые используются доверенными участниками. Это не встроенная функция git, но она используется в некоторых проектах (в частности, в ядре Linux) в рамках процесса подписания. В gpg.ssh.allowedSignersFile конфигурации git можно указать файл с доверенными SSH-ключами, которые git log --show-signature используются для проверки.

.gitreview настраивает интеграцию Gerrit для проверки кода. Используется в проектах, размещенных на Gerrit (OpenStack, Android, Eclipse), для указания сервера Gerrit и проекта, на который нужно отправить изменения.

[gerrit]
host=review.opendev.org
port=29418
project=openstack/nova.git
defaultbranch=master

При запуске git review этот файл считывается, и коммиты отправляются на проверку в Gerrit, а не напрямую в ветку. Это классический пример инструмента, расширяющего рабочий процесс git с помощью зафиксированного конфигурационного файла.

.gitlint настраивает gitlint для проверки сообщений о коммитах. Работает по тому же принципу: коммитируем конфигурацию, и все пользуются одними и теми же правилами.

[general]
ignore=body-is-missing

[title-max-length]
line-length=72

Gitlint считывает это значение для проверки формата сообщения о коммите. Аналогично использованию commit-msg хука, но с конфигурацией, которая хранится в репозитории.

.jj/ — это каталог состояния рабочей копии Jujutsu. Jujutsu — это git-совместимый VCS, который хранит свои собственные метаданные в .jj/, сохраняя при этом все волшебные файлы git. Если вы используете jj, у вас будут оба .git/ и .jj/ в вашем репозитории, и .gitignore, .gitattributes, .mailmap все работают одинаково.

За пределами Git

Этот шаблон применим не только к git. Другие инструменты используют тот же подход: добавьте в репозиторий файл dotfile, инструменты автоматически его обнаружат, и их поведение изменится.

.editorconfig стандартизирует поведение редакторов в разных командах. Поместите этот файл в корневую папку вашего репозитория, и редакторы будут использовать его для настройки стиля отступов, окончания строк, пробелов в конце строк и кодировки символов.

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

VS Code, Vim, Emacs, Sublime и большинство других редакторов либо поддерживают его изначально, либо имеют плагины. Полную спецификацию см. на editorconfig.org.

.ruby-version, .node-version, .python-version сообщают менеджерам версий, какую версию языка использовать. Такие инструменты, как rbenv, nodenv, pyenv, nvm и asdf, считывают эти файлы, когда вы cd заходите в каталог, и автоматически переключают версии.

# .ruby-version
3.3.0

# .node-version
20.11.0

.tool-versions — это файл с многоязычными версиями asdf. Один файл для всех языков.

ruby 3.3.0
nodejs 20.11.0
python 3.12.0

.dockerignore работает так же, как .gitignore но для контекста сборки Docker. При запуске docker build Docker отправляет файлы в демон. Укажите шаблоны в .dockerignore, и Docker их не отправит.

.git
node_modules
*.log
.env

Это ускоряет сборку и защищает образы от несанкционированного доступа. Синтаксис соответствует .gitignore: подстановочные знаки, отрицание, маркеры каталогов.

Поддержка этих файлов

Если вы создаете инструменты, которые взаимодействуют с репозиториями git, вам, вероятно, стоит обратить внимание на эти файлы:

  • Прочтите .gitignore при обходе дерева репозитория
  • Прочтите .gitattributes о том, какие файлы являются бинарными, поставляются в виде вендорных пакетов или генерируются автоматически
  • При отображении информации об авторе читайте .mailmap
  • Читайте .gitmodules о том, как работать с подмодулями

Формат git config (используется в .gitmodules и других файлах) — [section "subsection"] key = value. В Git есть команда git config, которая корректно считывает и записывает эти файлы. В библиотеках Git для большинства языков есть парсеры git config.

Похожие записи