To avoid problems in your diffs, you can configure Git to properly handle line endings.
About line endings
Every time you press return on your keyboard you insert an invisible character called a line ending. Different operating systems handle line endings differently.
When you’re collaborating on projects with Git and GitHub, Git might produce unexpected results if, for example, you’re working on a Windows machine, and your collaborator has made a change in macOS.
You can configure Git to handle line endings automatically so you can collaborate effectively with people who use different operating systems.
Global settings for line endings
The git config core.autocrlf
command is used to change how Git handles line endings. It takes a single argument.
Per-repository settings
Optionally, you can configure a .gitattributes
file to manage how Git reads line endings in a specific repository. When you commit this file to a repository, it overrides the core.autocrlf
setting for all repository contributors. This ensures consistent behavior for all users, regardless of their Git settings and environment.
The .gitattributes
file must be created in the root of the repository and committed like any other file.
A .gitattributes
file looks like a table with two columns:
- On the left is the file name for Git to match.
- On the right is the line ending configuration that Git should use for those files.
Example
Here’s an example .gitattributes
file. You can use it as a template for your repositories:
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
You’ll notice that files are matched—*.c
, *.sln
, *.png
—, separated by a space, then given a setting—text
, text eol=crlf
, binary
. We’ll go over some possible settings below.
-
text=auto
Git will handle the files in whatever way it thinks is best. This is a good default option. -
text eol=crlf
Git will always convert line endings toCRLF
on checkout. You should use this for files that must keepCRLF
endings, even on OSX or Linux. -
text eol=lf
Git will always convert line endings toLF
on checkout. You should use this for files that must keep LF endings, even on Windows. -
binary
Git will understand that the files specified are not text, and it should not try to change them. Thebinary
setting is also an alias for-text -diff
.
Refreshing a repository after changing line endings
After you set the core.autocrlf
option or commit a .gitattributes
file, Git automatically changes line endings to match your new configuration. You may find that Git reports changes to files that you have not modified.
To ensure that all the line endings in your repository match your new configuration, back up your files with Git, then remove and restore all of the files to normalize the line endings.
-
Before adding or committing any changes, verify that Git has applied the configuration correctly. For example, Git automatically determines whether files in a repository are text or binary files. To avoid corruption of binary files in your repository, we recommend that you explicitly mark files as binary in
.gitattributes
. For more information, see gitattributes — Defining attributes per path in the Git documentation. -
To avoid losing any local changes to files in the repository, add and commit any outstanding changes by running the following commands.
Shell git add . -u git commit -m "Saving files before refreshing line endings"
-
To update all files on the current branch to reflect the new configuration, run the following commands.
Shell git rm -rf --cached . git reset --hard HEAD
-
To display the rewritten, normalized files, run the following command.
-
Optionally, to commit any outstanding changes in your repository, run the following command.
Shell git commit -m "Normalize all the line endings"
Further reading
- Customizing Git — Git Attributes in the Pro Git book
- git-config in the man pages for Git
- Getting Started — First-Time Git Setup in the Pro Git book
- Mind the End of Your Line by Tim Clem
До этого момента мы описывали основы того, как Git работает и как его использовать, а так же мы познакомились с некоторыми инструментами Git, которые делают его использование простым и эффективным.
В этой главе мы рассмотрим некоторые настройки Git и систему хуков, что позволяет настроить поведение Git.
Таким образом, вы сможете заставить Git работать именно так как нужно вам или вашей компании.
Конфигурация Git
В главе Введение кратко упоминалось, что вы можете настроить Git, используя команду git config
.
Первое, что вы делали, это установили своё имя и e-mail адрес:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
Сейчас вы познакомитесь с несколькими наиболее интересными опциями, которые можно установить для настройки поведения Git.
Кратко: Git использует набор конфигурационных файлов для изменения стандартного поведения, если это необходимо.
Вначале, Git ищет настройки в файле /etc/gitconfig
, который содержит настройки для всех пользователей в системе и всех репозиториев.
Если передать опцию --system
команде git config
, то операции чтения и записи будут производиться именно с этим файлом.
Следующее место, куда смотрит Git — это файл ~/.gitconfig
(или ~/.config/git/config
), который хранит настройки конкретного пользователя.
Вы можете указать Git читать и писать в него, используя опцию --global
.
Наконец, Git ищет параметры конфигурации в файле настроек в каталоге Git (.git/config
) текущего репозитория.
Эти значения относятся только к текущему репозиторию и доступны при передаче параметра --local
команде git config
.
(Если уровень настроек не указан явно, то подразумевается локальный.)
Каждый из этих уровней (системный, глобальный, локальный) переопределяет значения предыдущего уровня, например, значения из .git/config
важнее значений из /etc/gitconfig
.
Примечание |
Конфигурация Git это обычные текстовые файлы, поэтому можно вручную установить необходимые значения используя соответствующий синтаксис. |
Базовая конфигурация клиента
Конфигурационные параметры Git разделяются на две категории: настройки клиента и настройки сервера.
Большая часть — клиентские, для настройки ваших личных предпочтений в работе.
Существует много, очень много настроек, но подавляющее большинство из них применимо только в конкретных случаях; мы рассмотрим только самые основные и самые полезные из них.
Для просмотра полного списка настроек, поддерживаемых вашей версией Git, выполните команду:
Эта команда выведет список доступных настроек с довольно подробным описанием.
Так же, соответствующую документацию можно найти здесь https://git-scm.com/docs/git-config.html.
core.editor
По умолчанию, Git использует ваш редактор по умолчанию ($VISUAL
или $EDITOR
), если значение не задано — переходит к использованию редактора vi
при создании и редактировании сообщений коммитов или тегов.
Чтобы изменить редактор по умолчанию, воспользуйтесь настройкой core.editor
:
$ git config --global core.editor emacs
Теперь, вне зависимости от того, какой редактор является основным для вашего окружения, Git будет вызывать Emacs
для редактирования сообщений.
commit.template
Если указать путь к существующему файлу, то он будет использован как сообщение по умолчанию при создании коммита.
Смысл создания шаблона сообщения коммита в том, чтобы лишний раз напомнить себе (или другим) о требованиях к формату или стилю оформления сообщения коммита.
Например, предположим что вы создали файл ~/.gitmessage.txt
, который выглядит так:
Subject line (try to keep under 50 characters)
Multi-line description of commit,
feel free to be detailed.
[Ticket: X]
Обратите внимание, что шаблон напоминает коммитеру о том, чтобы строка заголовка сообщения была короткой (для поддержки однострочного вывода команды git log --oneline
), что дополнительную информацию в сообщении следует располагать ниже, а так же о том, что было бы неплохо при наличии добавить ссылку на номер задачи или сообщения в системе отслеживания ошибок.
Чтобы заставить Git отображать содержимое этого файла в редакторе каждый раз при выполнении команды git commit
, следует установить значение параметра commit.template
:
$ git config --global commit.template ~/.gitmessage.txt
$ git commit
Теперь, при создании коммита, в вашем редакторе будет отображаться сообщение изменённого вида:
Subject line (try to keep under 50 characters)
Multi-line description of commit,
feel free to be detailed.
[Ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C
Если ваша команда придерживается требований к сообщениям коммитов, то создание шаблона такого сообщения и настройка Git на его использование увеличит вероятность соответствия заданным требованиям.
Данная настройка определяет какая программа будет использована для разбиения текста на страницы при выводе такой информации как log
и diff
.
Вы можете указать more
или любую другую (по умолчанию используется less
), а так же выключить совсем, установив пустое значение:
$ git config --global core.pager ''
В таком случае, Git будет выводить весь текст полностью, вне зависимости от его длины.
user.signingkey
Если вы создаёте подписанные аннотированные теги (как описано в разделе Подпись главы 7), то установка GPG ключа в настройках облегчит вам задачу.
Установить ключ можно следующим образом:
$ git config --global user.signingkey <gpg-key-id>
Теперь, вам не нужно указывать ключ для подписи каждый раз при вызове команды git tag
:
core.excludesfile
В разделе Игнорирование файлов главы 2 сказано, что вы можете указывать шаблоны исключений в файле .gitignore
вашего проекта, чтобы Git не отслеживал их и не добавлял в индекс при выполнении команды git add
.
Однако, иногда вам нужно игнорировать определённые файлы во всех ваших репозиториях.
Если на вашем компьютере работает Mac OS X, вероятно вы знакомы с файлами .DS_Store
.
Если вы используете Emacs или Vim, то вы знаете про файлы, имена которых заканчиваются на ~
или .swp
.
Данная настройка позволяет вам определить что-то вроде глобального файла .gitignore
.
Если вы создадите файл ~/.gitignore_global
с содержанием:
… и выполните команду git config --global core.excludesfile ~/.gitignore_global
, то Git больше не потревожит вас на счёт этих файлов.
help.autocorrect
Если вы ошибётесь в написании команды, Git покажет вам что-то вроде этого:
$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.
The most similar command is
checkout
Git старается угадать, что вы имели ввиду, но при этом команду не выполняет.
Если вы установите help.autocorrect
в значение 1, то Git будет выполнять эту команду:
$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...
Обратите внимание, что команда выполнилась через «0.1» секунды.
help.autocorrect
— это число, указываемое в десятых долях секунды.
Поэтому, если вы установите значение 50, то Git даст вам 5 секунд изменить своё решение перед тем, как выполнить скорректированную команду.
Цвета в Git
Git полностью поддерживает цветовой вывод в терминале, что позволяет быстро и легко визуально анализировать вывод команд.
Существует несколько опций для настройки цветов.
color.ui
Git автоматически подсвечивает большую часть своего вывода, но это можно отключить, если вам не нравится такое поведение.
Для отключения цветового вывода в терминал, выполните следующую команду:
$ git config --global color.ui false
Значение по умолчанию — auto
, при котором цвета используются при непосредственном выводе в терминал, но исключаются при перенаправлении вывода в именованный канал или файл.
Вы так же можете установить значение always
, что делает вывод одинаковым как в терминал, так и в именованный канал.
Скорее всего, вам это не понадобится; в большинстве случаев, при желании использовать цвета в перенаправленном выводе, указывается флаг --color
команде Git для принудительного использования цветовых кодов.
Практически всегда стандартное значение подходит лучше всего.
color.*
Если вы хотите явно указать вывод каких команд должен быть подсвечен и как, Git предоставляет соответствующие настройки.
Каждая из них может быть установлена в значения true
, false
или always
:
color.branch color.diff color.interactive color.status
Каждая из них имеет вложенную конфигурацию, которую можно использовать для настройки отдельных частей вывода при желании переопределить их цвет.
Например, чтобы установить для метаинформации вывода команды diff синий цвет, чёрный фон и полужирный шрифт, выполните команду:
$ git config --global color.diff.meta "blue black bold"
Для установки цвета доступны следующие значения: normal
, black
, red
, green
, yellow
, blue
, magenta
, cyan
, или white
.
Для указания атрибутов текста, как bold
в предыдущем примере, доступны значения: bold
, dim
, ul
(подчёркнутый), blink
и reverse
(поменять местами цвет фона и цвет текста).
Внешние программы слияния и сравнения
Хоть в Git и есть встроенная программа сравнения, которая описывается в этой книге, вы можете установить вместо неё другую.
Вы также можете настроить графический инструмент разрешения конфликтов слияния вместо того, чтобы разрешать конфликты вручную.
Мы покажем как настроить Perforce Visual Merge Tool (P4Merge) для разрешения конфликтов слияния, так как это прекрасный и бесплатный инструмент.
Если у вас есть желание попробовать P4Merge, то она работает на всех основных платформах, так что у вас должно получиться.
В примерах мы будем использовать пути к файлам, которые работают в системах Linux и Mac; для Windows вам следует изменить /usr/local/bin
на путь к исполняемому файлу у вас в системе.
Для начала скачайте P4Merge.
Затем, создайте скрипты обёртки для вызова внешних программ.
Мы будем использовать путь к исполняемому файлу в системе Mac; в других системах — это путь к файлу p4merge
.
Создайте скрипт с названием extMerge
для вызова программы слияния и передачи ей заданных параметров:
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*
Скрипт вызова программы сравнения проверяет наличие 7 аргументов и передаёт 2 из них в скрипт вызова программы слияния.
По умолчанию, Git передаёт следующие аргументы программе сравнения:
path old-file old-hex old-mode new-file new-hex new-mode
Так как вам нужны только old-file
и new-file
, следует использовать скрипт, который передаст только необходимые параметры.
$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
Так же следует убедиться, что созданные скрипты могут исполняться:
$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff
Теперь можно изменить файл конфигурации для использования ваших инструментов слияния и сравнения.
Для этого необходимо изменить ряд настроек: merge.tool
— чтобы сказать Git какую стратегию использовать, mergetool.<tool>.cmd
— чтобы сказать Git как запускать команду, mergetool.<tool>.trustExitCode
— чтобы сказать Git как интерпретировать код выхода из программы, diff.external
— чтобы сказать Git какую команду использовать для сравнения.
Таким образом, команду конфигурации нужно запустить четыре раза:
$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff
или вручную отредактировать файл ~/.gitconfig
добавив соответствующие строки:
[merge]
tool = extMerge
[mergetool "extMerge"]
cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
trustExitCode = false
[diff]
external = extDiff
После этого, вы можете запускать команды diff следующим образом:
$ git diff 32d1776b1^ 32d1776b1
Вместо отображения вывода diff в терминале Git запустит P4Merge, выглядеть это будет примерно так:
Рисунок 142. P4Merge
Если при слиянии двух веток у вас возникнут конфликты, выполните команду git mergetool
; она запустит P4Merge чтобы вы могли разрешить конфликты используя графический интерфейс.
Используя скрипт обёртку для вызова внешних программ, вы можете легко изменить вызываемую программу.
Например, чтобы начать использовать KDiff3 вместо P4Merge, достаточно изменить файл extMerge
:
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
Теперь, Git будет использовать программу KDiff3 для сравнения файлов и разрешения конфликтов слияния.
Git изначально настроен на использование ряда других инструментов для разрешения конфликтов слияния, поэтому вам не нужно дополнительно что-то настраивать.
Для просмотра списка поддерживаемых инструментов, выполните команду:
$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
emerge
gvimdiff
gvimdiff2
opendiff
p4merge
vimdiff
vimdiff2
The following tools are valid, but not currently available:
araxis
bc3
codecompare
deltawalker
diffmerge
diffuse
ecmerge
kdiff3
meld
tkdiff
tortoisemerge
xxdiff
Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.
Если вы хотите использовать KDiff3 только для разрешения конфликтов слияния, но не для сравнения, выполните команду:
$ git config --global merge.tool kdiff3
Если выполнить эту команду вместо настройки использования файлов extMerge
и extDiff
, то Git будет использовать KDiff3 для разрешения конфликтов слияния, а для сравнения — стандартную программу diff.
Форматирование и пробелы
Проблемы форматирования и пробелов являются одними из самых неприятных и незаметных проблем, с которыми сталкивают разработчики при совместной работе, особенно используя разные платформы.
Это легко может произойти с патчами или с любой другой совместной работой, так как редакторы молча исправляют несоответствия, и если ваши файлы когда либо касаются систем Windows, то переносы строк могут быть заменены.
В Git есть несколько настроек, чтобы справиться с этими проблемами.
core.autocrlf
Если вы программируете в Windows и работаете с людьми, которые не используют её (или наоборот), рано или поздно, вы столкнётесь с проблемами переноса строк.
Это происходит потому, что Windows при создании файлов использует для обозначения переноса строки два символа «возврат каретки» и «перевод строки», в то время как Mac и Linux используют только один — «перевод строки».
Это незначительный, но невероятно раздражающий факт кроссплатформенной работы; большинство редакторов в Windows молча заменяют переносы строк вида LF на CRLF или вставляют оба символа, когда пользователь нажимает клавишу ввод.
Git может автоматически конвертировать переносы строк CRLF в LF при добавлении файла в индекс и наоборот — при извлечении кода.
Такое поведение можно включить используя настройку core.autocrlf
.
Если у вас Windows, то установите значение true
— при извлечении кода LF окончания строк будут преобразовываться в CRLF:
$ git config --global core.autocrlf true
Если у вас система Linux или Mac, то вам не нужно автоматически конвертировать переносы строк при извлечении файлов; однако, если файл с CRLF окончаниями строк случайно попал в репозиторий, то Git может его исправить.
Можно указать Git конвертировать CRLF в LF во время коммита, но не наоборот, установив настройке core.autocrlf
значение input
:
$ git config --global core.autocrlf input
Такая конфигурация позволит вам использовать CRLF переносы строк в Windows, при этом в репозитории и системах Mac и Linux будет использован LF.
Если вы используете Windows и программируете только для Windows, то вы можете отключить описанный функционал задав значение false
, сохраняя при этом CR символы в репозитории:
$ git config --global core.autocrlf false
core.whitespace
Git поставляется настроенным на обнаружение и исправление некоторых проблем с пробелами.
Он в состоянии найти шесть основных проблем, обнаружение трёх из них включено по умолчанию, а трёх других — выключено.
Те, что включены по умолчанию — это blank-at-eol
, что ищет пробелы в конце строки; blank-at-eof
, что ищет пробелы в конце файла; и space-before-tab
, что ищет пробелы перед символом табуляции в начале строки.
Те, что выключены по умолчанию — это indent-with-non-tab
, что ищет строки с пробелами вначале вместо символа табуляции (и контролируется настройкой tabwidth
); tab-in-indent
, что ищет символы табуляции в отступах в начале строки; и cr-at-eol
, которая указывает Git на валидность наличия CR в конце строки.
Указав через запятую значения для настройки core.whitespace
, можно сказать Git какие из этих опций должны быть включены.
Чтобы отключить ненужные проверки, достаточно удалить их из строки значений или поставить знак -
перед каждой из них.
Например, чтобы включить все проверки, кроме space-before-tab
, выполните команду (при этом trailing-space
является сокращением и охватывает как blank-at-eol
, так и blank-at-eof
):
$ git config --global core.whitespace \
trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol
Или можно указать только часть проверок:
$ git config --global core.whitespace \
-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol
Git будет искать указанные проблемы при выполнении команды git diff
и пытаться подсветить их, чтобы вы могли исправить их перед коммитом.
Так же эти значения будут использоваться во время применения патчей командой git apply
.
При применении патчей, можно явно указать Git информировать вас в случае нахождения проблем с пробелами:
$ git apply --whitespace=warn <patch>
Так же можно указать Git автоматически исправлять эти проблемы перед применением патча:
$ git apply --whitespace=fix <patch>
Эти настройки так же применяются при выполнении команды git rebase
.
Если проблемные пробелы попали в коммит, но ещё не отправлены в удалённую ветку, можно выполнить git rebase --whitespace=fix
для автоматического исправления этих проблем.
Конфигурация сервера
Для серверной части Git не так много настроек, но есть несколько интересных, на которые стоит обратить внимание.
receive.fsckObjects
Git способен убедиться, что каждый объект, отправленный командой push
, валиден и соответствует своему SHA-1-хешу.
По умолчанию эта функция отключена; это очень дорогая операция и может привести к существенному замедлению, особенно для больших объёмов отправляемых данных или для больших репозиториев.
Вы можете включить проверку целостности объектов для каждой операции отправки, установив значение receive.fsckObjects
в true
:
$ git config --system receive.fsckObjects true
Теперь, Git будет проверять целостность репозитория до принятия новых данных для уверенности, что неисправные или злонамеренные клиенты не смогут отправить повреждённые данные.
receive.denyNonFastForwards
Если вы перебазируете коммиты, которые уже отправлены, и попытаетесь отправить их снова или попытаетесь отправить коммит в удалённую ветку, в которой не содержится коммит, на который она указывает, то данные приняты не будут.
В принципе, это правильная политика; но в случае перебазирования — вы знаете, что делаете и можете принудительно обновить удалённую ветку используя флаг -f
для команды push
.
Для запрета перезаписи истории установите receive.denyNonFastForwards
:
$ git config --system receive.denyNonFastForwards true
Сделать то же самое можно другим способом — используя хук на стороне сервера, мы рассмотрим его немного позже.
Этот подход позволяет более гибко настроить ограничения, например, запретить перезапись истории определённой группе пользователей.
receive.denyDeletes
Политику denyNonFastForwards
можно обойти, удалив ветку и создав новую с таким же именем.
Для предотвращения этого, установите receive.denyDeletes
в значение true
:
$ git config --system receive.denyDeletes true
Эта команда запретит удаление веток и тегов всем пользователям.
Чтобы удалить ветку, придётся удалить все соответствующие ей файлы на сервере вручную.
Куда более интересный способ — это настроить права пользователей, с ним вы познакомитесь в разделе Пример принудительной политики Git.
I want to force Git to check out files under Windows using just LF
not CR+LF
.
I checked the two configuration options, but was not able to find the right combination of settings.
I want to convert all files to have LF
line breaks and keep the LF
in the files.
Remark: I used autocrlf = input
but this just repairs the files when you commit them.
I want to force it to get them using LF
.
Probably I wasn’t so clear:
the repository is already using LF
but the files checked out using
Git for Windows are using CR+LF
and I want to force Git to get them with LF
:
forcing Unix line endings.
$ git config --list | grep crlf
core.autocrlf=input
Henke
4,6013 gold badges31 silver badges45 bronze badges
asked Mar 25, 2010 at 16:07
10
The proper way to get LF endings in Windows is to first set core.autocrlf
to false
:
git config --global core.autocrlf false
You need to do this if you are using msysgit, because it sets it to true
in its system settings.
Now git won’t do any line ending normalization. If you want files you check in to be normalized, do this: Set text=auto
in your .gitattributes
for all files:
* text=auto
And set core.eol
to lf
:
git config --global core.eol lf
Now you can also switch single repos to crlf (in the working directory!) by running
git config core.eol crlf
After you have done the configuration, you might want git to normalize all the files in the repo. To do this, go to to the root of your repo and run these commands:
git rm --cached -rf .
git diff --cached --name-only -z | xargs -n 50 -0 git add -f
If you now want git to also normalize the files in your working directory, run these commands:
git ls-files -z | xargs -0 rm
git checkout .
answered Oct 31, 2012 at 8:38
ChronialChronial
67k14 gold badges93 silver badges99 bronze badges
12
I come back to this question fairly often, though none of its other answers are quite right for me.
That said, the right answer for me is a mixture of the others.
What I find works is the following:
git config --global core.eol lf
git config --global core.autocrlf input
For repos (Git repositories) that were checked out after those global settings were set, everything will be checked out as whatever it is in the repo – hopefully LF
(\n
).
Any CRLF
will be converted to just LF
on check-in (commit).
With an existing repo that you have already checked out – that has the correct line endings in the repo but not your working copy – you can run the following commands to fix it:
git rm -rf --cached .
git reset --hard HEAD
This will delete (rm
) recursively (-r
) without prompt (-f
), all files except those that you have edited (--cached
), from the current directory (.
). The reset
then returns all those files to a state where they have their true line endings (matching what’s in the repo).
If you need to fix the line endings of files in a repo, I recommend grabbing an editor that will let you do that in bulk like IntelliJ or Sublime Text, but I’m sure any good one will likely support this.
Henke
4,6013 gold badges31 silver badges45 bronze badges
answered Oct 29, 2015 at 21:24
Ben LiyanageBen Liyanage
5,0131 gold badge21 silver badges24 bronze badges
8
The OP added in his question:
the files checked out using msysgit are using
CR+LF
and I want to force msysgit to get them withLF
A first simple step would still be in a .gitattributes
file:
# 2010
*.txt -crlf
# 2020
*.txt text eol=lf
(as noted in the comments by grandchild, referring to .gitattributes
End-of-line conversion), to avoid any CRLF
conversion for files with correct eol
.
And I have always recommended git config --global core.autocrlf false
to disable any conversion (which would apply to all versioned files)
See Best practices for cross platform git config?
Since Git 2.16 (Q1 2018), you can use git add --renormalize .
to apply those .gitattributes
settings immediately.
But a second more powerful step involves a gitattribute filter driver and add a smudge step
Whenever you would update your working tree, a script could, only for the files you have specified in the .gitattributes
, force the LF eol
and any other formatting option you want to enforce.
If the «clear
» script doesn’t do anything, you will have (after commit) transformed your files, applying exactly the format you need them to follow.
answered Mar 25, 2010 at 16:37
VonCVonC
1.3m530 gold badges4436 silver badges5275 bronze badges
6
Context
If you
- want to force all users to have LF line endings for text files and
- you cannot ensure that all users change their git config,
you can do that starting with git 2.10. 2.10 or later is required, because 2.10 fixed the behavior of text=auto together with eol=lf. Source.
Solution
Put a .gitattributes
file in the root of your git repository having following contents:
* text=auto eol=lf
Commit it.
Optional tweaks
You can also add an .editorconfig
in the root of your repository to ensure that modern tooling creates new files with the desired line endings.
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
answered Feb 9, 2017 at 11:52
kopporkoppor
19.2k15 gold badges119 silver badges162 bronze badges
5
core.autocrlf=input
is the right setting for what you want, but you might have to do a git update-index --refresh
and/or a git reset --hard
for the change to take effect.
With core.autocrlf
set to input
, git will not apply newline-conversion on check-out (so if you have LF in the repo, you’ll get LF), but it will make sure that in case you mess up and introduce some CRLFs in the working copy somehow, they won’t make their way into the repo.
albertjan
7,5496 gold badges44 silver badges75 bronze badges
answered Apr 1, 2010 at 0:23
kusmakusma
6,5562 gold badges22 silver badges26 bronze badges
1
You can find the solution to this problem at:
https://help.github.com/en/github/using-git/configuring-git-to-handle-line-endings
Simplified description of how you can solve this problem on windows:
Global settings for line endings
The git config core.autocrlf command is used to change how Git handles line endings. It takes a single argument.
On Windows, you simply pass true to the configuration. For example:
C:>git config —global core.autocrlf true
Good luck, I hope I helped.
answered Mar 26, 2020 at 20:54
1
Время на прочтение
9 мин
Количество просмотров 10K
Я работаю в операционной системе «Windows 10». У меня на компьютере установлена программа «Git for Windows» версии 2.35.1. В принципе, «Git for Windows» — это та же знаменитая программа (набор программ) «Git» (система управления версиями), только скомпилированная из исходного кода в исполняемый файл, который может запускаться в операционных системах «Windows» (изначально исходный код «Git» был написан для компиляции в исполняемый файл, запускаемый в операционной системе «Linux»).
Дистрибутив «Git for Windows» кроме программы «Git» содержит разные полезные для работы с «Git» программы, вроде программы-оболочки «Git Bash» с интерфейсом командной строки и программы «Git GUI» с графическим оконным интерфейсом. В документации сказано, что «Git for Windows» является подмножеством платформы (набора инструментов и библиотек) «MSYS2». Как я понимаю, для компиляции используется компилятор из набора инструментов «MinGW-w64».
Окончания строк в разных операционных системах
Как известно (возможно, не всем), в операционных системах «Windows» окончание строки обычно представляется двумя символами, в таблице Юникода они обозначены кодами U+000D (возврат каретки, по-английски «Carriage Return», сокращенно «CR») и U+000A (подача бумаги на следующую строку, по-английски «Line Feed», сокращенно «LF»). В мир компьютеров эти управляющие коды пришли из мира печатных (пишущих) машинок.
В Unix-подобных операционных системах окончание строки обычно представляется одним символом «LF». (Говорят, в операционных системах от компании «Apple» до появления операционной системы «Mac OS X», которая вышла в 2001 году, окончание строки представлялось одним символом «CR». Сейчас в операционных системах «macOS» окончание строки представляется одним символом «LF», как и в других Unix-подобных операционных системах.)
Из-за того, что большинство текстовых редакторов (даже заточенных под написание текстов программ) плохо умеет работать с окончаниями строк разного вида, вышеописанная разница приносит проблемы, если над одним и тем же проектом работают программисты из разных операционных систем.
Я подготовил для экспериментов текстовый файл, содержащий несколько строк с окончаниями разного вида. Для работы с кодом я обычно использую программы «VS Code» и «Notepad++». Обе эти программы могут правильно отображать строки с окончаниями разного вида. Однако, программа «VS Code» не отображает отдельные символы, входящие в окончания строк, поэтому в ней не получается понять, где и какое окончание строки использовано. Для просмотра и определения видов окончаний строк я обычно использую программу «Notepad++», она умеет отображать отдельные символы, входящие в окончания строк. Вот как у меня на компьютере выглядит в программе «Notepad++» тестовый файл «myfile.txt» (включено отображение всех символов, то есть и тех, которые обычно не отображаются в текстовых редакторах):
На иллюстрации выше видно, что две строки имеют окончания в виде пары символов CR и LF (эту пару символов часто обозначают как «CRLF»), а другие две строки — в виде LF. В программе «Notepad++» у меня не получилось создать разные виды окончаний строк в одном и том же файле (хотя можно скопировать и вставить существующие с помощью инструмента специальной вставки), поэтому я сначала ввел текст файла в программе «Notepad++» с одинаковыми окончаниями строк, а потом подправил два из этих окончаний строк в шестнадцатеричном (двоичном) редакторе. Кодировка файла «myfile.txt» — UTF-8 (как видно на иллюстрации, размер файла — 222 байта, русские буквы занимают по два байта).
Также на иллюстрации выше видно, что в строке состояния программы «Notepad++» режим работы с окончаниями строк показан как «Windows (CR LF)». Этот режим не влияет на отображение символов только что открытого файла. Он лишь говорит о том, что при вставке нового окончания строки (нажатием клавиши «Enter») будет вставлено окончание строки вида CRLF. Этот режим можно переключить на «Unix (LF)» или на «Macintosh (CR)», после чего можно будет клавишей «Enter» вставлять окончания строк вида LF или CR. Однако, переключение этого режима не дает возможности работать в одном файле одновременно с несколькими видами окончаний строк, так как при переключении этого режима меняются сразу все окончания строк в файле на выбранный в режиме вид окончаний строк.
Тестовый файл «myfile.txt» я разместил в папке C:\Users\Илья\source\repos\test\
. Пока он в этой папке один. Будем считать эту папку папкой нашего проекта.
Создание Git-репозитория и параметр «core.autocrlf»
С программой «Git» можно работать множеством способов, но я предпочитаю самый универсальный — из командной строки. Для этого я обычно использую программу-оболочку «PowerShell» версии 7, а запускаю ее в программе-«эмуляторе терминала» «Windows Terminal». Итак, проверим, что программа «Git» установлена на компьютере и доступна в папке нашего проекта:
PS C:\Users\Илья\source\repos\test> git --version
git version 2.35.1.windows.2
Создадим Git-репозиторий для нашего проекта:
PS C:\Users\Илья\source\repos\test> git init
Initialized empty Git repository in C:/Users/Илья/source/repos/test/.git/
«Репозиторием» обычно называют папку (хранилище, базу данных), в которой хранится исходный код программы (папку проекта). А «Git-репозиторием» называют базу данных, в которой хранятся разные версии файлов нашего проекта, информация о них и об изменениях, вносимых в эти файлы. Сама программа (система программ) «Git» у меня установлена в папке C:\Program Files\Git\
. Чтобы обеспечить управление версиями файлов нашего проекта, в папке нашего проекта с помощью вышеприведенной команды была создана скрытая папка «.git» (у меня в программе «Проводник Windows» включено отображение скрытых папок, поэтому ее там видно), в которой хранятся база данных с версиями файлов нашего проекта и разные служебные файлы.
Сразу после создания папки «.git» в ней уже есть файлы базы данных и разные служебные файлы. Но пока что эта база данных пуста (пока еще не содержит версий файлов нашего проекта). Чтобы файлы нашего проекта попали под отслеживание в них изменений от программы «Git», они должны быть добавлены в базу данных в папке «.git» посредством коммитов («коммит» — это операция регистрации изменений в файлах проекта).
Настройка работы программы «Git» может быть произведена на трех разных уровнях: на уровне операционной системы (для всех ее пользователей), на уровне отдельного пользователя (global) и на уровне проекта (local). При установке программы «Git» программа-установщик обычно задает умолчательные настройки на уровне текущего пользователя операционной системы. В рамках данного поста мы затронем только настройки на уровне текущего проекта, они хранятся в файле \.git\config
(этот файл не имеет расширения) текущего проекта. Этот файл был создан в результате вышеприведенной команды «git init», он — текстовый, но нет нужды редактировать его вручную, для этого есть отдельная команда «git config».
Если какой-либо параметр не определен в вышеупомянутом файле настроек текущего проекта, то значение этого параметра будет автоматически взято из файла настроек текущего пользователя операционной системы. Для чистоты эксперимента мы будем прямо прописывать нужное значение нужного параметра в файле настроек текущего проекта с помощью следующей команды:
PS C:\Users\Илья\source\repos\test> git config --local core.autocrlf true
Как работает параметр «core.autocrlf» мы проверим экспериментально, после чего станет понятно, для чего этот параметр можно использовать.
1. Параметр «core.autocrlf», значение «true»
Итак, с помощью команды, приведенной выше, мы установили для параметра «core.autocrlf» значение «true». Совершим первый коммит, в который включим текущую версию нашего тестового файла «myfile.txt»:
PS C:\Users\Илья\source\repos\test> git add "myfile.txt"
warning: LF will be replaced by CRLF in myfile.txt.
The file will have its original line endings in your working directory
PS C:\Users\Илья\source\repos\test> git commit -m "Первый коммит"
[master (root-commit) 4d71045] Первый коммит
1 file changed, 4 insertions(+)
create mode 100644 myfile.txt
В блоке кода выше приведены сразу две команды подряд. Команда «git add» формирует список содержимого будущего коммита. Когда содержимое коммита сформировано, делаем сам коммит (регистрацию изменений в коде программы в базе данных в папке «.git» нашего проекта) с помощью команды «git commit».
Два сообщения, выданные после первой команды в блоке кода выше, могут запутать неопытного пользователя. Первое сообщает о том, что окончания строк вида LF будут заменены окончаниями строк вида CRLF в нашем тестовом файле «myfile.txt». Второе сообщает, что версия файла «myfile.txt», находящаяся в папке проекта, сохранит окончания строк в оригинальном виде. На первый взгляд, эти сообщения противоречат друг другу. Путаница возникает из-за того, что в обоих сообщениях употреблено будущее время, но не уточняется, что события, о которых идет речь, хоть и произойдут в будущем, но произойдут НЕ одновременно.
На самом деле, во втором сообщении имеется в виду, что оригинальные окончания строк в файле «myfile.txt» останутся нетронутыми работой запущенной команды «git add». А первое сообщение предупреждает о том, что в будущем, после извлечения версии файла «myfile.txt» из базы данных в папку проекта, окончания строк вида LF будут затерты окончаниями строк CRLF из-за текущего значения настройки «core.autocrlf».
Проверим это на практике. После окончания работы двух команд, показанных в блоке кода выше, я заглянул в файл «myfile.txt», находящийся в папке проекта (в терминах программы «Git» ее называют «рабочей папкой» [working directory], так как именно тут мы работаем с файлами проекта, вносим в них изменения), и убедился, что окончания строк в нем остались без изменений (две строки с окончаниями вида CRLF, две строки с окончаниями вида LF). То есть обещание «The file will have its original line endings in your working directory» сбылось.
После этого я удалил файл «myfile.txt» из папки проекта в корзину операционной системы. Представим, что я потерял рабочие файлы своего проекта. Восстановим их (конкретно в нашем проекте один файл, но в общем случае их может быть много) в папку проекта из базы данных, созданной ранее средствами программы «Git» для нашего проекта:
PS C:\Users\Илья\source\repos\test> git checkout -f master
Already on 'master'
В результате этой команды в папке проекта снова появился файл «myfile.txt». Однако, все четыре окончания строк в этом файле теперь стали одного вида: CRLF. Сбылось обещание из предупреждения «warning: LF will be replaced by CRLF in myfile.txt.».
Как работает настройка «core.autocrlf» со значением «true»? Если при такой настройке мы помещаем версию измененного файла в базу данных «Git» данного проекта, то все найденные в этом файле окончания строк вида CRLF конвертируются в окончания строк вида LF. Если при такой настройке мы извлекаем версию файла, хранящуюся в базе данных «Git» данного проекта, то все найденные в этой версии файла окончания строк вида LF конвертируются в окончания строк вида CRLF. Вот как это можно показать схематично:
add, commit База checkout
--------------> данных Git -------------->
(CRLF -> LF) (LF) (LF -> CRLF)
Подчеркну, что на этой схеме внесение в базу данных (коммит) и извлечение из нее (checkout) разнесены во времени. Если внесение в базу данных произошло при настройке «core.autocrlf» со значением «true», а извлечение из базы данных произошло при настройке «core.autocrlf» со значением «false», то конвертация при извлечении не произойдет и все четыре окончания строк в извлеченном файле окажутся вида LF (в том виде, в котором этот файл был помещен в базу данных и хранится там). Это замечание может быть сходным образом применено и к другим значениям настройки «core.autocrlf».
2. Параметр «core.autocrlf», значение «false»
Схема работы при такой настройке:
add, commit База checkout
-------------------> данных Git ------------------->
(без конвертации) (CRLF и/или LF) (без конвертации)
При такой настройке в базе данных «Git» будет храниться именно то, что мы туда положили. И будет извлечено именно то, что хранится в базе данных, без изменений.
3. Параметр «core.autocrlf», значение «input»
Схема работы при такой настройке:
add, commit База checkout
--------------> данных Git ------------------->
(CRLF -> LF) (LF) (без конвертации)
Зачем нужны эти три настройки
Параметр «core.autocrlf» со значением «false» — это естественный режим работы программы «Git», который использовался бы, если б не было разницы в представлении окончаний строк в разных операционных системах.
Собственно, параметр «core.autocrlf» придумали для обеспечения работы над одним проектом программистов из разных операционных систем. Предполагается, что программист в операционной системе «Windows» будет работать с файлами, в которых окончания строк только вида CRLF. При этом предполагается, что он включит для проекта настройку «core.autocrlf» со значением «true». Тогда он будет работать в своей папке проекта с файлами, в которых окончания строк будут вида CRLF, при этом в базе данных «Git» эти же файлы будут сохранены с окончаниями вида LF. Программист в операционной системе «Windows» этого даже не заметит, ведь конвертация происходит автоматически, как было показано выше в пункте 1.
В тот же момент программист в Unix-подобной операционной системе будет работать с той же базой данных «Git», но у него для проекта будет включена настройка «core.autocrlf» со значением «input» (или со значением «false»). Он будет получать из базы данных файлы с окончаниями строк вида LF, как и принято в Unix-подобных операционных системах.
В принципе, программист в операционной системе «Windows» тоже может использовать параметр «core.autocrlf» со значением «false» в случае, если он работает со своей базой данных «Git» один и пишет код только для операционных систем Windows. Либо он работает вместе с другими программистами, но все участники проекта работают в операционных системах «Windows» и проект предназначен только для операционных систем «Windows». Либо, еще один вариант, в коде есть файлы с окончаниями строк разного вида (CRLF и/или LF) и программист хочет сам отслеживать виды окончаний строк в своих файлах, без вмешательства программ, без автоматической конвертации.
Полезные ссылки
-
В книге «Pro Git» (вторая редакция, вышла в 2014 году), авторы: Scott Chacon (Скотт Чакон) и Ben Straub (Бен Страуб), в главе 8 «Настройка Git», в подглаве 8.1 «Конфигурация Git» (статья большая, ищите в ее последней трети раздел «Форматирование и пробелы»).
-
Хороший, развернутый ответ на вопрос «Git replacing LF with CRLF» на известном сайте «Stack Overflow».
Git and normalization of line-endings
A few months ago, I spent hours trying to decide about the best way to deal with line endings and how to switch a repo to using .gitattributes. I just found those comprehensive notes, and thought they’d be easier to find here than buried in my notes…
TL;DR
- line-ending normalization is about converting
LF
<=>CR+LF
, for cross-platform compatibility -
.gitattributes
file is the safestgit
mechanism to manage line-endings normalization - updating normalization settings is tricky because
git
may report changes on unmodified files, and it is totally not obvious what is happening - there are some tricks to help understand what is happening and to fix things
Line endings and Operating systems
When you press <Enter>
in your text editor, the file is modified with invisible characters that represent the new line. This invisible thing is most commonly represented in two ways:
- ASCII character LF (aka Line Feed)
- ASCII character CR+LF (aka Carriage Return + Line Feed)
Historically, most systems used to require CR+LF, and Unix systems decided in the 1980s to remove the CR character to simplify things and save disk space.
In practice, Windows is the only modern operating systems that still uses CRLF line endings.
When developing in a team, you will end up with people working on Windows and other operating systems, and you will need to manage this difference in your source control system.
Git’s core.autocrlf
This settings is defined via git config. It applies globally or per repo. When enabled, it applies normalization on all files detected by git as text
-
Checkout Windows-style, commit Unix-style (
core.autocrlf=true
)- Git will convert LF to CRLF when checking out text files.
- When committing text files, CRLF will be converted to LF.
- This is the default value pushed by the installer on Windows systems
-
Checkout as-is, commit Unix-style (
core.autocrlf=input
)- Git will not perform any conversion when checking out text files.
- When committing text files, CRLF will be converted to LF.
- some people recommend using this when developing on Unix systems
-
Checkout as-is, commit as-is (
core.autocrlf=false
)- Git will not perform any conversions when checking out or committing text files.
- This is default value if the setting is not defined.
Some people consider it is not git’s responsibility to do line-ending normalization. It could be tempting to go «checkout as-is commit as-is» in order to disable git’s normalization. But it cannot be commited to a repo, so it is dependent on developer workstation settings ====> fragile
Regardless of what is defined in people’s local core.autocrlf
setting, individual repository maintainers can override the behavior via the .gitattributes
file, which is the most robust way to go.
.gitattributes
.gitattributes
assigns attributes to file types. The text
and eol
attributes are used to control the end-of-line normalization process
-
-text
: disable normalization for this type of file. Should be used for any type of binary file. -
text
: normalizes this type of file usingcore.eol
, which defaults to OS native (core.eol
should not be touched in normal situations) -
eol=lf
: forceslf
on all systems, regardless of OS -
eol=crlf
: forcescrlf
on all systems, regardless of OS -
global wildcards
-
* text=auto
- lets
git
detect file type and apply normalization accordingly - similar to setting
core.autocrlf=true
- lets
-
* -text
- people have tried to use this to emulate «checkout as-is commit as is»
- but they had various levels of success
- you can always use these wildcards in addition to more specific overrides
-
Beware, line-endings normalization must not be enabled on any binary file.
Updating the normalization settings
If you change the normalization settings (either core.autocrlf
or .gitattributes
), you will have some work to do on your local repository, on your remote repository, and on your colleagues workstations.
You can also just leave it be, but you expose yourself to weird git behaviors (untouched files reported as changed, among others) or other issues.
Your first reflex would be to look at the line endings in your code editor and play around with the different git commands you’ll find online, but it can very quickly become very confusing.
View the difference between Index and Workspace
You will find quantities of «solutions»/tutorials in stackoverflow or other websites that tell you what to do, but they always miss some edge cases.
Git normalization does not happen in the workspace, but during the transition into or out of the index, so you need a way to view line-endings in both the index and the workspace before acting.
Here is the thing that should be checked to understand what is happening, and most tutorials don’t talk about it:
git ls-files --eol
Enter fullscreen mode
Exit fullscreen mode
Which could result in this type of output:
i/lf w/crlf attr/ Applications/K8S/versions.tf
i/lf w/lf attr/text eol=lf .gitignore
i/-text w/-text attr/ Services/SMB/hosts-2022-10-20.xlsx
i/lf w/lf attr/ .gitattributes
i/crlf w/crlf attr/ Applications/K8S/ci/backend.tfvars
i/lf w/crlf attr/text eol=lf Legacy/Modules/Keyvault/.gitignore
Enter fullscreen mode
Exit fullscreen mode
- i/ tells you how the file is saved in the index
- w/ tells you how the file is presented in the workspace
- attr/ tells you how the .gitattributes file(s) is (are) hinting git to deal with this file
For a usual Windows developer using the core.autocrlf=true
option (which is the default pushed by git installation on Windows), you should normally mostly get a mix of the first three types:
-
i/lf w/crlf attr/
: the file is normalized by git and uses Windows standard line-endingscrlf
-
i/lf w/lf attr/text eol=lf
: the file is normalized by git and enforced to uself
-
i/-text w/-text attr/
: the file is autodetected as a binary and not normalized by git
If you ended up with a mix of any other ones, it may be because you or somebody made some changes in the .gitattributes
file or the core.autocrlf
option.
Repairing i/crlf w/crlf attr/
This file was most probably pushed by someone using core.autocrlf=false
and working in Windows. This will typically make git complain about changes on untouched files.
Fix strategies:
-
in any case,
- make sure your have a clean repo before acting
- communicate on this change, because people will encounter real conflicts
-
option1: make a commit that will fix all the files in your repo with
git add . --renormalize
- pb: will impede your capability to do a blame
- you could instruct blame to be more happy with option
-w
- in practice, git GUIs will happily workaround this
- if necessary you could also use these blame options —ignore-rev, —ignore-revs-file
-
option2: rewrite your history
- pb: rewriting history is hard.
- need to synchronize all committers
- almost impossible in opensource projects
https://www.ofcodeandcolor.com/2013/08/29/normalizing-line-endings-in-git-repositories/
https://www.moxio.com/blog/43/ignoring-bulk-change-commits-with-git-blame
Repairing i/lf w/crlf attr/text eol=lf
In this case, the index is ok, but the workspace is «broken».
This file was probably checked out before attribute eol=lf
was specified.
Git will not bother you with this. But maybe your code editor or tool will bug you if it requires crlf
line-endings for some file types.
Examples:
- visual studio may complain or introduce incoherent line-endings if csproj have «wrong» line endings
- terraform will complain if
*.lock.hcl
files have wrong line-endings
The fix : delete the local file, and check it out again
Bulk fixing: pipe the output of this command to xargs rm, then do a git reset (with all the precautions needed!!!)
git ls-files --eol | grep "i/lf w/crlf attr/t" | cut -f2 -d$'\t'
Enter fullscreen mode
Exit fullscreen mode
Repairing i/lf w/lf attr/text eol=crlf
In this case, the index is ok, but the workspace is «broken».
This time, it may be a problem if your tooling or IDE requires lf
line-endings.
The fix: same as the other «broken» workspace situation.