Почему Git хочет исправить мои окончания строк в CRLF, хотя я хочу, чтобы они были в LF? - PullRequest
3 голосов
/ 11 апреля 2019

При работе с относительно большим проектом используется политика извлечения CRLF и фиксации LF. Для этого моя система использует:

git config --global core.autocrlf true

Однако при фиксации файла, в данном случае файла .gitattributes, возвращается предупреждение:

LF would be replaced by CRLF in .gitattributes

Сам файл .gitattributes содержит строку * text=auto !eol, а сам файл использует LF-окончания строк.

Почему это происходит? Почему Git говорит мне быть осторожным, поскольку он преобразует LF в CRLF, хотя я хочу, чтобы этот файл был нормализован с окончаниями LF в хранилище?

Я, должно быть, упускаю что-то совершенно очевидное, поскольку я прошел через:

И еще, но это все еще не работает так, как я думал.

1 Ответ

4 голосов
/ 11 апреля 2019

Давайте посмотрим на это в нескольких частях:

  • !eol здесь не имеет никакой функции.Это устанавливает eol в unspecified, но это уже значение по умолчанию, и неопределенное значение eol не отключает преобразование LF в CRLF.

  • Поскольку вы указалиtext=auto, Git проверит, является ли содержимое .gitattributes текстовым или двоичным, и, конечно, оно должно быть текстовым.

Следовательно, эта конкретная запись сообщает Git, чтоон должен выполнять переводы на .gitattributes.

Тем временем, полезно понимать, что преобразования с окончанием строки являются частным случаем общей концепции фильтра «чистый и грязный». Принятый ответ VonC на вашу третью ссылку имеет хороший рисунок того, как работает фильтр смазывания , но ему не хватает того, как работает фильтр clean , поэтому давайте углубимсяв этом, с небольшим фоном.

Git-ified ("лиофилизированный") против файлов рабочего дерева ("регидратированный"), и индекс

нормальный Git 1 атомная единица хранения - коммит.Коммит содержит полный снимок вашего дерева исходных текстов (плюс коммит метаданные , которые я не буду здесь рассматривать).По многим веским причинам файлы в коммите хранятся в сжатом, замороженном, доступном только для чтения и Git-формате.Я недавно стал называть эти файлы сублимированным .Это помогает отличить их от файлов, с которыми вы на самом деле работаете / on.

Как и все, что находится во внутренней базе данных объектов-ключей Git, эти коммиты и их файлы доступны только для чтения.Это означает, что они сохраняются навсегда (или до тех пор, пока сам коммит продолжает существовать), что отлично подходит для архивирования, но совершенно бесполезно для выполнения любой новой работы.Таким образом, Git должен предоставить способ «повторно увлажнить» файлы, превратив их в обычные файлы, с которыми вы можете работать.

Ваше рабочее дерево - это то место, куда Git помещает повторно созданные файлы.Они имеют свою обычную форму, в обычных файлах под обычными именами.Каждая программа на вашем компьютере может справиться с ними, и вы можете манипулировать ими по своему усмотрению.

Git может остановиться здесь: у вас будут замороженные зафиксированные файлы и ваша податливая работа.файлы дерева, и Git будет создавать новые коммиты из рабочего дерева.Mercurial, который во многом похож на Git, останавливается на .Но Git не останавливается здесь.Вместо этого он продолжает добавлять в смесь посредника, сидящего между текущим замороженным коммитом и рабочим деревом.Этот посредник Git's index .Git иногда называет это промежуточной областью или кеш , в зависимости от того, кто / какая часть документации Git выполняет вызов.Все три являются именами для одного и того же объекта.

Индекс / промежуточная область просто содержит дополнительную копию каждого файла .Формат этой дополнительной копии является лиофилизированным внутренним форматом хранения Git-only.Файлы в этом формате автоматически распределяются между всеми коммитами, имеющими один и тот же файл, поэтому это означает, что если копия в имеет индекс такой же , что и копия в любом коммите,на самом деле используется совместно с , который фиксирует.

Это также означает, что git commit, который должен вымораживать каждый файл, чтобы сохранить его навсегда, на самом деле практически не имеет смысла: файлы уже сублимирован! Процесс сублимации проходил раньше, когда вы запустили git add.Вот что делает Git большей частью своей скорости.Это также , почему Git постоянно требует от вас git add. 2 Обратите внимание, что это означает, что когда вы запускаете git commit, Git даже не нужнопосмотрите на ваше рабочее дерево. (хотя по-прежнему выполняется быстрая половина - git status запускается по умолчанию, чтобы создать текст комментария для вашего сообщения о коммите.)


1 Я говорю здесь normal , потому что Git также предлагает низкоуровневый доступ к простому хранилищу значения ключа через то, что он называет blob объектами. Однако, чтобы использовать это, вы должны прибегнуть к использованию некоторых из так называемых команд plumbing , а не тех, которые, по крайней мере в теории, удобны для пользователя. : -)

2 Mercurial, который использует рабочее дерево в качестве предлагаемого следующего коммита, не требует, чтобы вы сохраняли hg add -ing-ваши файлы. После того, как вы сделали начальный hg add, hg commit сканирует ваше рабочее дерево и фиксирует все, что вы изменили. Это намного дружелюбнее для новичков, но это также означает, что в большом проекте, когда вы запускаете hg commit, будьте готовы ждать.


Роль индексной / промежуточной области в преобразованиях с окончанием строки

Помните, что в индексе хранятся сублимированные копии Git-ified каждого файла. Это означает, что шаг «регидратации» индекса к рабочему дереву является отличным местом для выполнения любых преобразований, которые вы хотите выполнить. Вот тут-то и появляются фильтры размазывания в связанном ответе: фильтр размазывания может изменить зафиксированный текст, чтобы текст рабочего дерева был более полезным.

Аналогичным образом, шаг «дерево-на-индекс» «замораживание» - тот, который происходит при запуске git add - является отличным местом для выполнения любых преобразований, которые вы хотите выполнить. Вот тут-то и появляются чистые фильтры: чистые фильтры могут удалять вещи, которые не должны входить в реальный коммит в хранилище.

Преобразования конца строки в Git - это просто особые случаи фильтров clean и smudge. Сублимированный файл в репозитории может иметь любые окончания строк. 3 Когда у нас есть Git, скопируйте этот файл из области индекса / размещения, в рабочее дерево, во время git checkout мы можем иметь, например, Git изменить эти окончания строк с LF-only на CRLF. Когда у нас есть Git, скопируйте этот файл из рабочего дерева, в область индекса / размещения, мы можем сделать так, чтобы Git изменил эти окончания строк с CRLF на LF -только.

И это по умолчанию для преобразований CRLF для текстового файла. В результате этих преобразований замененные сублимированные файлы только для LF превращаются в регидратированные файлы CRLF, а преобразованные файлы CRLF заменяются на высушенные сублимацией файлы только LF.

Вы должны получать предупреждение всякий раз, когда Git может обнаружить, что это может сделать что-то отличное от того, что уже делается. Итак, предположим, что файл в .gitattributes в вашем рабочем дереве прямо сейчас имеет окончания строк только для LF. Предположим далее, что лиофилизированная копия в коммите и / или в области index / staging также имеет LF-конец строки. И предположим, что в директивах говорится, что index -> work-tree должен изменить LF-only на CRLF: почему тогда что-то странное, и Git должен предупредить.

Я обнаружил, что эти предупреждения иногда немного счастливы. Я не могу связать это с конкретными случаями в определенных версиях Git, потому что я сам делаю все возможное, чтобы никогда, никогда не позволял Git возиться с моими данными . Я хочу, чтобы копия рабочего дерева каждый раз совпадала с лиофилизированной копией, потому что я избегала ОС, которые требуют особой глупости в конце строки. Но вышеупомянутое является общим правилом, и предупреждение, которое вы получаете сейчас, имеет смысл: реальные файлы сублимационной сушки и файлы рабочего дерева все имеют LF-only окончания строк прямо сейчас , но ваши настройки сообщают Git, что текст из .gitattributes должен был быть преобразован, чтобы иметь окончания строк CRLF в вашем рабочем дереве.


3 И Линус Торвальдс требует, чтобы вам понравились окончания строк только для НЧ. :-) Шутка в сторону, Git вроде как предпочитает это. Если вы отключите все преобразования - вообще не включив CRLF или пометив все файлы как -text, Git сохранит - навсегда! - любую строку, заканчивающуюся вами, говорите. Если вы затем передумали , вы застряли с окончаниями строк, которые вы уже заморозили , потому что ничто в любом коммите не может быть изменено. Если эти коммиты неверны Единственное, что вы можете сделать, это перестать их использовать. Вы можете создавать новые, улучшенные, исправленные и использовать их вместо этого.

Я думаю, что эти "замороженные подтвержденные копии неправильны, потому что они имеют окончания CRLF", которые обычно вызывают фиктивные проблемы с предупреждением об окончании строки CRLF. Поскольку я на самом деле не использую код, преобразующий окончание строки, сам, в этом трудно быть уверенным.

...