Атрибуты файлов
.gitattributes — самый полезный файл в git, который почти никто не пишет. Это
способ репозитория рассказать git о своём собственном содержимом: какие
файлы бинарные, какие надо склеивать вместо того, чтобы конфликтовать, какие
никогда не попадают в архив, какие переводы строк получает каждый.
Важная часть: он коммитится. Правило, которое вы добавили, чинит проблему для всех, кто клонирует, на любой ОС, навсегда — в отличие от настройки в вашем собственном конфиге, которая чинит её только вам, а коллеги узнают о ней трудным путём.
⌘K → Атрибуты файлов.

Что делают правила
| Атрибут | Что чинит |
|---|---|
text=auto eol=lf |
Переводы строк, которые скачут в зависимости от того, кто выгрузил файл |
binary |
Попытки git показать дифф или трёхсторонне смёржить PSD, DOCX, собранный ассет |
merge=union |
Changelog, в который дописывают все и на котором конфликтуют все |
-merge |
Файлы, где трёхстороннее слияние выдаёт бессмыслицу — лок-файлы, сгенерированный код |
export-ignore |
Конфиги CI и фикстуры, уехавшие внутри релизного тарбола |
diff=<driver> |
Нечитаемые диффы для форматов, которые читаемы, если дать конвертер |
filter=lfs |
Большие файлы, хранимые через LFS |
linguist-vendored |
Вендоренный код, засчитанный вам в языковой статистике |
binary — это сокращение для -diff -merge -text, то есть три ответа на «хватит
гадать про этот файл» одним словом.
Редактирование
Пресеты подставляют шаблон пути и его атрибуты; поправьте шаблон перед
добавлением — CHANGELOG.md здесь предложение, а не правило про ваш проект.
Правки хирургические. Добавление правила для шаблона, у которого правило уже есть, переписывает ту самую строку на её месте, а не дописывает второе правило, которое побеждает просто потому, что оно ниже. Комментарии в файле остаются нетронутыми, потому что «почему» рядом с правилом обычно стоит дороже самого правила.
Каждое сохранение — обычное действие Gitcito: оно показывает тост, а Отмена возвращает файл ровно в прежний вид.
У репозитория может быть несколько файлов атрибутов. Один в корне, по одному
в любом подкаталоге и приватный .git/info/attributes, который никогда не
коммитится и действует только на вашей машине — правильное место для правила,
которое про вас, а не про проект. Gitcito перечисляет их все и говорит, какой
есть какой.
Что применяется к пути?
Правила приходят из нескольких файлов, побеждает более специфичное, и читать их,
чтобы вывести ответ, — гадание. Что применяется к пути? запускает
git check-attr и показывает, к какому выводу приходит сам git — единственный
ответ, который имеет значение.
Драйверы диффа: как сделать документ Word читаемым
.docx — это zip. .pdf — сжатый граф объектов. Git показывает дифф по тому,
чем они являются — по шуму, — так что история документа нечитаема, хотя сам
документ вполне читаем.
Драйвер диффа решает это через textconv: команду, которая превращает файл в
текст только для диффа. Файл в вашем рабочем дереве не трогается; git просто
сравнивает сконвертированный текст.
Две половины, и нужны обе:
diff.<name>.textconvв конфиге git — команда-конвертер.*.docx diff=<name>в.gitattributes— к каким файлам она применяется.
Кнопки здесь делают и то и другое разом. Для Word, Excel, JSON и .strings Gitcito
поставляет конвертер сам — тот же разбор документов, которым пользуются
его предпросмотры, доступный как небольшая команда gitcito-textconv внутри
приложения, — так что эти четыре работают вовсе без установки. Остальным
по-прежнему нужен настоящий инструмент в вашем PATH: Gitcito проверяет и
показывает серым то, чего не хватает, вместо того чтобы записать драйвер,
который сломается на первом же диффе.
| Драйвер | Требует | Что даёт |
|---|---|---|
word |
ничего — поставляется с Gitcito | Диффы по тексту .docx |
excel |
ничего — поставляется с Gitcito | Построчные диффы (CSV на каждый лист) .xlsx/.xls |
json |
ничего — поставляется с Gitcito | Стабильные диффы JSON с сортировкой по ключам |
strings |
ничего — поставляется с Gitcito | Построчный diff .strings в UTF-16, который git называет двоичным |
pdf |
pdftotext (poppler) |
Текстовые диффы .pdf |
exif |
exiftool |
Что изменилось в изображении, когда пиксели непрозрачны |
Тот, что кусает iOS-проекты
Localizable.strings почти всю историю Xcode лежит в UTF-16, а UTF-16 полон
байтов NUL — поэтому git объявляет файл двоичным и не показывает ничего:
diff --git a/Localizable.strings b/Localizable.strings
Binary files a/Localizable.strings and b/Localizable.strings differ
Именно здесь важнее всего видеть, какую строку кто-то сдвинул. Драйвер
strings декодирует файл только для сравнения — читая метку порядка байтов, а
не предполагая её, так что современный .strings в UTF-8 проходит невредимым, а
не превращается в кракозябры.
String Catalog (.xcstrings, Xcode 15 и новее) — это JSON, и его закрывает
драйвер json: он сортирует ключи, поэтому перевод, добавленный сверху,
перестаёт переписывать в диффе весь файл.
Пределы встроенного конвертера, названные прямо: .doc (старый двоичный
формат Word) он не понимает — только .docx; PDF не покрыт — Gitcito
показывает PDF средствами просмотрщика браузера, и извлекателя текста, который
можно было бы переиспользовать, у него нет; и каждый дифф документа платит
короткую цену запуска конвертера. Настройка
git config diff.<name>.cachetextconv true заставляет git кэшировать вывод
для каждого блоба.
Половина с конвертером живёт в вашем конфиге, а не в репозитории — git не
станет запускать команды, которые вам подсунул клон, и это свойство
безопасности стоит сохранить. К тому же встроенные драйверы указывают на ваш
путь установки Gitcito, так что коллега, который клонирует, получит правило
diff=word и, пока не подключит собственный конвертер (Gitcito или любой
другой), старый нечитаемый дифф. Напишите об этом в README.
Фильтры clean/smudge — сначала пробный прогон
Фильтр переписывает содержимое на входе в репозиторий и на выходе из него:
clean запускается при добавлении в индекс (рабочее дерево → репозиторий),
smudge — при выгрузке (репозиторий → рабочее дерево). Так работает git-lfs,
и так команды вырезают учётные данные или сгенерированный шум из того, что
попадает в коммит.
Это же и самое опасное, на что может указывать .gitattributes: фильтр
запускается при каждой выгрузке каждого подходящего файла, и неправильный
фильтр молча портит ваше рабочее дерево. Поэтому Gitcito отказывается быть
здесь просто текстовым полем. Настройка фильтра проходит через пробный
прогон на настоящих подходящих файлах вашего репозитория:
- Команда
cleanзапускается на копии каждого подходящего файла (до пяти) — ничего в репозитории и его конфиге не трогается. - Если задана команда
smudge, она запускается на очищенном выводе, и результат сравнивается байт в байт с оригиналом — проверка обратимости. Фильтр, который её не проходит, означает, что выгрузка не вернёт то, что у вас было. - Кнопка сохранения оживает только после пробного прогона ровно на тех значениях, которые вы сохраняете. Неудавшийся прогон — ошибка команды, ничего не подошло или разошедшаяся обратимость — сохранить всё же можно, но только через явное предупреждение, которое говорит, что можно потерять.
Сохранение записывает filter.<name>.clean/smudge в ваш локальный конфиг
git и правило filter=<name> в файл атрибутов, а также оставляет запись
отмены, которая возвращает конфиг к тому, что в нём было прежде. Переключатель
required устанавливает filter.<name>.required, из-за чего git проваливает
операцию, вместо того чтобы молча пропускать файлы, когда фильтр сломан.
Пределы, названные прямо: пробный прогон берёт до пяти подходящих файлов не
больше 5 МБ каждый, с таймаутом 10 секунд на команду — фильтр, который ведёт
себя хорошо на выборке, всё ещё может повести себя плохо на файле, в выборку
не попавшем. Команды живут в вашем конфиге, так что коллега, который
клонирует, получит правило filter=<name>, но не команды; без них (и без
required) его файлы проходят насквозь без изменений.
Ограничения, о которых стоит знать
text=autoменяет то, что попадает в коммит, нормализуя переводы строк на входе. В существующем репозитории добавьте его, а затем осознанно выполнитеgit add --renormalize .— отдельным коммитом.- Атрибуты не применяются задним числом. Пометив файл как
binaryсегодня, вы не измените, как хранились его прошлые диффы; вы измените то, как git обращается с ним отныне. - Правила действуют только там, где файл виден. Правило в
design/.gitattributesничего не говорит проsrc/. - Gitcito пишет файлы целиком, так что вручную отформатированный файл вернётся
со своим форматированием — но правило, которое Gitcito переписал, будет
приведено к каноничным для git отступам вида
pattern attr attr.
См. также: LFS и разреженная выгрузка · Бандлы и архивы · Параметры слияния · Хуки