Рабочие инструменты

Атрибуты файлов

.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 просто сравнивает сконвертированный текст.

Две половины, и нужны обе:

  1. diff.<name>.textconv в конфиге git — команда-конвертер.
  2. *.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 отказывается быть здесь просто текстовым полем. Настройка фильтра проходит через пробный прогон на настоящих подходящих файлах вашего репозитория:

  1. Команда clean запускается на копии каждого подходящего файла (до пяти) — ничего в репозитории и его конфиге не трогается.
  2. Если задана команда smudge, она запускается на очищенном выводе, и результат сравнивается байт в байт с оригиналом — проверка обратимости. Фильтр, который её не проходит, означает, что выгрузка не вернёт то, что у вас было.
  3. Кнопка сохранения оживает только после пробного прогона ровно на тех значениях, которые вы сохраняете. Неудавшийся прогон — ошибка команды, ничего не подошло или разошедшаяся обратимость — сохранить всё же можно, но только через явное предупреждение, которое говорит, что можно потерять.

Сохранение записывает 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 и разреженная выгрузка · Бандлы и архивы · Параметры слияния · Хуки

Улучшить этот перевод на GitHub