Как можно зафиксировать файл с помощью CRLF в git?

У меня есть репозиторий, содержащий 5 файлов, которые были зафиксированы с помощью CRLF. Я не знаю, как это произошло, но при чистой проверке, если я использую эту команду, она печатает 5 файлов (из сотен):

git grep -I --files-with-matches --perl-regexp '\r' HEAD

Кто-нибудь знает, как я могу воспроизвести эту проблему? Другими словами, какой набор настроек git может привести к этой ситуации?


person Marinos An    schedule 11.10.2017    source источник


Ответы (2)


Внутри Git просто хранит необработанные данные. Если вы запустите git hash-object -w, вы можете отправить любые данные большого двоичного объекта в репозиторий (хотя тогда вам нужно будет прикрепить тег или добавить большой двоичный объект в индекс, чтобы сохранить его в новом коммите).

Как я отметил в своем ответе на Что означает код проверки в документации git для концов строк?, Git применит CRLF- перевод окончаний строк только в LF в любом файле, для которого такие переводы включены, во время запуска git add для этого файла. В результате версия файла в индексе (или, точнее, хэш BLOB-объекта в индексе, представляющий объект BLOB-объекта в репо) имеет окончания строк только LF.

Если вы запустите git add в этом файле с помощью:

  • переводы отключены глобально, или
  • переводы отключены для этого конкретного имени пути

тогда Git не будет выполнять эти переводы, а индексная версия файла будет содержать любые '\r' символа, которые были в версии рабочего дерева.

Настройки в .gitattributes и/или core.autocrlf определяют, включены ли переводы, и если да, то какие переводы выполнять. Из-за исторических настроек (от тех времен, когда Git вообще ничего не делал, до ранних этапов добавления поддержки Windows, через различные промежуточные версии Git, до текущего довольно сложного метода .gitattributes) правила для всего этого довольно сложны.

Другими словами, какой набор настроек git может привести к этой ситуации?

Есть много разных способов сделать это, но самый простой из них — написать файл .gitattributes с помощью всего лишь:

* -text

или установить core.autocrlf в false (но обратите внимание, что .gitattributes в общем случае переопределяет core.autocrlf). Теперь Git будет обрабатывать все файлы как двоичные, не выполняя «очистку» во время git add и не «смазывая» во время git checkout. Содержимое рабочего дерева теперь будет байт за байтом соответствовать содержимому индекса, за исключением любых изменений, которые вы вносите самостоятельно или с помощью запуска программ в файлах рабочего дерева. Затем вы можете git add добавить эти новые файлы в индекс, и он скопирует их, байт за байтом; и каждый новый git commit, который вы делаете, будет использовать то, что находится в индексе.

После того как вы сохранили в качестве постоянных и неизменяемых коммитов конкретные версии определенных файлов, которые вам нужны, вы можете изменить .gitattributes, чтобы он содержал любые другие параметры, которые вы хотели бы протестировать, и запустить git checkout <commit> -- <path>, чтобы Git скопировал файл из коммита в индекс, через смазывающие фильтры и в рабочее дерево. Вы можете изменить любой файл рабочего дерева любым удобным для вас способом, а затем запустить git add <path>, чтобы пропустить файл через очищающие фильтры и скопировать его в индекс. Эти фильтры будут контролироваться тем, что у вас есть в .gitattributes во время запуска команд, поэтому вы можете экспериментировать с различными атрибутами, не делая новых коммитов.

person torek    schedule 11.10.2017
comment
Может ли вышеизложенное привести к выводу, что невозможно (используя стандартный клиент git) выполнить фиксацию, включающую CRLF, если core.autocrlf=true (windows)/core.autocrlf=input (linux) и отсутствуют атрибуты .git? - person Marinos An; 12.10.2017
comment
@MarinosAn: нет, потому что если вы начнете с фиксации, которая имеет окончания CRLF в каком-либо файле, и извлечете этот файл из фиксации в индекс, индексная версия файла будет иметь окончания CRLF. Если вы никогда не git add вернете файл обратно в индекс, версия индекса по-прежнему будет иметь окончания CRLF, и следующая фиксация будет использовать версию индекса. В этот момент никакие настройки не имеют значения: то, что входит в следующую фиксацию, совпадает с тем, что было в предыдущей фиксации. - person torek; 12.10.2017
comment
оба ваших ответа действительно многое прояснили. Также помог мне выяснить, как некоторые файлы могут стать настолько необратимыми в git: stackoverflow.com/a/45030792/1555615 - person Marinos An; 12.10.2017

Вероятно, вы используете git config --global core.autocrlf true

Более подробное объяснение см. в документах. .

person Bernardo Duarte    schedule 11.10.2017