Как заставить git понимать окончания строк в Mac (CR) - PullRequest
0 голосов
/ 05 сентября 2018

По некоторым причинам один из моих файлов содержит окончания строк Mac старого стиля (после редактирования в OSX). Это символы "CR" (возврат каретки), которые отображаются как ^ M в git diff.

Git не понимает, что они являются кодами конца строки (действительно, насколько сложно это может быть?) И интерпретирует весь файл как одну строку.

Я знаю, что могу преобразовать файлы в окончания LF или CRLF и затем зафиксировать их обратно, однако, поскольку git автоматически преобразует мои окончания строк в Windows (CRLF) в LF, я надеялся, что он позаботится об окончаниях строк CR как Что ж. В противном случае это звучит как неполная функциональность.

Есть ли способ заставить git интерпретировать CR как конец строки?

1 Ответ

0 голосов
/ 05 сентября 2018

TL; DR

Создайте драйвер фильтра плюс .gitattributes: создайте нечеткий фильтр , который запускает tr '\n' '\r', и clean filter , который запускает tr '\r' '\n', и отметьте файл (ы) вопрос как использовать этот фильтр. Сохраните файл внутри Git, используя LF-only окончания строк. (Драйвер фильтра определен в файле .git/config или $HOME/.gitconfig, а имена или шаблоны имен файлов указаны в .gitattributes.)

Long

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

Современные MacOS, как и все остальные, используют переводы строки. Только древние обратно совместимые форматы имеют только строки CR. См., Например, на этом веб-сайте SuperUser Stack Exchange: .

Git не имеет встроенного фильтра для преобразования в или из таких концов строк. Git имеет , однако имеет механизм общего назначения для внесения изменений в файлы рабочего дерева.

Помните, что когда Git сохраняет какой-либо файл в моментальном снимке, файл представлен тем, что Git называет BLOB-объектом , который хранится внутри в специальном сжатом (иногда сильно сжатом), только для Git форма. Эта форма бесполезна ни для чего , но Git, поэтому, когда вы получаете файлы в полезной форме - например, через git checkout - Git расширяет их в их обычную для вашего компьютера форму. Между тем, всякий раз, когда вы берете обычный файл, подобный этому, и конвертируете его в форму только для Git, Git сжимает файл до его формы только для Git. Это происходит всякий раз, когда вы копируете файл обратно в Git index , используя git add.

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

Это копирование в или из индекса и рабочего дерева является идеальной точкой для преобразования LF-в-CRLF в стиле Windows или наоборот, так что именно здесь Git делает это. Если у вас есть какое-то преобразование другое , которое не встроено непосредственно в Git, вы можете сказать Git сделать это.

Пятна и чистые фильтры

A smudge filter - это фильтр, который Git применяет при преобразовании файла из сжатой индексной копии в копию рабочего дерева. Здесь, если вы выбрали замену символов новой строки на CRLF в стиле «конец строки или разделители» в стиле Windows, у Git есть внутренний конвертер, который сделает это: eol=crlf. clean filter - это тот, который Git применяет при преобразовании файла из несжатой копии рабочего дерева в сжатую индексную копию; и здесь eol=crlf указывает Git выполнить обратное преобразование.

Если вы хотите заменить переводы строк только на CR, вы должны придумать свои собственные конвертеры. Допустим, вы называете общий процесс convert-cr:

*.csv   filter=convert-cr

(вместо *.csv eol=crlf). Эта строка переходит в .gitattributes (файл, который можно зафиксировать, и вы должны его зафиксировать).

Теперь вы должны определить фильтр convert-cr. Это происходит в файле конфигурации Git, и здесь мы обнаруживаем небольшой недостаток: файл конфигурации не является коммитируемым. Это проблема безопасности: Git будет запускать здесь произвольные команды, и если я смогу зафиксировать этот файл, а вы клонируете его, вы запустите команды I , не имея возможности сначала их проверить. Таким образом, вы должны поместить это в ваш .git/config самостоятельно или в глобальную конфигурацию (например, git config --global --edit):

[filter "convert-cr"]
    clean = tr '\r' '\n'
    smudge = tr '\n' '\r'

Теперь, когда Git конвертирует из формата Git-only, он переводит символы новой строки в CR, а всякий раз, когда Git преобразует в Git-only формат, он переводит CR в символы новой строки. .

Это не помогает с существующими сохраненными файлами

Все имеющиеся у вас сегодня снимки, содержащие \r, сохраняются таким образом навсегда. Git никогда не изменит существующий сохраненный файл! Сохраненные данные драгоценны и нерушимы. С этим ничего не поделаешь. Что ж, в почти ничего нет: вы можете полностью выбросить эти коммиты, делая новые и улучшенные коммиты, которые вы используете вместо этого. Но это довольно болезненно: каждый коммит запоминает свои родительские коммиты, поэтому, если вы замените ранний коммит в своем хранилище, вы должны заменить каждого ребенка, внука и т. Д., Чтобы они все помнят эту новую последовательность коммитов. (git filter-branch делает эту работу.)

Однако вы можете указать Git, как diff конкретные файлы в существующих коммитах, также используя .gitattributes и diff драйверы . Есть несколько способов сделать это, но самый простой - определить атрибут textconv , который превращает «двоичный» файл, например, файл, в сохраненной версии которого могут быть только символы CR, в текст ( файл, ориентированный на строку, т. е. на новую строку. Используемый здесь фильтр textconv точно такой же, как и фильтр smudge.

Подробнее см. в документации gitattributes .

...