Следите за концом строки
- 21 марта 2019
Перевод статьи Тима Клема «Mind the End of Your Line»
Один из самых частых вопросов о Гите — почему так сложно работать с окончаниями строк. В этой статье мы попробуем ответить на этот вопрос и рассказать о множестве опций и настроек для контроля над окончаниями строк в Гите.
Гит имеет дело с двумя системами для работы с концами строк в репозиториях. Корень проблемы в том, что популярные операционные системы по-разному обозначают конец строки: Unix, Linux и Mac OS X используют LF
, а Windows CRLF
. В этой статье мы не будем брать во внимание, что в предыдущих версиях Mac OS X использовался CR
.
Ничего из этого не было бы проблемой, если бы каждый из нас жил в своём маленьком, изолированном мире и никогда не обменивался кодом между разными операционными системами. Под обменом кодом, в данном случае, будем понимать всё — от работы над кросс-платформенным проектом до копирования кода из браузера. Всякий раз, когда вы скачиваете архив проекта с Гитхаба, копируете код из чьего-то блога или гиста или используете код из файла на облачном хранилище, вы работаете с текстом, а значит имеете дело с невидимыми символами окончаний строк.
Все эти действия с кодом потенциально могут привнести разные настройки окончаний строк в вашу кодовую базу. Это может привести к беспорядочным диффам и сделать работу с Гитом в целом неприятной.
Основное решение, которое принял Гит для этой проблемы — указать, что лучший способ хранить окончания строк в репозитории для текстовых файлов — использование LF
. Это правило ни к чему вас не принуждает, но большинство разработчиков, использующих Гит и Гитхаб, приняли его как соглашение и мы тоже рекомендуем так настроить ваш конфиг.
Основы
Перед тем, как мы опишем настройки для управления окончаниями строк, нам надо узнать несколько вещей о core.eol
и разобраться с тем, что значит записать что-либо в базу данных Гит.
Конец строки
core.eol
— первый параметр, о котором нужно знать.
Почти всегда, кроме самых редких случаев, нам не стоит менять дефолтное значение этого параметра. Хотя сам по себе core.eol
мало что делает, нам нужно знать его значение каждый раз, когда мы хотим, чтобы Гит изменил окончания строк. Так как этот параметр будет использоваться во всём, о чём пойдёт речь дальше, хорошо бы знать о его существовании и о том, что его значение, вероятно, менять не придётся.
core.eol = native
— значение по умолчанию. При записи файла в рабочую папку, Гит изменит окончания строк на соответствующие вашей платформе по умолчанию. Для Windows это будетCRLF
, для Unix, Linux и Mac OS X —LF
;core.eol = crlf
— если установлено такое значение, Гит всегда будет использовать для обозначения конца строкиCRLF
при записи файла в вашу рабочую директорию;core.eol = lf
— это значение скажет Гиту всегда использоватьLF
для обозначения конца строки при записи файла в вашу рабочую папку.
Чтобы узнать, какое значение core.eol
установлено в вашей системе, нужно запустить в консоли команду git config --global core.eol
. Если команда ничего не вернёт, значит, в вашей системе используется значение по умолчанию, native
.
Запись и вывод объектов из базы данных
Прежде чем двигаться дальше, мы поговорим о двух важных операциях: записи в объектную базу и выводе данных из неё в рабочую директорию. Возможно, вы уже знаете, что Гит хранит свою базу данных в папке .git
. Он создаёт эту директорию и несколько файлов в ней, после запуска команды git init
. Файлы в папке .git
определяют все конфигурации Гита, в них хранится история проекта. Это обычные файлы и мы можем их читать и редактировать так же, как файлы самого проекта.
Каждый раз, когда мы делаем команду типа git commit
, мы записываем объекты в эту базу данных. Запись в базу данных включает в себя:
- сохранение всего содержимого файла;
- добавление его в список со всеми файлами, которые отслеживает Гит;
- создание блоб-файла;
- вычисление SHA-ключа — хэш-кода, в котором хранится информация о содержимом файла.
Во время записи в базу данных Гит может запустить фильтры и преобразовать окончания строк.
Есть ещё один случай, когда у Гита появляется возможность преобразовать окончания строк — это запись файлов из базы данных в нашу рабочую папку. Это то, что мы подразумеваем под выводом из базы данных. Такой процесс можно запустить множеством команд, но самая очевидная и простая для понимания — git checkout
. Вывод из объектной базы данных также происходит после запуска команд, которые делают изменения в нашей рабочей папке, например, git clone
или git reset
.
Старая система
Теперь давайте поговорим о старой системе — оригинальном наборе функций в Гите, предназначенном для решения конкретной проблемы с окончаниями строк. Есть большая вероятность, что вы прямо сейчас пользуетесь старой системой и даже не подозреваете об этом.
Вот как это работает: у Гита есть настройка конфигураций core.autocrlf
, которая специально создана для того, чтобы все окончания строк в текстовом файле преобразовывались в LF
при записи в объектную базу данных репозитория. Вот список разных настроек для core.autocrlf
и их значений:
core.autocrlf = false
— это значение по умолчанию, которое большинству людей следует сменить. Результатом использования этого значения станет то, что Гит не будет связываться с окончаниями строк в ваших файлах. Там могут быть разные окончаниями строк:LF
,CRLF
,CR
или микс из всех них, но Гиту это будет безразлично. Такое значение может привести к тому, что диффы станут менее читаемыми и появятся сложности при слиянии веток. У большинства пользователей Unix/Linux установлено именно это значение, потому что у них нет проблем сCRLF
и им не нужно, чтобы Гит делал дополнительную работу каждый раз при записи файлов в базу данных или в рабочую папку.core.autocrlf = true
— значит, что Гит обработает все текстовые файлы и убедится, что всеCRLF
заменены наLF
перед записью в базу данных. При обратном процессе он преобразует всеLF
вCRLF
. Такая установка гарантирует, что ваш репозиторий можно будет использовать на других платформах, сохраняяCRLF
в вашем рабочей папке. Поэтому параметрtrue
дляcore.autocrlf
рекомендован для Windows.core.autocrlf = input
— значит, что Гит обработает все текстовые файлы и убедится, что всеCRLF
изменены наLF
при записи файлов в базу данных. Однако обратной замены не произойдёт. При записи файлов в рабочую папку из базы данных, для обозначения конца строки останутсяLF
. Этот параметр обычно используется в Unix / Linux / OS X для предотвращения записиCRLF
в репозиторий. Идея заключается в том, что если вы вставили код из браузера и случайно записалиCRLF
в один из ваших файлов, Гит удостоверится, что произойдёт замена наLF
при записи в базу данных.
Чтобы увидеть, какое значение для core.autocrlf
установлено в вашей системе, нужно запустить в командной строке git config --global core.autocrlf
. Если команда ничего не вернёт, то вы используете значение по умолчанию, false
.
Как же Гит определяет, что файл текстовый? Хороший вопрос. У Гита есть внутренний эвристический метод, который проверяет, двоичный ли файл. Если файл не двоичный, то Гит считает его текстовым. Но Гит иногда может ошибаться, и это будет причиной для знакомства со следующей настройкой.
Параметр core.safecrlf
был создан на тот случай, если Гит ошибётся и изменит окончания строк там, где лучше было бы оставить их в покое.
core.safecrlf = true
— перед записью в базу данных при подготовке к заменеCRLF
наLF
, Гит убедится, что сможет успешно прервать операцию. Он проверит, что можно откатить изменения (изLF
вCRLF
), а если нет, то отменит операцию.core.safecrlf = warn
— сделает то же, что и предыдущий параметр, но вместо того, чтобы прервать операцию, Гит просто предупредит вас о том, что может случиться что-то нехорошее.
Наконец, вы можете создать в корне своего репозитория файл .gitattributes
и указать в нём настройки для конкретных файлов. Это позволит вам управлять такими настройками, как autocrlf
для каждого типа файлов.
- Например, для того, чтобы Гит заменил
CRLF
наLF
во всех текстовых файлах, можно написать в.gitattributes
такую строку: - Или можно сделать, чтобы Гит никогда не заменял
CRLF
наLF
в текстовых файлах с помощью такой строки: - Чтобы Гит заменял
CRLF
наLF
в текстовых файлах только при записи в базу данных, но возвращалLF
при записи в рабочий каталог, нужно написать:
Хорошо, видите, какой беспорядок мы тут учинили? И он становится ещё больше, если мы начинаем работать над проектами, которые подталкивают нас к другим глобальным настройкам. Введём в дело новую систему, доступную начиная с версии Гит 1.7.2.
Новая система
Новая система определяет все настройки для окончаний строк в файле .gitattributes
вашего репозитория, инкапсулируя их внутри и делая независимыми от глобальных настроек.
В новой системе за то, чтобы указать Гиту, в каких файлах надо заменить CRLF
на LF
, отвечаете вы, сообщая об этом с помощью атрибута text
в файле .gitattributes
. В этом случае будет полезен мануал для .gitattributes
, а ниже вы найдёте несколько примеров использования атрибута text
.
.txt text
— устанавливает атрибутtext
для всех текстовых файлов. Это значит, что Гит будет запускать процесс заменыCRLF
наLF
каждый раз при записи в БД и делать обратную замену при выводе из базы данных в рабочий репозиторий..txt -text
— снимет со всех текстовых файлов этот фильтр. Это значит, что в указанных файлах не будет заменыCRLF
наLF
..txt text=auto
— установит для всех, подходящих под условие файлов, заменуCRLF
наLF
, если Гит с помощью своего эвристического метода определит эти файлы как текстовые, а не бинарные.
Если файл не определён, Гит вернётся к старой системе и настройке core.autocrlf
.
Именно так работает обратная совместимость, но я рекомендую, особенно тем, кто использует Windows для разработки, явно создавать файл gitattributes.
Ниже пример файла .gitattributes
с общими настройками, который можно использовать для своего проекта. Пример взят отсюда.
# Общие настройки, которые всегда должны быть использованы для настроек вашего языка.
# Автоматическое определение текстовых файлов и выполнение нормализации LF
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
* text=auto
#
# Строка выше будет обрабатывать все файлы, которых нет в списке ниже.
#
# Documents
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text
*.tex text
*.adoc text
*.textile text
*.mustache text
*.csv text
*.tab text
*.tsv text
*.sql text
# Graphics
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.tif binary
*.tiff binary
*.ico binary
# SVG по дефолту рассматривается как бинарный. Если вы хотите, чтобы он распознавался как текст, закомментируйте следующую строку и раскомментируйте следующую за ней.
*.svg binary
#*.svg text
*.eps binary
#
# Исключить файлы из экспорта
#
.gitattributes export-ignore
.gitignore export-ignore
Как вы могли заметить, с помощью следующей команды можно сказать Гиту обнаруживать все текстовые файлы и автоматически конвертировать в них CRLF
в LF
:
* text=auto
Это, конечно, лучше, чем требовать от всех одной глобальной настройки для core.autocrlf
, но и означает, что вы полностью доверяете Гиту в определении бинарности файлов. На наш взгляд, лучше явно указать текстовые файлы, которым требуется нормализация. Если вы собираетесь использовать этот параметр, не забудьте, что он должен быть указан на первой строке файла .gitattributes
, чтобы последующие строки могли его переопределить.
«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.
Читать дальше






search: новый HTML-элемент в 2023
Перевод статьи Альваро Монторо о новом теге
- 12 мая 2023

Как сверстать доступный сайт
Что важно учесть, чтобы сайтом смогли пользоваться все.
- 11 мая 2023


В каких браузерах тестировать вёрстку в 2023
Понятная инструкция для тех, кто запутался в хромиумах.
- 11 апреля 2023
