gitattributes
Название
gitattributes — определение атрибутов для путей
Краткое описание
$GIT_DIR/info/attributes, .gitattributes
Описание
Файл gitattributes — это простой текстовый файл, который назначает attributes путям.
Каждая строка файла gitattributes имеет следующий формат:
pattern attr1 attr2 ...
То есть шаблон, за которым следует список атрибутов, разделённые пробельными символами. Начальные и конечные пробелы игнорируются. Строки, начинающиеся с #, игнорируются. Шаблоны, начинающиеся с двойной кавычки, заключаются в кавычки в стиле C. Если шаблон соответствует рассматриваемому пути, перечисленные в строке атрибуты назначаются этому пути.
Для заданного пути каждый атрибут может находиться в одном из следующих состояний:
- Установлен
-
Путь имеет атрибут со специальным значением «true»; это задаётся указанием только имени атрибута в списке атрибутов.
- Снят
-
Путь имеет атрибут со специальным значением «false»; это задаётся указанием имени атрибута с тире
-перед ним в списке атрибутов. - Установлен в значение
-
Путь имеет атрибут с указанным строковым значением; это задаётся указанием имени атрибута, за которым следует знак равенства
=и его значение в списке атрибутов. - Не задан
-
Ни один шаблон не соответствует пути, и ничто не указывает, имеет ли путь атрибут или нет; в этом случае атрибут для пути считается не заданным.
Если пути соответствует несколько шаблонов, более поздняя строка переопределяет предыдущую. Переопределение выполняется отдельно для каждого атрибута.
Правила соответствия шаблонов путям такие же, как в файлах .gitignore (см. gitignore[5]), за несколькими исключениями:
-
отрицательные шаблоны запрещены
-
шаблоны, соответствующие каталогу, не соответствуют рекурсивно путям внутри этого каталога (поэтому синтаксис с завершающей косой чертой
path/в файле атрибутов бесполезен; вместо него используйтеpath/**)
При определении атрибутов, назначенных пути, Git проверяет файл $GIT_DIR/info/attributes (имеющий наивысший приоритет), файл .gitattributes в том же каталоге, что и рассматриваемый путь, а также файлы в его родительских каталогах вплоть до корня рабочего дерева (чем дальше от рассматриваемого пути находится каталог, содержащий .gitattributes, тем ниже его приоритет). В последнюю очередь рассматриваются глобальные и общесистемные файлы (у них наименьший приоритет).
Если файл .gitattributes отсутствует в рабочем дереве, в качестве резервного варианта используется путь в индексе. Во время извлечения файлов сначала используется .gitattributes в индексе, а затем, в качестве резервного варианта, файл в рабочем дереве.
Если вы хотите изменить настройки только для одного репозитория (то есть назначить атрибуты файлам, характерным для рабочего процесса одного пользователя в этом репозитории), атрибуты следует поместить в файл $GIT_DIR/info/attributes. Атрибуты, которые должны контролироваться системой версий и распространяться в другие репозитории (то есть представляющие интерес для всех пользователей), следует поместить в файлы .gitattributes. Атрибуты, которые должны влиять на все репозитории одного пользователя, следует поместить в файл, указанный параметром конфигурации core.attributesFile (см. git-config[1]). По умолчанию используется значение $XDG_CONFIG_HOME/git/attributes. Если переменная $XDG_CONFIG_HOME не задана или пуста, вместо неё используется $HOME/.config/git/attributes. Атрибуты для всех пользователей системы следует поместить в файл $(prefix)/etc/gitattributes.
Иногда может понадобиться переопределить для пути настройку атрибута, установив его в состояние Unspecified. Это можно сделать, указав имя атрибута с восклицательным знаком ! перед ним.
Зарезервированные встроенные атрибуты builtin_*
Пространство имён builtin_* зарезервировано для встроенных значений атрибутов. Любые пользовательские атрибуты в этом пространстве имён игнорируются и вызывают предупреждение.
builtin_objectmode
Этот атрибут предназначен для фильтрации файлов по битовым режимам файлов (40000, 120000, 160000, 100755, 100644), например :(attr:builtin_objectmode=160000). Эти значения также можно проверить с помощью git check-attr builtin_objectmode -- <file>. Если объекта нет в индексе, команда git check-attr --cached вернёт значение «не задан».
Эффекты
На некоторые операции Git можно влиять, назначая определённые атрибуты пути. В настоящее время атрибуты учитываются при следующих операциях.
Извлечение и фиксация
Эти атрибуты влияют на то, как содержимое, хранящееся в репозитории, копируется в файлы рабочего дерева при выполнении таких команд, как git switch, git checkout и git merge. Они также влияют на то, как Git сохраняет содержимое, подготовленное вами в рабочем дереве, в репозитории при выполнении git add и git commit.
text
Этот атрибут помечает путь как текстовый файл, что включает преобразование окончаний строк: при добавлении соответствующего файла в индекс его окончания строк нормализуются до LF. И наоборот, при копировании файла из индекса в рабочий каталог окончания строк могут преобразовываться из LF в CRLF в зависимости от атрибута eol, конфигурации Git и платформы (см. пояснение к eol ниже).
- Установлен
-
Установка атрибута
textдля пути включает преобразование окончаний строк при фиксации и извлечении, как описано выше. При каждой фиксации файла окончания строк в индексе нормализуются до LF, даже если ранее файл был добавлен в Git с окончаниями CRLF. - Снят
-
Снятие атрибута
textс пути указывает Git не выполнять преобразование окончаний строк при фиксации или извлечении. - Установлен в строковое значение "auto"
-
Если
textимеет значение "auto", Git самостоятельно определяет, является ли файл текстовым или двоичным. Если файл текстовый и ранее он не находился в Git с окончаниями CRLF, окончания строк преобразуются при фиксации и извлечении, как описано выше. В противном случае при фиксации и извлечении преобразование не выполняется. - Не задан
-
Если атрибут
textне задан, Git использует переменную конфигурацииcore.autocrlf, чтобы определить, следует ли преобразовывать файл.
Любое другое значение приводит к тому, что Git действует так, как если бы атрибут text оставался незаданным.
eol
Этот атрибут указывает использовать для пути определённый стиль окончания строк в рабочем дереве при извлечении. Он действует только в том случае, если задан атрибут text или text=auto (см. выше), однако указание eol автоматически задаёт text, если атрибут text не был задан.
- Установлен в строковое значение "crlf"
-
При извлечении файла эта настройка преобразует окончания строк файла в рабочем каталоге в CRLF.
- Установлен в строковое значение "lf"
-
При извлечении файла эта настройка использует в рабочем каталоге те же окончания строк, что и в индексе.
- Не задан
-
Если атрибут
eolдля файла не задан, окончания строк в рабочем каталоге определяются переменной конфигурацииcore.autocrlfилиcore.eol(определения этих параметров см. в git-config[1]). Если задан атрибутtext, но ни одна из этих переменных не задана, по умолчанию используетсяeol=crlfв Windows иeol=lfна всех остальных платформах.
Обратная совместимость с атрибутом crlf
Для обратной совместимости атрибут crlf интерпретируется следующим образом:
crlf text -crlf -text crlf=input eol=lf
Преобразование окончаний строк
Хотя обычно Git не изменяет содержимое файлов, его можно настроить так, чтобы окончания строк нормализовались до LF в репозитории и, при необходимости, преобразовывались в CRLF при извлечении файлов.
Если вам нужно, чтобы в рабочем каталоге всегда были окончания строк CRLF, независимо от используемого репозитория, можно задать переменную конфигурации "core.autocrlf", не используя атрибуты.
[core]
autocrlf = true Это не принуждает к нормализации текстовых файлов, но гарантирует, что окончания строк в добавляемых вами в репозиторий текстовых файлах будут нормализованы до LF при их добавлении, а уже нормализованные в репозитории файлы останутся нормализованными.
Если вы хотите гарантировать, что окончания строк в текстовых файлах, добавляемых в репозиторий любым участником, будут нормализованы, можно задать атрибут text со значением "auto" для файлов all.
* text=auto
Атрибуты позволяют точно управлять преобразованием окончаний строк. Вот пример, в котором Git нормализует файлы .txt, .vcproj и .sh, обеспечивает окончания CRLF в рабочем каталоге для файлов .vcproj и LF для файлов .sh, а также предотвращает нормализацию файлов .jpg независимо от их содержимого.
* text=auto *.txt text *.vcproj text eol=crlf *.sh text eol=lf *.jpg -text
| Примечание | Если в кроссплатформенном проекте включено преобразование text=auto и обмен изменениями с центральным репозиторием выполняется с помощью push и pull, текстовые файлы с окончаниями CRLF следует нормализовать. |
В чистом рабочем каталоге выполните:
$ echo "* text=auto" >.gitattributes $ git add --renormalize . $ git status # Show files that will be normalized $ git commit -m "Introduce end-of-line normalization"
Если в git status появятся файлы, которые не следует нормализовать, снимите с них атрибут text перед выполнением git add -u.
manual.pdf -text
И наоборот, можно вручную включить нормализацию для текстовых файлов, которые Git не распознаёт.
weirdchars.txt text
Если для core.safecrlf задано значение "true" или "warn", Git проверяет, обратимо ли преобразование при текущем значении core.autocrlf. При значении "true" Git отклоняет необратимые преобразования; при значении "warn" Git только выводит предупреждение, но принимает необратимое преобразование. Этот механизм безопасности срабатывает, чтобы предотвратить такое преобразование файлов в рабочем дереве, однако есть несколько исключений. Хотя…
-
сама команда
git addне затрагивает файлы в рабочем дереве, но при следующем извлечении они будут затронуты, поэтому механизм безопасности срабатывает; -
команда
git applyдля обновления текстового файла с помощью патча затрагивает файлы в рабочем дереве, но эта операция выполняется с текстовыми файлами, а преобразование CRLF предназначено для устранения несоответствий в окончаниях строк, поэтому механизм безопасности не срабатывает; -
сама команда
git diffне затрагивает файлы в рабочем дереве; её часто запускают, чтобы проверить изменения, которые вы собираетесь затем выполнить с помощьюgit add. Чтобы заранее выявить потенциальные проблемы, механизм безопасности срабатывает.
working-tree-encoding
Git распознаёт файлы в ASCII или одной из его надмножеств (например, UTF-8, ISO-8859-1, …) как текстовые. Файлы в некоторых других кодировках (например, UTF-16) интерпретируются как двоичные, поэтому встроенные средства обработки текста Git (например, git diff), а также большинство веб-интерфейсов Git по умолчанию не отображают их содержимое.
В таких случаях можно указать Git кодировку файла в рабочем каталоге с помощью атрибута working-tree-encoding. Если файл с этим атрибутом добавляется в Git, Git перекодирует его содержимое из указанной кодировки в UTF-8. Затем Git сохраняет содержимое в кодировке UTF-8 во внутренней структуре данных (называемой «индексом»). При извлечении содержимое перекодируется обратно в указанную кодировку.
Обратите внимание, что использование атрибута working-tree-encoding может быть сопряжено с рядом проблем:
-
Альтернативные реализации Git (например, JGit или libgit2) и более старые версии Git (по состоянию на март 2018 года) не поддерживают атрибут
working-tree-encoding. Если вы решите использовать атрибутworking-tree-encodingв своём репозитории, настоятельно рекомендуется убедиться, что все клиенты, работающие с репозиторием, его поддерживают.Например, файлы ресурсов Microsoft Visual Studio (
*.rc) или файлы сценариев PowerShell (*.ps1) иногда кодируются в UTF-16. Если вы объявите файлы*.ps1как файлы в UTF-16 и добавитеfoo.ps1с помощью клиента Git, поддерживающегоworking-tree-encoding, тоfoo.ps1будет храниться внутри в UTF-8. Клиент без поддержкиworking-tree-encodingизвлечётfoo.ps1как файл в кодировке UTF-8. Обычно это вызывает проблемы у пользователей этого файла.Если клиент Git, не поддерживающий атрибут
working-tree-encoding, добавит новый файлbar.ps1, тоbar.ps1будет храниться внутри «как есть» (в этом примере, вероятно, в UTF-16). Клиент с поддержкойworking-tree-encodingинтерпретирует внутреннее содержимое как UTF-8 и попытается преобразовать его в UTF-16 при извлечении. Эта операция завершится неудачно и вызовет ошибку. -
Перекодирование содержимого в кодировки, отличные от UTF, может вызывать ошибки, поскольку преобразование может быть необратимым при обратном преобразовании в UTF-8. Если вы подозреваете, что преобразование в вашей кодировке не является обратимым, добавьте её в
core.checkRoundtripEncoding, чтобы Git проверял обратное преобразование (см. git-config[1]). Известно, что при преобразовании между SHIFT-JIS (японской кодировкой) и UTF-8 возникают проблемы с обратным преобразованием; по умолчанию Git проверяет эту кодировку. -
Перекодирование содержимого требует ресурсов и может замедлить некоторые операции Git (например,
git checkoutилиgit add).
Используйте атрибут working-tree-encoding, только если файл нельзя хранить в кодировке UTF-8 и вы хотите, чтобы Git мог обрабатывать его содержимое как текст.
Например, используйте следующие атрибуты, если файлы *.ps1 имеют кодировку UTF-16 с маркером порядка байтов (BOM) и вы хотите, чтобы Git автоматически преобразовывал окончания строк в зависимости от платформы.
*.ps1 text working-tree-encoding=UTF-16
Используйте следующие атрибуты, если файлы *.ps1 имеют кодировку UTF-16 little endian без BOM и вы хотите, чтобы Git использовал окончания строк Windows в рабочем каталоге (если вам нужна кодировка UTF-16 little endian с BOM, используйте UTF-16LE-BOM вместо UTF-16LE). Обратите внимание: если используется атрибут working-tree-encoding, настоятельно рекомендуется явно задать окончания строк с помощью eol, чтобы избежать неоднозначности.
*.ps1 text working-tree-encoding=UTF-16LE eol=crlf
Получить список всех доступных в вашей системе кодировок можно следующей командой:
iconv --list
Если кодировка файла вам неизвестна, можно воспользоваться командой file, чтобы определить её предположительно:
file foo.ps1
ident
Когда для пути задан атрибут ident, при извлечении Git заменяет в объекте blob последовательность $Id$ на $Id:, за которой следует 40-символьное шестнадцатеричное имя объекта blob, а затем знак доллара $. При фиксации любая последовательность байтов в файле рабочего дерева, начинающаяся с $Id: и заканчивающаяся на $, заменяется на $Id$.
filter
Атрибуту filter можно присвоить строковое значение, обозначающее драйвер фильтра, указанный в конфигурации.
Драйвер фильтра состоит из команды clean и команды smudge; любую из них можно не задавать. При извлечении, если указана команда smudge, объект blob передаётся ей через стандартный ввод, а её стандартный вывод используется для обновления файла в рабочем дереве. Аналогично команда clean используется для преобразования содержимого файла рабочего дерева при фиксации. По умолчанию эти команды обрабатывают только один объект blob и завершают работу. Если вместо фильтров clean и/или smudge используется длительно работающий фильтр process, Git может обрабатывать все объекты blob одним вызовом команды фильтра на протяжении всего выполнения одной команды Git, например git add --all. Если настроен длительно работающий фильтр process, он всегда имеет приоритет над настроенным фильтром для одного объекта blob. Описание протокола взаимодействия с фильтром process см. в разделе ниже.
Один из способов применения фильтрации содержимого — привести содержимое к виду, более удобному для использования на данной платформе, в данной файловой системе и пользователем. В этом режиме работы ключевое здесь — «более удобный», а не «превращение непригодного в пригодное». Иными словами, предполагается, что проект останется пригодным к использованию, даже если кто-то отменит определение драйвера фильтра или у него не окажется соответствующей программы фильтрации.
Другой способ применения фильтрации содержимого — хранить в репозитории содержимое, которое нельзя использовать напрямую (например, UUID, ссылающийся на фактическое содержимое за пределами Git, или зашифрованное содержимое), и преобразовывать его в пригодный для использования вид при извлечении (например, загружать внешнее содержимое или расшифровывать его).
Эти два типа фильтров работают по-разному. По умолчанию фильтр считается фильтром первого типа, который приводит содержимое к более удобному виду. Отсутствующее в конфигурации определение драйвера фильтра или завершение драйвера с ненулевым кодом состояния не считается ошибкой, а приводит к тому, что фильтр пропускает данные без изменений.
Можно объявить, что фильтр преобразует непригодное само по себе содержимое в пригодное, задав для переменной конфигурации filter.<driver>.required значение true.
Примечание: при изменении фильтра clean репозиторий следует перенормализовать: $ git add --renormalize .
Например, в .gitattributes для путей можно назначить атрибут filter.
*.c filter=indent
Затем в .git/config нужно определить конфигурацию "filter.indent.clean" и "filter.indent.smudge", задающую пару команд для изменения содержимого программ на C при фиксации исходных файлов (выполняется команда "clean") и при их извлечении (изменения не производятся, поскольку команда — "cat").
[filter "indent"]
clean = indent
smudge = cat Для наилучшего результата clean не должен дополнительно изменять свой вывод при повторном запуске («clean→clean» должен быть эквивалентен «clean»), а повторные команды smudge не должны изменять вывод команды clean («smudge→smudge→clean» должно быть эквивалентно «clean»). См. раздел о слиянии ниже.
Фильтр "indent" ведёт себя корректно в этом отношении: он не изменяет входные данные, которые уже имеют правильные отступы. В данном случае отсутствие фильтра smudge означает, что фильтр clean must принимает собственный вывод без изменений.
Если фильтр must должен успешно завершиться, чтобы сохранённое содержимое стало пригодным к использованию, можно объявить этот фильтр required в конфигурации:
[filter "crypt"]
clean = openssl enc ...
smudge = openssl enc -d ...
required Последовательность "%f" в командной строке фильтра заменяется именем файла, с которым работает фильтр. Фильтр может использовать это при подстановке ключевых слов. Например:
[filter "p4"]
clean = git-p4-filter --clean %f
smudge = git-p4-filter --smudge %f Обратите внимание, что "%f" — это имя обрабатываемого пути. В зависимости от версии, проходящей фильтрацию, соответствующий файл на диске может отсутствовать или иметь другое содержимое. Поэтому команды smudge и clean не должны обращаться к файлу на диске, а должны лишь фильтровать содержимое, переданное им через стандартный ввод.
Длительно работающий процесс фильтрации
Если команда фильтра (строковое значение) определена с помощью filter.<driver>.process, Git может обрабатывать все объекты blob одним вызовом фильтра на протяжении всего выполнения одной команды Git. Это достигается с помощью протокола длительно работающего процесса (описанного в Documentation/technical/long-running-process-protocol.adoc).
Когда Git встречает первый файл, который нужно очистить или обработать фильтром smudge, он запускает фильтр и выполняет рукопожатие. В рукопожатии приветственное сообщение, отправляемое Git, — "git-filter-client"; поддерживается только версия 2, а список поддерживаемых возможностей включает "clean", "smudge" и "delay".
Затем Git отправляет список пар "key=value", завершающийся пакетом сброса. Список содержит как минимум команду фильтра (с учётом поддерживаемых возможностей) и путь к фильтруемому файлу относительно корня репозитория. Сразу после пакета сброса Git отправляет содержимое, разделённое на ноль или более пакетов pkt-line, и пакет сброса, завершающий содержимое. Обратите внимание: фильтр не должен отправлять ответ, пока не получит содержимое и завершающий пакет сброса. Также обратите внимание, что значение в паре "key=value" может содержать символ "=", тогда как ключ никогда не содержит этот символ.
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> 0000 packet: git> CONTENT packet: git> 0000
Ожидается, что фильтр ответит списком пар "key=value", завершённым пакетом сброса. Если у фильтра не возникло проблем, список должен содержать статус "success". Сразу после этих пакетов фильтр должен отправить содержимое в виде нуля или более пакетов pkt-line и пакет сброса в конце. Наконец, ожидается второй список пар "key=value", завершённый пакетом сброса. Фильтр может изменить статус во втором списке или оставить его прежним, отправив пустой список. Обратите внимание: пустой список в любом случае должен завершаться пакетом сброса.
packet: git< status=success packet: git< 0000 packet: git< SMUDGED_CONTENT packet: git< 0000 packet: git< 0000 # empty list, keep "status=success" unchanged!
Если результирующее содержимое пусто, фильтр должен ответить статусом "success" и пакетом сброса, обозначающим пустое содержимое.
packet: git< status=success packet: git< 0000 packet: git< 0000 # empty content! packet: git< 0000 # empty list, keep "status=success" unchanged!
Если фильтр не может или не хочет обработать содержимое, он должен ответить статусом "error".
packet: git< status=error packet: git< 0000
Если при обработке фильтр сталкивается с ошибкой, он может отправить статус "error" после того, как содержимое было отправлено (частично или полностью).
packet: git< status=success packet: git< 0000 packet: git< HALF_WRITTEN_ERRONEOUS_CONTENT packet: git< 0000 packet: git< status=error packet: git< 0000
Если фильтр не может или не хочет обрабатывать содержимое, а также любое последующее содержимое в течение всего времени работы процесса Git, он должен в любой момент протокола ответить статусом "abort".
packet: git< status=abort packet: git< 0000
Если задан статус "error"/"abort", Git не останавливает и не перезапускает процесс фильтра. Однако Git устанавливает код завершения в соответствии с флагом filter.<driver>.required, имитируя поведение механизма filter.<driver>.clean / filter.<driver>.smudge.
Если фильтр завершится во время обмена данными или не будет соблюдать протокол, Git остановит процесс фильтра и перезапустит его для следующего файла, который потребуется обработать. В зависимости от флага filter.<driver>.required Git интерпретирует это как ошибку.
Отложенная обработка
Если фильтр поддерживает возможность "delay", Git может отправить флаг "can-delay" после команды фильтра и пути. Этот флаг указывает, что фильтр может отложить фильтрацию текущего объекта blob (например, чтобы компенсировать задержки сети), ответив без содержимого, но со статусом "delayed" и пакетом сброса.
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> can-delay=1 packet: git> 0000 packet: git> CONTENT packet: git> 0000 packet: git< status=delayed packet: git< 0000
Если фильтр поддерживает возможность "delay", он должен поддерживать команду "list_available_blobs". При отправке Git этой команды фильтр должен вернуть список путей, соответствующих объектам blob, обработка которых была отложена ранее и которые теперь доступны. Список должен завершаться пакетом сброса, за которым следует статус "success", также завершающийся пакетом сброса. Если отложенные объекты по указанным путям ещё недоступны, фильтр должен блокировать ответ, пока не станет доступен хотя бы один объект blob. Фильтр может сообщить Git, что больше отложенных объектов нет, отправив пустой список. Как только фильтр ответит пустым списком, Git прекращает запросы. Все объекты blob, которые Git к этому моменту не получил, считаются отсутствующими и приведут к ошибке.
packet: git> command=list_available_blobs packet: git> 0000 packet: git< pathname=path/testfile.dat packet: git< pathname=path/otherfile.dat packet: git< 0000 packet: git< status=success packet: git< 0000
Получив пути, Git повторно запросит соответствующие объекты blob. Эти запросы содержат путь и пустую секцию содержимого. Фильтр должен ответить обработанным фильтром smudge содержимым обычным способом, описанным выше.
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> 0000 packet: git> 0000 # empty content! packet: git< status=success packet: git< 0000 packet: git< SMUDGED_CONTENT packet: git< 0000 packet: git< 0000 # empty list, keep "status=success" unchanged!
Пример
Демонстрационную реализацию длительно работающего фильтра можно найти в contrib/long-running-filter/example.pl, расположенном в основном репозитории Git. Если вы разрабатываете собственный длительно работающий процесс фильтрации, переменные окружения GIT_TRACE_PACKET могут быть очень полезны для отладки (см. git[1]).
Обратите внимание, что нельзя использовать существующую команду filter.<driver>.clean или filter.<driver>.smudge с filter.<driver>.process, поскольку первые две используют протокол межпроцессного взаимодействия, отличающийся от протокола последней.
Взаимодействие атрибутов фиксации и извлечения
При фиксации файл рабочего дерева сначала преобразуется драйвером filter (если он указан и для него определён соответствующий драйвер), затем результат обрабатывается с помощью ident (если он указан) и, наконец, с помощью text (если он также указан и применим).
При извлечении содержимое объекта blob сначала преобразуется с помощью text, а затем ident и передаётся в filter.
Слияние ветвей с разными атрибутами фиксации и извлечения
Если вы добавили к файлу атрибуты, изменяющие канонический формат этого файла в репозитории, например фильтр clean/smudge или атрибуты text/eol/ident, слияние любых данных, в которых этот атрибут не задан, обычно приводит к конфликтам слияния.
Чтобы предотвратить такие ненужные конфликты слияния, можно настроить Git на выполнение виртуальных извлечения и фиксации для всех трёх версий каждого файла, требующего трёхстороннего слияния содержимого, задав переменную конфигурации merge.renormalize. Это не позволяет изменениям, вызванным преобразованием при фиксации, приводить к ложным конфликтам слияния преобразованного файла с непреобразованным.
Если результат "smudge→clean" совпадает с результатом "clean" даже для файлов, уже обработанных фильтром smudge, эта стратегия автоматически разрешит все конфликты, связанные с фильтрами. Фильтры, работающие иначе, могут вызывать дополнительные конфликты слияния, которые потребуется разрешать вручную.
Создание текста diff
diff
Атрибут diff влияет на то, как Git создает diff для определенных файлов. Он указывает Git, следует ли создавать текстовый патч для пути или обрабатывать путь как двоичный файл. Он также может влиять на то, какая строка отображается в заголовке блока изменений @@ -k,l +n,m @@, указывать Git использовать внешнюю команду для создания diff или предписывать Git преобразовывать двоичные файлы в текстовый формат перед созданием diff.
- Установлено
-
Путь, для которого задан атрибут
diff, обрабатывается как текст, даже если он содержит байтовые значения, которые обычно не встречаются в текстовых файлах, например NUL. - Снято
-
Для пути, у которого снят атрибут
diff, будет созданBinaryfilesdiffer(или двоичный патч, если включены двоичные патчи). - Не указано
-
Если для пути атрибут
diffне указан, сначала проверяется его содержимое. Если оно похоже на текст и его размер меньше core.bigFileThreshold, путь обрабатывается как текст. В противном случае будет созданBinaryfilesdiffer. - Строка
-
Diff отображается с использованием указанного драйвера diff. Каждый драйвер может задавать один или несколько параметров, описанных в следующем разделе. Параметры драйвера diff «foo» определяются переменными конфигурации в разделе «diff.foo» файла конфигурации Git.
Определение внешнего драйвера diff
Определение драйвера diff задается в gitconfig, а не в файле gitattributes, поэтому, строго говоря, это руководство — неподходящее место для его описания. Однако…
Чтобы определить внешний драйвер diff jcdiff, добавьте в файл $GIT_DIR/config (или файл $HOME/.gitconfig) раздел следующего вида:
[diff "jcdiff"]
command = j-c-diff Когда Git потребуется показать diff для пути с установленным атрибутом diff со значением jcdiff, он вызовет указанную в приведенной выше конфигурации команду, то есть j-c-diff, передав ей 7 параметров, как при вызове программы GIT_EXTERNAL_DIFF. Подробнее см. в git[1].
Если программа умеет игнорировать некоторые изменения (аналогично git diff --ignore-space-change), задайте также параметр trustExitCode равным true. В этом случае ожидается, что программа вернет код выхода 1, если обнаружит существенные изменения, и 0, если не обнаружит.
Настройка внутреннего алгоритма diff
Алгоритм diff можно задать с помощью ключа конфигурации diff.algorithm, но иногда бывает полезно задавать его отдельно для разных путей. Например, можно использовать алгоритм diff minimal для файлов .json и алгоритм histogram для файлов .c и так далее, не указывая алгоритм каждый раз в командной строке.
Сначала в .gitattributes назначьте атрибут diff для путей.
*.json diff=<name>
Затем задайте конфигурацию «diff.<name>.algorithm», чтобы указать алгоритм diff. Выберите один из вариантов: myers, patience, minimal или histogram.
[diff "<name>"] algorithm = histogram
Этот алгоритм diff применяется к выводимому пользователю diff, например в git-diff(1) и git-show(1), а также используется для вывода --stat. Механизм слияния не использует алгоритм diff, заданный этим способом.
| Примечание | Если для пути с атрибутом diff=<name> задан параметр diff.<name>.command, он выполняется как внешний драйвер diff (см. выше), и добавление diff.<name>.algorithm ни на что не влияет, поскольку алгоритм не передается внешнему драйверу diff. |
Настройка заголовка блока изменений
Каждая группа изменений (называемая «блоком») в текстовом выводе diff предваряется строкой следующего вида:
@@ -k,l +n,m @@ TEXT
Она называется hunk header. По умолчанию часть «TEXT» — это строка, начинающаяся с буквы, символа подчеркивания или знака доллара; так устроен вывод GNU diff -p. Однако такой вариант по умолчанию подходит не для всякого содержимого, и для выбора можно использовать собственный шаблон.
Сначала в .gitattributes назначьте атрибут diff для путей.
*.tex diff=tex
Затем задайте конфигурацию «diff.tex.xfuncname», указав регулярное выражение, которое соответствует строке, которую вы хотите видеть в качестве «TEXT» в заголовке блока изменений. Добавьте в файл $GIT_DIR/config (или файл $HOME/.gitconfig) раздел следующего вида:
[diff "tex"]
xfuncname = "^(\\\\(sub)*section\\{.*)$" Примечание. Парсер файла конфигурации удаляет один уровень обратных косых черт, поэтому обратные косые черты нужно удваивать; приведенный выше шаблон выбирает строку, начинающуюся с обратной косой черты, за которой следует ноль или более вхождений sub, затем section и открывающая фигурная скобка, до конца строки.
Для удобства предусмотрено несколько встроенных шаблонов. Один из них — tex, поэтому его не нужно указывать в файле конфигурации (но его по-прежнему нужно включить с помощью механизма атрибутов, задав .gitattributes). Доступны следующие встроенные шаблоны:
-
adaподходит для исходного кода на языке Ada. -
bashподходит для исходного кода на языке Bourne-Again SHell. Охватывает более широкий набор определений функций, чем POSIX shell. -
bibtexподходит для файлов со ссылками в формате BibTeX. -
cppподходит для исходного кода на языках C и C++. -
csharpподходит для исходного кода на языке C#. -
cssподходит для каскадных таблиц стилей. -
dtsподходит для файлов devicetree (DTS). -
elixirподходит для исходного кода на языке Elixir. -
fortranподходит для исходного кода на языке Fortran. -
fountainподходит для документов Fountain. -
golangподходит для исходного кода на языке Go. -
htmlподходит для документов HTML/XHTML. -
javaподходит для исходного кода на языке Java. -
kotlinподходит для исходного кода на языке Kotlin. -
markdownподходит для документов Markdown. -
matlabподходит для исходного кода на языках MATLAB и Octave. -
objcподходит для исходного кода на языке Objective-C. -
pascalподходит для исходного кода на языке Pascal/Delphi. -
perlподходит для исходного кода на языке Perl. -
phpподходит для исходного кода на языке PHP. -
pythonподходит для исходного кода на языке Python. -
rubyподходит для исходного кода на языке Ruby. -
rustподходит для исходного кода на языке Rust. -
schemeподходит для исходного кода на большинстве диалектов Lisp, включая Scheme, Emacs Lisp, Common Lisp и Clojure. -
texподходит для исходного кода документов LaTeX.
Настройка word diff
Можно настроить правила, используемые git diff --word-diff для разделения строки на слова, указав подходящее регулярное выражение в переменной конфигурации «diff.*.wordRegex». Например, в TeX обратная косая черта, за которой следует последовательность букв, образует команду, но несколько таких команд могут идти подряд без пробелов между ними. Чтобы разделить их, используйте регулярное выражение в файле $GIT_DIR/config (или файле $HOME/.gitconfig) следующего вида:
[diff "tex"]
wordRegex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+" Для всех языков, перечисленных в предыдущем разделе, предусмотрен встроенный шаблон.
Создание текстовых diff для двоичных файлов
Иногда полезно просмотреть diff текстового представления некоторых двоичных файлов. Например, документ текстового процессора можно преобразовать в текстовое представление ASCII и показать diff этого текста. Несмотря на то что при таком преобразовании теряется часть информации, полученный diff удобно просматривать (но его нельзя применить напрямую).
Параметр конфигурации textconv используется для задания программы, выполняющей такое преобразование. Программа должна принимать один аргумент — имя преобразуемого файла — и выводить полученный текст в stdout.
Например, чтобы показывать diff данных exif файла вместо двоичных данных (при условии, что у вас установлен инструмент exif), добавьте в файл $GIT_DIR/config (или файл $HOME/.gitconfig) следующий раздел:
[diff "jpg"]
textconv = exif | Примечание | Обычно преобразование в текст выполняется только в одном направлении; в этом примере теряется собственно содержимое изображения, и сохраняются только текстовые данные. Поэтому diff, созданный с помощью textconv, не подходит для применения. По этой причине преобразование в текст выполняют только git diff и семейство команд git log (то есть log, whatchanged, show). Команда git format-patch никогда не создает такой вывод. Если вы хотите отправить кому-либо diff двоичного файла, преобразованный в текст (например, чтобы быстро показать внесенные изменения), создайте его отдельно и отправьте как комментарий в дополнение к обычному двоичному diff, который вы собираетесь отправить. |
Поскольку преобразование в текст может выполняться медленно, особенно когда с помощью git log -p выполняется большое число таких преобразований, Git предоставляет механизм кэширования результатов для использования в будущих diff. Чтобы включить кэширование, задайте переменную «cachetextconv» в конфигурации драйвера diff. Например:
[diff "jpg"]
textconv = exif
cachetextconv = true Результат выполнения «exif» для каждого blob будет кэшироваться бессрочно. Если изменить переменную конфигурации textconv для драйвера diff, Git автоматически аннулирует записи кэша и повторно запустит фильтр textconv. Чтобы вручную аннулировать кэш (например, если вы обновили версию «exif» и она теперь выдает более качественный результат), можно удалить кэш вручную с помощью git update-ref -d refs/notes/textconv/jpg (где «jpg» — имя драйвера diff, как в примере выше).
Выбор между textconv и внешним diff
Если вы хотите показывать различия между двоичными или особым образом форматированными blob в репозитории, можно использовать внешнюю команду diff или преобразовать их с помощью textconv в текстовый формат, пригодный для diff. Выбор метода зависит от конкретной ситуации.
Преимущество внешней команды diff — гибкость. Вы не ограничены поиском построчных изменений, а вывод не обязан напоминать унифицированный diff. Вы можете находить и отображать изменения наиболее подходящим для вашего формата данных способом.
В сравнении с этим textconv накладывает гораздо больше ограничений. Вы преобразуете данные в построчный текстовый формат, а Git использует для создания вывода обычные инструменты diff. У этого метода есть несколько преимуществ:
-
Простота использования. Преобразовать двоичные данные в текст часто гораздо проще, чем самостоятельно реализовать diff. Во многих случаях в качестве фильтров textconv можно использовать готовые программы (например, exif, odt2txt).
-
Возможности Git diff. Выполняя самостоятельно только этап преобразования, вы по-прежнему можете использовать многие возможности diff в Git, включая раскраску, word-diff и объединенные diff для слияний.
-
Кэширование. Кэширование textconv может ускорить повторное создание diff, например при выполнении
gitlog-p.
Пометка файлов как двоичных
Обычно Git правильно определяет, содержит ли blob текстовые или двоичные данные, проверяя начало содержимого. Однако иногда нужно переопределить это решение: например, если двоичные данные находятся дальше в файле или если содержимое, хотя технически и состоит из текстовых символов, непонятно человеку. Например, многие файлы PostScript содержат только символы ASCII, но приводят к шумным и бессмысленным diff.
Самый простой способ пометить файл как двоичный — снять атрибут diff в файле .gitattributes:
*.ps -diff
В результате Git будет создавать Binary files differ (или двоичный патч, если двоичные патчи включены) вместо обычного diff.
Однако может потребоваться также задать другие атрибуты драйвера diff. Например, вы можете использовать textconv для преобразования файлов PostScript в представление ASCII, удобное для просмотра, но при этом обрабатывать их как двоичные файлы. Нельзя одновременно задать атрибуты -diff и diff=ps. Решение — использовать параметр конфигурации diff.*.binary:
[diff "ps"] textconv = ps2ascii binary = true
Выполнение трехстороннего слияния
merge
Атрибут merge влияет на слияние трех версий файла, когда при git merge необходимо выполнить слияние на уровне файла, а также при выполнении других команд, таких как git revert и git cherry-pick.
- Установлено
-
Для слияния содержимого используется встроенный драйвер трехстороннего слияния, аналогичный команде
mergeиз набораRCS. Подходит для обычных текстовых файлов. - Снято
-
Версия из текущей ветки используется как предварительный результат слияния, а слияние помечается как конфликтное. Подходит для двоичных файлов, для которых не определена семантика слияния.
- Не указано
-
По умолчанию используется тот же встроенный драйвер трехстороннего слияния, что и при установленном атрибуте
merge. Однако переменная конфигурацииmerge.defaultпозволяет указать другой драйвер слияния для путей, у которых атрибутmergeне задан. - Строка
-
Трехстороннее слияние выполняется с помощью указанного пользовательского драйвера слияния. Встроенный драйвер трехстороннего слияния можно явно задать, указав драйвер «text»; встроенный драйвер «взять текущую ветку» можно запросить с помощью «binary».
Встроенные драйверы слияния
Для атрибута merge можно указать несколько встроенных низкоуровневых драйверов слияния.
- text
-
Обычное трехстороннее слияние текстовых файлов на уровне файла. Конфликтующие области помечаются маркерами конфликтов <<<<<<<,
=======и >>>>>>>. Версия из вашей ветки находится перед маркером=======, а версия из объединяемой ветки — после маркера=======. - binary
-
Оставить в рабочем дереве версию из вашей ветки, но сохранить для пути состояние конфликта, чтобы пользователь разрешил его самостоятельно.
- union
-
Выполнить трехстороннее слияние текстовых файлов на уровне файла, но взять строки из обеих версий вместо добавления маркеров конфликтов. В результате добавленные строки часто оказываются в случайном порядке, поэтому пользователю следует проверить результат. Не используйте этот вариант, если не понимаете его последствий.
Определение пользовательского драйвера слияния
Определение драйвера слияния задается в файле .git/config, а не в файле gitattributes, поэтому, строго говоря, это руководство — неподходящее место для его описания. Однако…
Чтобы определить пользовательский драйвер слияния filfre, добавьте в файл $GIT_DIR/config (или файл $HOME/.gitconfig) раздел следующего вида:
[merge "filfre"]
name = feel-free merge driver
driver = filfre %O %A %B %L %P
recursive = binary Переменная merge.*.name задает понятное человеку имя драйвера.
Значение переменной merge.*.driver используется для формирования команды, запускаемой для версии общего предка (%O), текущей версии (%A) и версии другой ветки (%B). При формировании командной строки эти три маркера заменяются именами временных файлов, содержащих соответствующие версии. Кроме того, %L будет заменен размером маркера конфликта (см. ниже).
Драйвер слияния должен записать результат слияния в файл, заданный с помощью %A, перезаписав его, и завершиться с нулевым кодом, если слияние прошло без конфликтов, или с ненулевым кодом, если возникли конфликты. Если драйвер аварийно завершает работу (например, получает сигнал SEGV), ожидается, что он вернет ненулевой код выше 128; в таком случае слияние завершается с ошибкой (это отличается от возникновения конфликта).
Переменная merge.*.recursive указывает, какой другой драйвер слияния использовать при выполнении внутреннего слияния общих предков, если их больше одного. Если значение не указано, этот же драйвер используется как для внутреннего, так и для итогового слияния.
Драйвер слияния может получить путь, по которому будет сохранен результат слияния, с помощью заполнителя %P. Метки конфликта для общего предка, локальной вершины и другой вершины можно передать с помощью %S, %X и %Y соответственно.
conflict-marker-size
Этот атрибут задает длину маркеров конфликта, оставляемых в файле рабочего дерева при конфликтном слиянии. Значение имеет только положительное целое число.
Например, эта строка в .gitattributes указывает механизму слияния оставлять гораздо более длинные маркеры конфликтов (вместо стандартных маркеров длиной 7 символов), если слияние файла Documentation/git-merge.adoc приводит к конфликту.
Documentation/git-merge.adoc conflict-marker-size=32
Проверка ошибок в пробельных символах
whitespace
Переменная конфигурации core.whitespace позволяет определить, какие diff и apply должны считать ошибками в пробельных символах для всех путей проекта (см. git-config[1]). Этот атрибут позволяет задавать более точные настройки для отдельных путей.
- Установлено
-
Обнаруживать все типы потенциальных ошибок в пробельных символах, известные Git. Ширина табуляции берется из значения переменной конфигурации
core.whitespace. - Снято
-
Не считать ошибкой ничего.
- Не указано
-
Использовать значение переменной конфигурации
core.whitespace, чтобы определить, что считать ошибкой. - Строка
-
Задать список распространенных проблем с пробельными символами, которые нужно обнаруживать. Элементы списка разделяются запятыми, формат такой же, как у переменной конфигурации
core.whitespace.
Создание архива
export-ignore
Файлы и каталоги с атрибутом export-ignore не будут добавлены в архивы.
export-subst
Если для файла установлен атрибут export-subst, Git заменит несколько заполнителей при добавлении этого файла в архив. Возможность замены зависит от наличия идентификатора коммита: если git-archive[1] передано дерево, а не коммит или тег, замена выполняться не будет. Заполнители совпадают с теми, что используются для параметра --pretty=format: команды git-log[1], за исключением того, что в файле их нужно заключать в $Format:PLACEHOLDERS$. Например, строка $Format:%H$ будет заменена хешем коммита. Однако для защиты от атак типа «отказ в обслуживании» в каждом архиве заменяется не более одного заполнителя %(describe).
Упаковка объектов
delta
Для blob путей, у которых атрибут delta имеет значение false, дельта-сжатие выполняться не будет.
Просмотр файлов в графических инструментах
encoding
Значение этого атрибута задает кодировку символов, которую должны использовать графические инструменты (например, gitk[1] и git-gui[1]) для отображения содержимого соответствующего файла. Обратите внимание: из соображений производительности gitk[1] использует этот атрибут, только если вручную включить в настройках кодировки для отдельных файлов.
Если этот атрибут не задан или имеет недопустимое значение, вместо него используется значение переменной конфигурации gui.encoding (см. git-config[1]).
Использование макроатрибутов
Для отслеживаемых двоичных файлов не нужно выполнять преобразование окончаний строк или создавать текстовые diff. Для этого потребуется, например, указать:
*.jpg -text -diff
Однако при большом количестве атрибутов это может стать неудобным. Макроатрибуты позволяют определять атрибут, установка которого одновременно устанавливает или снимает несколько других атрибутов. В системе есть встроенный макроатрибут binary:
*.jpg binary
Установка атрибута «binary» также снимает атрибуты «text» и «diff», как показано выше. Обратите внимание: макроатрибутам можно задавать только состояние «Установлено», однако при этом другие атрибуты могут быть установлены, сняты или даже возвращены в состояние «Не указано».
Определение макроатрибутов
Пользовательские макроатрибуты можно определять только в файлах gitattributes верхнего уровня ($GIT_DIR/info/attributes, файле .gitattributes в корне рабочего дерева или глобальных либо общесистемных файлах gitattributes), но не в файлах .gitattributes во вложенных каталогах рабочего дерева. Встроенный макроатрибут «binary» эквивалентен следующему:
[attr]binary -diff -merge -text
Примечания
При обращении к файлу .gitattributes в рабочем дереве Git не переходит по символическим ссылкам. Это обеспечивает одинаковое поведение при обращении к файлу из индекса или дерева и при обращении к нему в файловой системе.
Примеры
Если у вас есть эти три файла gitattributes:
(in $GIT_DIR/info/attributes) a* foo !bar -baz (in .gitattributes) abc foo bar baz (in t/.gitattributes) ab* merge=filfre abc -foo -bar *.c frotz
атрибуты, назначенные пути t/abc, вычисляются следующим образом:
-
Проверяя
t/.gitattributes(который находится в том же каталоге, что и рассматриваемый путь), Git обнаруживает, что первая строка совпадает. Атрибутmergeустанавливается. Также обнаруживается, что вторая строка совпадает, а атрибутыfooиbarсбрасываются. -
Затем Git проверяет
.gitattributes(который находится в родительском каталоге) и обнаруживает, что первая строка совпадает, но файлt/.gitattributesуже определил, как назначить этому пути атрибутыmerge,fooиbar, поэтому атрибутыfooиbarостаются сброшенными. Атрибутbazустанавливается. -
Наконец, Git проверяет
$GIT_DIR/info/attributes. Этот файл используется для переопределения настроек в дереве. Первая строка совпадает, атрибутfooустанавливается,barвозвращается в неопределенное состояние, аbazсбрасывается.
В результате назначение атрибутов для t/abc выглядит так:
foo set to true bar unspecified baz set to false merge set to string value "filfre" frotz unspecified
См. также
gitattributes
© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/gitattributes