Git. Символы конца строки EOL
15.07.2022
Теги: Git • IDE • Linux • Web-разработка • Windows • Конфигурация • Настройка • Файл
Символы конца строки EOL для текстовых файлов различаются в зависимости от операционной системы. Linux использует перевод строки LF, Windows использует возврат каретки + перевод строки CRLF. Если несколько разработчиков работают над одним проектом на GitHub под разными операционными системами — бардак практически гарантирован.
Главное, что нужно помнить — в репозитории все текстовые файлы должны быть с окончаниями LF.
Настройки EOL для Git
Настройка core.eol
имеет значение по умолчанию native
, другие возможные значения — это lf
и crlf
. Git использует значение этой настройки, когда записывает файлы в рабочую директорию при выполнении таких команд, как git checkout
или git clone
. Имеет смысл, только если core.autocrlf
равно true
.
Настройка core.autocrlf
имеет значение по умолчанию false
, другие возможные значения — это true
и input
. Настройка определяет, будет ли Git выполнять какие-либо преобразования EOL при записи/чтении в/из репозитория. Значение по умолчанию опасно, потому что может привести к записи в репозиторий CRLF файлов.
core.autocrlf=false
— ничего не делать при записи в репозиторий, ничего не делать при чтении из репозиторияcore.autocrlf=input
— при записи в репозиторий заменять CRLF на LF, при чтении из репозитория ничего не делатьcore.autocrlf=true
— при записи в репозиторий заменять CRLF на LF, при чтении из репозитория заменять LF наcore.eol
Значение input
подходит при работе под Linux:
$ git config --local core.eol native $ git config --local core.autocrlf input
Значение true
подходит при работе под Windows:
$ git config --local core.eol native $ git config --local core.autocrlf true
При выполнении этих команд будет создан файл .git/config
в директории проекта:
[core] eol = native autocrlf = input
[core] eol = native autocrlf = true
Можно записать эти значения в глобальный файл конфигурации Git ~/.gitconfig
, если заменить --local
на --global
.
Все настройки Git
Поскольку мы тут работаем с настройками Git, есть смысл упомянуть, какие они бывают и как их посмотреть.
- Системная конфигурация Git управляет настройками для всех пользователей и всех репозиториев на компьютере.
- Глобальная конфигурация Git управляет настройками текущего вошедшего пользователя и всех его репозиториев.
- Локальная конфигурация Git управляет настройками для отдельно взятого репозитория.
Эти три файла конфигурации выполняются в каскадном порядке — сначала системный, затем глобальный, и наконец, локальный. Это означает, что локальная конфигурация Git всегда будет перезаписывать настройки, установленные в глобальной или системной конфигурации.
$ git config --list $ git config --list --system $ git config --list --global $ git config --list --local
Если не указать, какую конфигурацию надо показать (первая команда) — будут показаны все три конфигурации, объединенные в вывод консоли. Чтобы посмотреть настройки вместе с именем файла конфигурации, можно использовать ключ show-origin
.
$ git config --list --show-origin file:C:/Program Files/Git/etc/gitconfig http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt file:C:/Program Files/Git/etc/gitconfig http.sslbackend=openssl file:C:/Program Files/Git/etc/gitconfig diff.astextplain.textconv=astextplain .......... file:C:/Users/Evgeniy/.gitconfig user.name=Evgeniy Tokmakov file:C:/Users/Evgeniy/.gitconfig user.email=............... file:C:/Users/Evgeniy/.gitconfig core.autocrlf=false .......... file:.git/config core.repositoryformatversion=0 file:.git/config core.filemode=false file:.git/config core.bare=false ..........
$ git config --list --show-origin | grep autocrlf file:C:/Program Files/Git/etc/gitconfig core.autocrlf=true file:C:/Users/Evgeniy/.gitconfig core.autocrlf=false file:.git/config core.autocrlf=true
Небольшой эксперимент
У меня операционная система Windows. Создаем директорию repo-eol-example
, внутри нее — текстовой файл file.txt
. Добавим в файл пару строк и убедимся, что окончания строк — CRLF.
Переходим в директорию проекта, выполняем три команды
$ git init $ git config --local core.eol native $ git config --local core.autocrlf true
Добавляем наш файл в индекс и фиксируем изменения
$ git add file.txt $ git commit -m "add file.txt"
Добавляем в наш файл еще строку, чтобы он изменился
И восстановим его из репозитория в изначальном виде
$ git checkout -- file.txt
Что произошло? При добавлении файла в репозиторий (commit) символы CRLF были заменены на LF. При извлечении файла в рабочую директорию (checkout) — символы LF были заменены на CRLF.
Давайте убедимся в том, что в репозитории у нас символы LF. Для этого изменим настройку Git, чтобы вообще никаких замен не было. Добавим в файл строку, а потом восстановим из репозитория в изначальном виде.
$ git config --local core.autocrlf false $ git checkout -- file.txt
Что произошло? При извлечении файла в рабочую директорию — символы EOL остались без изменений, как они сохранены в репозитории.
Предупреждения от Git
Когда случается нештатная ситуация — Git предупреждает об этом. Например, если мы установили следующие настройки для Git:
$ git config --local core.eol native $ git config --local core.autocrlf input
И пытаемся записать CRLF файл в репозиторий — Git предупреждает, что символы CRLF будут заменены на LF (при записи в репозиторий). Тут ситуация явно нештатная — вроде бы настройки соответствуют Linux, но при этом в рабочей директории откуда-то взялся CRLF файл, а этого быть не должно.
$ git add other.txt warning: CRLF will be replaced by LF in other.txt. The file will have its original line endings in your working directory
При извлечении такого файла из репозитория в рабочую директорию — никаких преобразований EOL не будет, потому что input
работает только при записи в репозиторий. И мы получим LF окончания строк в этом файле — так, как и должно быть в Linux.
Еще одна нештатная ситуация — мы установили следующие настройки для Git:
$ git config --local core.eol native $ git config --local core.autocrlf true
И пытаемся записать LF файл в репозиторий — Git предупреждает, что символы LF будут заменены на CRLF (при чтении из репозитория). Тут ситуация явно нештатная — вроде бы настройки соответствуют Windows, но при этом в рабочей директории откуда-то взялся LF файл, а этого быть не должно.
$ git add another.txt warning: LF will be replaced by CRLF in another.txt. The file will have its original line endings in your working directory
При извлечении такого файла из репозитория в рабочую директорию — будет выполнена замена LF на CRLF. И мы получим CRLF окончания строк в этом файле — так, как и должно быть в Windows.
Тут важно то, что как в первой, так и во второй ситуации — файл будет сохранен в репозитории с LF окончаниями строк, как и должно быть.
Настройка core.safecrlf
Как Git узнает, что файл является текстовым? У Git есть внутренний метод эвристической проверки, является ли файл двоичным или нет. Файл считается текстовым, если он не является двоичным. Git иногда может ошибаться — и по этой причине существует настройка core.safecrlf
.
Эту настройку нужно установить в значение true
. Тогда при подготовке к замене CRLF на LF — Git проверит, что сможет успешно отменить операцию. Это защита от того, чтобы выполнить замену в файле, который не является текстовым — и, тем самым, безнадежно его испортить.
Работа под Windows
Лично мне удобно везде использовать LF, хотя у меня основная система Windows — поэтому установил себе настройки, чтобы вообще не заменять EOL.
$ git config --global core.eol lf $ git config --global core.autocrlf false
Современные IDE способны работать под Windows с EOL как в Linux, так что необходимости в заменах просто нет. В настройках VS Code у меня установлено значение LF для EOL.
{ .......... "files.eol": "\n", // символ конца строки как в linux .......... }
Чтобы следить за символами конца строки — можно установить расширение «Render Line Endings», которое показывает символы LF и CRLF.
{ .......... "editor.renderWhitespace": "all", // показывать символы пробелов "files.eol": "\n", // символ конца строки как в linux .......... "code-eol.newlineCharacter": "↓", // символ LF "code-eol.crlfCharacter": "←↓", // символы CRLF // подсвечивать как ошибку EOL в файле, если не совпадает с настройкой files.eol "code-eol.highlightNonDefault": true, }
Когда в проект случайно попадёт файл с CRLF символами конца строки — эти символы будут подсвечены красным цветом (вообще, цветом errorForeground
темы).
Но такая подсветка будет всего секунду, потому что у меня еще настроено автосохранение открытых файлов — и файл будет сохранен с окончаниями LF.
{ .......... "editor.renderWhitespace": "all", // показывать символы пробелов "files.eol": "\n", // символ конца строки как в linux "files.autoSave": "afterDelay", // автоматическое сохранение файла "files.autoSaveDelay": 1000, // задержка перед сохранением файла .......... "code-eol.newlineCharacter": "↓", // символ LF "code-eol.crlfCharacter": "←↓", // символы CRLF // подсвечивать как ошибку EOL в файле, если не совпадает с настройкой files.eol "code-eol.highlightNonDefault": true, }
Чтобы настройки VS Code всегда были правильными, можно создать файл .editorconfig
в корне проекта и установить расширение «EditorConfig for VS Code». Расширение читает файл .editorconfig
и устанавливает правильные настройки VS Code.
# эта настройка должна быть в самом начале; если установлена в true, # парсер не будет искать другие конфиги родительских директориях root = true # правила для текстовых файлов [*.{txt,md,html,css,scss,js,jsx,ts,tsx,py,php,json,xml,sh}] # кодировка файлов charset = utf-8 # концы строк как в linux end_of_line = lf # пустая строка в конце файла insert_final_newline = true # удалять пробелы в конце строк trim_trailing_whitespace = true # заменять табуляцию на пробелы indent_style = space # табуляция заменяется 4 пробелами indent_size = 4
{ .......... "files.encoding": "utf8", // кодировка файлов "files.eol": "\n", // концы строк как в linux "files.insertFinalNewline": true, // пустая строка в конце файла "files.trimTrailingWhitespace": true, // удалять пробелы в конце строк "editor.insertSpaces": true, // заменять табуляцию на пробелы "editor.tabSize": 4, // табуляция заменяется 4 пробелами .......... }
Еще лучше — разместить файл .editorconfig
в корне директории, которая содержит все проекты, над которыми идет работа. Тогда при открытии любого проекта VS Code будет подхватывать этот файл и его не надо будет создавать отдельно для каждого проекта.
Работа в команде
В настоящее время настройку core.autocrlf
использовать нежелательно. На смену ей пришел файл .gitattributes
в корне рабочей директории проекта, который нужно добавить под наблюдение Git.
* text=auto
$ git add .gitattributes $ git commit -m "Add .gitattributes"
Тем самым мы говорим Git, чтобы он самостоятельно определял текстовые файлы и заменял CRLF на LF при записи в репозиторий. Это эквивалентно установке core.autocrlf=true
в файле конфигурации, но файл .gitattributes
имеет приоритет над файлом конфигурации.
Таким образом, у всех разработчиков, которые работают над одним проектом, будет одинаковое поведение Git при записи в репозиторий. А вот настройка core.eol
у каждого разработчика будет своя, из файла конфигурации на компьютере. И извлекать файлы в рабочую директорию разработчик может с любыми окончаниями — LF или CRLF.
.gitattributes
нет — Git по старинке будет использовать core.autocrlf
из файла конфигурации для замены символов EOL.
Если случилась беда
Все-таки это произошло — в репозиторий попали CRLF файлы. Проверить это можно с помощью команды
$ git ls-files --eol i/crlf w/crlf attr/ file-crlf-one.txt i/crlf w/crlf attr/ file-crlf-two.txt i/lf w/lf attr/ file-lf-one.txt i/lf w/lf attr/ file-lf-two.txt
Первая колонка — окончания строк в репозитории, вторая колонка — окончания строк в рабочей директории. Такая команда может выдать несколько тысяч строк, а нам интересно — есть ли вообще в репозитории такие файлы, так что нужен фильтр.
$ git ls-files --eol | grep "i/crlf" i/crlf w/crlf attr/ file-crlf-one.txt i/crlf w/crlf attr/ file-crlf-two.txt
Давайте наведем порядок — создадим файл .gitattributes
, добавим его в репозиторий, выполним команду нормализации EOL в репозитории.
* text=auto
$ git add .gitattributes $ git commit -m "Add .gitattributes" [master 347c98e] Add .gitattributes 1 file changed, 1 insertion(+) create mode 100644 .gitattributes
$ git add --renormalize .
$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: file-crlf-one.txt modified: file-crlf-two.txt $ git commit -m "Normalize eol" [master e54c4b7] Normalize eol 2 files changed, 4 insertions(+), 4 deletions(-)
Смотрим, что у нас теперь в репозитории — все хорошо, все окончания строк сейчас LF:
$ git ls-files --eol i/none w/none attr/text=auto .gitattributes i/lf w/crlf attr/text=auto file-crlf-one.txt i/lf w/crlf attr/text=auto file-crlf-two.txt i/lf w/lf attr/text=auto file-lf-one.txt i/lf w/lf attr/text=auto file-lf-two.txt
Теперь надо заменить файлы в рабочей директории, для этого выполняем две команды:
$ git rm --cached -r . rm '.gitattributes' rm 'file-crlf-one.txt' rm 'file-crlf-two.txt' rm 'file-lf-one.txt' rm 'file-lf-two.txt' $ git reset --hard HEAD is now at e54c4b7 Normalize eol
Смотрим, что у нас теперь в рабочей директории (у меня Windows и core.eol
установлена в native
):
$ git ls-files --eol i/none w/none attr/text=auto .gitattributes i/lf w/crlf attr/text=auto file-crlf-one.txt i/lf w/crlf attr/text=auto file-crlf-two.txt i/lf w/crlf attr/text=auto file-lf-one.txt i/lf w/crlf attr/text=auto file-lf-two.txt
Дополнительно
- Расширение «ESLint» для VS Code, часть 2 из 2
- Расширение «ESLint» для VS Code, часть 1 из 2
- Расширение «Prettier — Code formatter» для VS Code
- Отладка с помощью xdebug в PhpStorm
- GitHub Actions. Начало работы, часть 2 из 2
- GitHub Actions. Начало работы, часть 1 из 2
- Настройка PhpStorm для работы с Laravel
Поиск: Git • Linux • Web-разработка • Windows • Конфигурация • Настройка • EOL • CRLF • LF • Файл • IDE