В чем разница между autocrlf и eol
Я читаю git документацию о .gitattributes
чтобы исправить мои проблемы со смешанными окончаниями строк и выяснить, что есть две похожие настройки.
AUTOCRLF:
Конвертация конца строки Хотя Git обычно оставляет содержимое файла в покое, он может быть сконфигурирован для нормализации конца строки в LF в хранилище и, при необходимости, для преобразования их в CRLF при извлечении файлов.
Если вы просто хотите иметь окончания строк CRLF в вашем рабочем каталоге независимо от того, с каким репозиторием вы работаете, вы можете установить переменную конфигурации "core.autocrlf" без использования каких-либо атрибутов.
[core] autocrlf = true Это не вызывает нормализацию текстовых файлов, но гарантирует, что текстовые файлы, которые вы вводите в репозиторий, при добавлении их концов строк нормализуются по LF, а файлы, которые уже нормализованы в репозитории, остаются нормализуется.
И EOL:
Этот атрибут устанавливает определенный стиль окончания строки, который будет использоваться в рабочем каталоге. Он позволяет конвертировать в конец строки без каких-либо проверок содержимого, эффективно устанавливая атрибут текста.
Установить строковое значение "crlf" Этот параметр заставляет Git нормализовать окончания строк для этого файла при регистрации и преобразовывать их в CRLF при извлечении файла.
Set to string value "lf" Этот параметр заставляет Git нормализовать окончания строк до LF при регистрации и предотвращает преобразование в CRLF при извлечении файла.
Обратная совместимость с атрибутом crlf Для обратной совместимости атрибут crlf интерпретируется следующим образом:
текст crlf
-crlf -text
crlf = входной eol=lf
Кажется, что оба делают то же самое, но есть что-то compatibility
, Означает ли это, что autocrlf
устарела и новый вкус eol
или что-то? В настоящее время у меня есть хранилище с несколькими поврежденными файлами, которые я хочу преобразовать в crlf
представление. И вы видите, что документация сбивает нас с толку, а не проясняет.
Что я должен применить в этой ситуации?
1 ответ
Вместо непосредственного ответа на сам вопрос - см . Ответ VonC на связанный вопрос для этого - давайте сконцентрируемся на этом:
В настоящее время у меня есть хранилище с несколькими поврежденными файлами, которые я хочу преобразовать в представление crlf.
Во-первых, отметим, что ни один из этих параметров не может изменить какой-либо существующий коммит. Это фундаментальное свойство Git: после создания ни один из существующих коммитов не может быть изменен. Что вы можете сделать, это сделать новые коммиты. Обычно это не так уж важно, поскольку обычно мы хотим, чтобы новые вещи были правильными (но посмотрим git filter-branch
, который копирует коммиты после применения фильтров к их содержимому и может быть использован для повторного копирования всего хранилища: новое хранилище больше не совместимо со старым, но вы можете таким образом "исправить историю").
Далее, я думаю, что это ключ к пониманию всех этих параметров атрибута конца строки / CRLF: преобразования применяются к файлам, когда они входят или выходят из индекса.
Помните, что индекс Git - это место, где вы строите следующий коммит. Содержимое индекса изначально совпадает с текущим коммитом: вы запускаете git checkout master
например, и Git разрешает имя master
к идентификатору фиксации и копирует этот конкретный коммит в ваше рабочее дерево, но копия проходит через индекс.
Другими словами, Git сначала находит этот файл foo.txt
находится в коммите (и должен быть извлечен). Так Git перемещает эту версию foo.txt
в указатель. Версия индекса точно соответствует HEAD
версия коммита. Git не применяет фильтры к версии индекса и не изменяет окончания строк.
После обновления версии индекса Git копирует эту версию файла из индекса в рабочее дерево. 1 Некоторые преобразования происходят сейчас, во время этого процесса извлечения. Если есть грязный фильтр, Git применяет его сейчас. Если есть конверсии в конце строки, Git применяет их сейчас.
Файл рабочего дерева во время этого процесса может отличаться от версии индекса. Теперь у Git есть проблема, потому что теперь файл "грязный" (изменен в рабочем дереве). Здесь вещи становятся особенно запутанными, хотя в большинстве случаев детали здесь невидимы.
В конце концов, после работы с вашим рабочим деревом, вы можете запустить git add
по какому-либо пути к файлу (или используйте git add -a
или что угодно, чтобы добавить много файлов). Это копирует файл из рабочего дерева в индекс. 2 Во время этой копии теперь происходят другие преобразования: если есть чистый фильтр, Git применяет его сейчас. Если есть конверсии в конце строки, Git применяет их сейчас.
Другими словами, после git add
-при этих файлах версия индекса может не соответствовать версии рабочего дерева. Тем не менее, Git помечает индексную версию как "совпадающую" в любом случае. git status
будет пропускать версию рабочего дерева, потому что теперь Git утверждает, что индексная версия совпадает с версией рабочего дерева. Это вроде как, потому что индексная версия соответствует тому, что будет добавлено, если вы запустите git add
снова.
Фактическая реализация использует метки времени, обычно с разрешением в одну секунду. Git будет продолжать полагать, что версия индекса соответствует версии рабочего дерева, если и до тех пор, пока ОС не коснется отметки времени в версии файла рабочего дерева. Это верно даже в том случае, если вы измените набор фильтров и / или конечных преобразований для применения. Git не понимает, что вы изменили способ окончания строк или изменили "чистый" фильтр, чтобы сделать что-то другое: он просто видит, что аспект "кэша" индекса говорит: "Я соответствую метке времени версии рабочего дерева Т ". Пока отметка времени версии рабочего дерева все еще T, файл должен быть "чистым".
Следовательно, чтобы обновить эти вещи после изменения любых настроек преобразования текста, вы должны заставить Git понять, что файл не чистый. Вы можете touch <path>
установить новую метку времени "сейчас", которая не будет соответствовать старой метке времени в индексе. Сейчас git add -a
(или что-то еще) будет сканироваться как обычно, но поскольку метки времени не совпадают, он найдет файл на этот раз и повторно отфильтрует его, чтобы добавить в индекс.
Опять же, эти преобразования происходят, когда вы git add
файл.
Обычно в Windows-подобной системе ваша цель - взять файлы формата репозитория только для LF и превратить их в файлы CR-LF для работы с Windows. Это преобразование происходит при выходе из индекса в рабочее дерево, т. Е. Во время git checkout
, Затем вы захотите преобразовать эти файлы рабочего дерева CR-LF в формат LF-only во время git add
процесс, так что форма в репозитории - это способ, которым Linux (и Линус Торвальдс и, следовательно, Git:-)) предпочитают их. Но вы можете хранить их в репозитории в формате CR-LF, если вы действительно хотите раздражать всех пользователей Unix/Linux. Все дело в том, какие преобразования, если они есть, вы применяете на следующих этапах: git checkout
время и git add
время.
.gitattributes
Файл указывает, какие преобразования применяются к каким файлам. core.autocrlf
а также core.eol
Настройки этого не делают: Git должен сделать лучшее предположение о том, какие файлы получают, какие преобразования на каком этапе.
1 Технически все, что находится в индексе, - это хэш-идентификатор файла. Сам файл хранится как объект блоба Git в базе данных репозитория. Как и в случае с объектами коммитов, эти объекты BLOB-объектов неизменны. Вот почему его нельзя изменить в индексе: на самом деле это просто хэш-идентификатор.
2 git add
процесс просто записывает новый BLOB-объект, а новый BLOB-объект записывается после любой фильтрации. Если новый большой двоичный объект в точности совпадает с существующим большим двоичным объектом, новый большой двоичный объект повторно использует запись базы данных существующего большого двоичного объекта и идентификатор хеша и фактически не сохраняется - существующего большого двоичного объекта достаточно. Если нет, данные блоба сохраняются как новый файл с новым идентификатором. Это новый идентификатор хеша, который входит в индекс.