Какова лучшая стратегия обработки CRLF (возврат каретки, перевод строки) с Git?

Я попытался зафиксировать файлы с CRLF-концевыми строками, но это не удалось

Я провел целый рабочий день на своем компьютере с Windows, пробуя разные стратегии, и был почти не в силах прекратить попытки использовать Git и вместо этого попробовать Mercurial.

Пожалуйста, поделитесь только одним лучшим опытом для ответа.

9 ответов

Решение

Спустя почти четыре года после того, как я задал этот вопрос, я наконец нашел ответ, который меня полностью устраивает!

Подробности смотрите в github: справочное руководство по работе с окончаниями строк.

Git позволяет вам устанавливать свойства окончания строки для репо, используя атрибут text в .gitattributes файл. Этот файл фиксируется в репо и переопределяет core.autocrlf настройки, позволяющие обеспечить согласованное поведение для всех пользователей независимо от их настроек git.

И поэтому

Преимущество этого состоит в том, что ваша конфигурация конца строки теперь перемещается с вашим хранилищем, и вам не нужно беспокоиться о том, имеют ли соавторы правильные глобальные настройки.

Вот пример .gitattributes файл

# Auto detect text files and perform LF normalization
*        text=auto

*.cs     text diff=csharp
*.java   text diff=java
*.html   text diff=html
*.css    text
*.js     text
*.sql    text

*.csproj text merge=union
*.sln    text merge=union eol=crlf

*.docx   diff=astextplain
*.DOCX   diff=astextplain

# absolute paths are ok, as are globs
/**/postinst* text eol=lf

# paths that don't start with / are treated relative to the .gitattributes folder
relative/path/*.txt text eol=lf

Существует удобная коллекция готовых к использованию файлов.gitattributes для самых популярных языков программирования. Это полезно для начала.

Как только вы создали или скорректировали свой .gitattributes Вы должны выполнить повторную нормализацию окончаний строки раз и навсегда.

Обратите внимание, что приложение GitHub Desktop может предложить и создать .gitattributes файл после открытия репозитория Git вашего проекта в приложении. Чтобы попробовать это, щелкните значок шестеренки (в правом верхнем углу) > Настройки репозитория... > Концы строк и атрибуты. Вам будет предложено добавить рекомендуемые .gitattributes и если вы согласитесь, приложение также выполнит нормализацию всех файлов в вашем хранилище.

Наконец, в статье " Разум в конце своей строки" содержится дополнительная справочная информация и объясняется, как Git развивался в рассматриваемых вопросах. Я считаю это обязательным чтением.

Возможно, в вашей команде есть пользователи, которые используют EGit или JGit (такие инструменты, как Eclipse и TeamCity используют их) для фиксации своих изменений. Тогда вам не повезло, как объясняет @gatinueta в комментариях к этому ответу:

Этот параметр не удовлетворит вас полностью, если в вашей команде есть люди, работающие с Egit или JGit, поскольку эти инструменты будут просто игнорировать.gitattributes и успешно проверять файлы CRLF https://bugs.eclipse.org/bugs/show_bug.cgi?id=342372

Одна хитрость может заключаться в том, чтобы они зафиксировали свои изменения в другом клиенте, скажем SourceTree. Наша команда тогда предпочитала этот инструмент Eclipse EGit для многих случаев использования.

Кто сказал, что программное обеспечение легко?:-/

Не конвертируйте окончания строк. Это не работа VCS, чтобы интерпретировать данные - просто сохраните и версируйте их. Каждый современный текстовый редактор в любом случае может читать оба вида окончаний строк.

Вы почти всегда хотите autocrlf=input если вы действительно не знаете, что делаете.

Некоторый дополнительный контекст ниже:

Должно быть либо core.autocrlf=true если вам нравится конец DOS или core.autocrlf=input если вы предпочитаете unix-newlines. В обоих случаях ваш репозиторий Git будет иметь только LF, что является правильным. Единственный аргумент в пользу core.autocrlf=false было то, что автоматическая эвристика может неправильно определить некоторый двоичный файл как текст, и тогда ваша плитка будет повреждена. Так, core.safecrlf была введена опция для предупреждения пользователя в случае необратимого изменения. На самом деле, есть две возможности необратимых изменений - смешивание конца строки в текстовом файле, при этом нормализация желательна, поэтому это предупреждение можно игнорировать или (очень маловероятно), что Git неправильно определил ваш двоичный файл как текст. Затем вам нужно использовать атрибуты, чтобы сообщить Git, что этот файл является двоичным.

Вышеупомянутый абзац был первоначально извлечен из потока на gmane.org, но с тех пор он отключился.

Две альтернативные стратегии, позволяющие добиться согласованности в окончаниях строк в смешанных средах (Microsoft + Linux + Mac):

A. Глобальная настройка для всех репозиториев

1) конвертировать все в один формат

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) Установить core.autocrlf в input в Linux/UNIX или true на MS Windowns (репозиторий или глобальный)

git config --global core.autocrlf input

3) [Необязательно] установить core.safecrlf в true (остановить) или warn (петь:), чтобы добавить дополнительное охранное сравнение, если обратное преобразование новой строки приведет к тому же файлу

git config --global core.safecrlf true


Б. Или для каждого хранилища

1) конвертировать все в один формат

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) добавить .gitattributes файл в ваш репозиторий

echo "* text=auto" > .gitattributes
git add .gitattributes
git commit -m 'adding .gitattributes for unified line-ending'

Не беспокойтесь о ваших двоичных файлах - Git должен быть достаточно умным с ними.


Подробнее о переменных safecrlf/autocrlf

Я потратил часы, чтобы придумать наилучшее из возможных .gitattributesЧтобы окончательно осознать, что я не могу на это рассчитывать.
К сожалению, пока существуют редакторы на основе JGit (которые не могут обрабатывать .gitattributes правильно), безопасное решение - заставить LF везде, даже на уровне редактора.

Используйте следующее anti-CRLF дезинфицирующие средства.

--- Обновить ---

Даже если вы не хотите использовать вышеуказанную стратегию, следующая команда - ваш друг (Примечание: в Windows клиенты работают только через git-bash и на клиентах linux только если скомпилировано с использованием --with-libpcre в ./configure).

# Print all files that have been committed with CRLF (more correctly that contain CR), so that you normalize them.
git grep -I --files-with-matches --perl-regexp '\r' HEAD

Один болезненный пример:

NetBeans 8.2 (в Windows) будет некорректно фиксировать все текстовые файлы с CRLF в репо, если вы не установили явно core.autocrlfкак глобальный. Это противоречит стандартному поведению клиента git и вызывает много проблем позже при обновлении / слиянии. Это то, что заставляет некоторые файлы выглядеть по-разному (хотя это не так), даже когда вы возвращаетесь.
Такое же поведение в NetBeans происходит, даже если вы добавили правильный .gitattributes к вашему проекту.

Использование приведенной выше команды после коммита, по крайней мере, поможет вам на раннем этапе определить, есть ли у вашего git-репо проблемы с окончанием строки.

С помощью core.autocrlf=false прекратил помечать все файлы как обновленные, как только я проверил их в своем проекте Visual Studio 2010. Два других члена команды разработчиков также используют системы Windows, поэтому смешанная среда не вошла в игру, но настройки по умолчанию, поставляемые с хранилищем, всегда отмечали все файлы как обновленные сразу после клонирования.

Я думаю, суть в том, чтобы найти, какой параметр CRLF работает в вашей среде. Тем более что во многих других репозиториях на наших установках Linux ящики autocrlf = true дает лучшие результаты.

Спустя 20 с лишним лет, и мы все еще имеем дело с разницей в конце строк между операционными системами... грустно.

Попробуйте установить core.autocrlf опция конфигурации для true, Также посмотрите на core.safecrlf вариант.

На самом деле это звучит как core.safecrlf может быть уже установлен в вашем хранилище, потому что (выделение мое):

Если это не относится к текущим настройкам core.autocrlf, git отклонит файл.

Если это так, то вы можете проверить, что ваш текстовый редактор настроен на последовательное использование концов строк. Скорее всего, вы столкнетесь с проблемами, если текстовый файл будет содержать сочетания концов строк LF и CRLF.

Наконец, я чувствую, что рекомендация просто "использовать то, что вам дано" и использовать строки с ограничением LF в Windows, вызовет больше проблем, чем решит. У Git есть вышеупомянутые опции, чтобы попытаться обработать окончания строк разумным способом, поэтому имеет смысл использовать их.

Это две опции для пользователей Windows и Visual Studio, которые делятся кодом с пользователями Mac или Linux. Для подробного объяснения прочитайте руководство по gitattributes.

* текст = авто

В вашем репо .gitattributes добавление файла:

*   text=auto

Это нормализует все файлы с LF окончания строк в репо.

И в зависимости от вашей операционной системы (core.eol настройки), файлы в рабочем дереве будут нормализованы к LF для систем на базе Unix или CRLF для систем Windows.

Это конфигурация, которую используют репозитории Microsoft .NET.

Пример:

Hello\r\nWorld

Будет нормализован в репо всегда так:

Hello\nWorld

При оформлении заказа рабочее дерево в Windows будет преобразовано в:

Hello\r\nWorld

На кассе рабочее дерево в Mac останется как:

Hello\nWorld

Примечание. Если репозиторий уже содержит файлы, которые не были нормализованы, git status эти файлы будут полностью изменены в следующий раз, когда вы внесете в них какие-либо изменения, и другим пользователям будет неудобно объединять их изменения позже. См. Обновление хранилища после изменения концов строк для получения дополнительной информации.

core.autocrlf = true

Если text не указано в .gitattributes Git использует core.autocrlf переменная конфигурации, чтобы определить, должен ли файл быть преобразован.

Для пользователей Windows, git config --global core.autocrlf true отличный вариант, потому что:

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

Проблема с этим подходом заключается в том, что:

  • Если вы пользователь Windows с autocrlf = input, вы увидите кучу файлов с LF окончания строки. Не представляет опасности для остальной части команды, потому что ваши коммиты все равно будут нормализованы с LF окончания строки.
  • Если вы пользователь Windows с core.autocrlf = false, вы увидите кучу файлов с LF окончания строк, и вы можете ввести файлы с CRLF Концы строк в репо.
  • Большинство пользователей Mac используют autocrlf = input и может получить файлы с CRLF окончания файлов, вероятно, от пользователей Windows с core.autocrlf = false,

Это просто обходное решение:

В обычных случаях используйте решения, которые поставляются с git. Они прекрасно работают в большинстве случаев. Принудительно LF, если вы делитесь разработкой в ​​системах на базе Windows и Unix, устанавливая .gitattributes.

В моем случае>10 программистов разрабатывали проект в Windows. Этот проект был проверен с CRLF, и не было никакой возможности, чтобы заставить LF.

Некоторые настройки были написаны на моем компьютере без какого-либо влияния на формат LF; таким образом, некоторые файлы глобально менялись на LF при каждом небольшом изменении файла.

Мое решение:

Windows-машины: пусть все как есть. Ничего не волнует, так как вы являетесь разработчиком окон "одинокий волк" по умолчанию, и вам приходится обращаться с этим так: "В широком мире нет другой системы, не так ли?"

Unix-машины

  1. Добавьте следующие строки в конфиг [alias] раздел. Эта команда выводит список всех измененных (т.е. измененных / новых) файлов:

    lc = "!f() { git status --porcelain \
                 | egrep -r \"^(\?| ).\*\\(.[a-zA-Z])*\" \
                 | cut -c 4- ; }; f "
    
  2. Преобразуйте все эти измененные файлы в формат DOS:

    unix2dos $(git lc)
    
  3. По выбору...

    1. Создайте git hook для этого действия, чтобы автоматизировать этот процесс

    2. Используйте параметры и включите их и измените grep функция для соответствия только определенным именам файлов, например:

      ... | egrep -r "^(\?| ).*\.(txt|conf)" | ...
      
    3. Не стесняйтесь делать это еще удобнее, используя дополнительный ярлык:

      c2dos = "!f() { unix2dos $(git lc) ; }; f "
      

      ... и запустить преобразованный материал, набрав

      git c2dos
      
Другие вопросы по тегам