Spec-Zone.ru › Git

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, будет создан Binary files differ (или двоичный патч, если включены двоичные патчи).

Не указано

Если для пути атрибут diff не указан, сначала проверяется его содержимое. Если оно похоже на текст и его размер меньше core.bigFileThreshold, путь обрабатывается как текст. В противном случае будет создан Binary files differ.

Строка

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. У этого метода есть несколько преимуществ:

  1. Простота использования. Преобразовать двоичные данные в текст часто гораздо проще, чем самостоятельно реализовать diff. Во многих случаях в качестве фильтров textconv можно использовать готовые программы (например, exif, odt2txt).

  2. Возможности Git diff. Выполняя самостоятельно только этап преобразования, вы по-прежнему можете использовать многие возможности diff в Git, включая раскраску, word-diff и объединенные diff для слияний.

  3. Кэширование. Кэширование textconv может ускорить повторное создание diff, например при выполнении git log -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, вычисляются следующим образом:

  1. Проверяя t/.gitattributes (который находится в том же каталоге, что и рассматриваемый путь), Git обнаруживает, что первая строка совпадает. Атрибут merge устанавливается. Также обнаруживается, что вторая строка совпадает, а атрибуты foo и bar сбрасываются.

  2. Затем Git проверяет .gitattributes (который находится в родительском каталоге) и обнаруживает, что первая строка совпадает, но файл t/.gitattributes уже определил, как назначить этому пути атрибуты merge, foo и bar, поэтому атрибуты foo и bar остаются сброшенными. Атрибут baz устанавливается.

  3. Наконец, 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

См. также

git-check-attr[1].

gitattributes

© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/gitattributes

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API