Force LF eol в git-репо и рабочей копии

170

У меня есть git-репозиторий, размещенный на github. Многие из файлов были изначально разработаны для Windows, и я не слишком заботился об окончании строк. Когда я выполнил начальную фиксацию, у меня также не было никакой конфигурации git для обеспечения правильного окончания строк. В результате в моем репозитории github есть несколько файлов с окончаниями строк CRLF.

Сейчас я частично занимаюсь разработкой для Linux, и я хотел бы очистить окончание строк. Как я могу убедиться, что файлы правильно хранятся с помощью LF на github и имеют LF в моей рабочей копии?

Я создал .gitattributesфайл, содержащий text eol=LF; это правильно? С этим совершенным и подталкиваемым, могу ли я просто сделать rmлокальное репо и повторно клонировать его с github, чтобы получить желаемый эффект?

Chowlett
источник
1
возможный дубликат git с заменой LF на CRLF
Lazy Badger
Ни то, ни другое не совсем то, о чем я спрашиваю. Я единственный разработчик, и я вполне готов настроить все мои машины одинаково. У меня есть репозиторий, в котором уже есть несколько файлов CRLF, и несколько клонов на разных машинах. Как я могу обновить репо и каждую рабочую копию, чтобы везде были LF?
Чоулетт
Вы смотрели это руководство Github?
Энди

Ответы:

237

Без некоторой информации о том, какие файлы находятся в вашем хранилище (чистый исходный код, изображения, исполняемые файлы, ...), довольно сложно ответить на вопрос :)

Кроме того, я буду считать, что вы по умолчанию хотите использовать LF в качестве окончания строк в вашем рабочем каталоге, потому что вы хотите убедиться, что текстовые файлы имеют окончания LF в вашем репозитории .git, если вы работаете в Windows или Linux , Действительно лучше, чем потом сожалеть ....

Тем не менее, есть лучшая альтернатива: используйте концы строк LF в вашем рабочем каталоге Linux, окончания строк CRLF в вашем рабочем каталоге Windows и окончания строк LF в вашем хранилище.

Поскольку вы частично работаете над Linux и Windows, убедитесь, что core.eolустановлено nativeи core.autocrlfустановлено на true.

Затем замените содержимое вашего .gitattributesфайла следующим

* text=auto

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

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

Если вы работаете над проектом обработки изображений на основе C, замените содержимое вашего .gitattributesфайла следующим

* text=auto
*.txt text
*.c text
*.h text
*.jpg binary

Это гарантирует, что файлы с расширением c, h или txt будут храниться с LF-окончаниями в вашем репо и будут иметь собственные окончания в рабочем каталоге. Файлы JPEG не будут затронуты. Все остальные получат выгоду от той же автоматической фильтрации, как показано выше.

Чтобы получить более глубокое понимание внутренних деталей всего этого, я бы посоветовал вам погрузиться в этот очень хороший пост « Имей в виду конец своей линии» от Гитуббера Тима Клема.

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

ОБНОВЛЕНИЕ к ответу, учитывая следующий комментарий

Я на самом деле не хочу CRLF в моих каталогах Windows, потому что моя среда Linux на самом деле представляет собой VirtualBox, разделяющий каталог Windows

Имеет смысл. Спасибо за разъяснения. В этом конкретном контексте одного .gitattributesфайла будет недостаточно.

Запустите следующие команды для вашего хранилища

$ git config core.eol lf
$ git config core.autocrlf input

Поскольку ваш репозиторий является общим для вашей среды Linux и Windows, это обновит локальный файл конфигурации для обеих сред. core.eolудостоверится, что текстовые файлы имеют LF окончания строки при оформлении заказа core.autocrlfгарантирует, что потенциальные CRLF в текстовых файлах (например, в результате операции копирования / вставки) будут преобразованы в LF в вашем хранилище.

При желании, вы можете помочь Git различать , что это текстовый файл, создав .gitattributesфайл , содержащий нечто похожее на следующее:

# Autodetect text files
* text=auto

# ...Unless the name matches the following
# overriding patterns

# Definitively text files 
*.txt text
*.c text
*.h text

# Ensure those won't be messed up with
*.jpg binary
*.data binary

Если вы решили создать .gitattributesфайл, передайте его .

Наконец, убедитесь, что git statusупоминается «ничего не совершать (очистка рабочего каталога)» , затем выполните следующую операцию

$ git checkout-index --force --all

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

Как только это будет сделано, каждый текстовый файл в вашем рабочем каталоге будет иметь LF-окончания и git statusвсе равно должен будет считать рабочий каталог чистым.

nulltoken
источник
34
Я на самом деле не хочу CRLF в моих каталогах Windows, потому что моя среда Linux на самом деле представляет собой VirtualBox, совместно использующий каталог Windows; и хотя Notepad ++ и т. д. может обрабатывать только LF в Windows, viон менее доволен CRLF. Должен ли я просто хочу , чтобы изменить его так , что core.autocrlfесть false(или input)?
Чоулетт
5
Отличный ответ. Краткое примечание для всех, кто использует эту настройку: строка "* text = auto" должна быть первой строкой в ​​вашем файле .gitattributes, чтобы последующие строки могли переопределить этот параметр.
Ари Патрик
9
@CMCDragonkai В зависимости от вашей оболочки, git checkout-index --force --allможет работать лучше. Второй пункт выглядит немного не по теме в отношении исходного вопроса. Как насчет того, чтобы задать специальный вопрос?
nulltoken
8
Я не понимаю, почему .gitattributes не может справиться с делением рабочей копии между Linux и Windows. Разве мы не можем установить textи eol=lfдостичь того же результата, который описан в вашем ответе через core.eolи core.autocrlf?
DanielSank
10
git checkout-index --force --allничего не делает для меня Что работает, так это список команд в инструкциях GitHub для решения этой проблемы.
Роман Старков
128

Начиная с git 2.10 (выпущен 2016-09-03), нет необходимости перечислять каждый текстовый файл отдельно. Git 2.10 исправил поведение text = auto вместе с eol = lf . Источник .

.gitattributes файл в корне вашего репозитория git:

* text=auto eol=lf

Добавьте и передайте это.

После этого вы можете выполнить следующие шаги и все файлы теперь нормализованы:

git rm --cached -r .  # Remove every file from git's index.
git reset --hard      # Rewrite git's index to pick up all the new line endings.

Источник: Ответ от Кенорб .

koppor
источник
7
Git 2,10 был выпущен 3 сентября 2016 года
стил
Я запустил это, и он заложил все мои нетекстовые файлы
Энтони
Вы можете явно установить двоичный режим для определенных файлов. - Интересно, почему автоопределение (все еще ?!) не работает на некоторых файлах
koppor
Это должен быть принятый ответ.
CletusW
25

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

# Ensure all C and PHP files use LF.
*.c         eol=lf
*.php       eol=lf

что гарантирует, что все файлы, которые Git считает текстовыми, имеют в конце LFстроки нормализованное ( ) окончание строки (обычно это core.eolэлементы управления конфигурацией, которые у вас есть по умолчанию).

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

$ echo "* text=auto" >> .gitattributes
$ rm .git/index     # Remove the index to force Git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

или согласно документации GitHub :

git add . -u
git commit -m "Saving files before refreshing line endings"
git rm --cached -r . # Remove every file from Git's index.
git reset --hard # Rewrite the Git index to pick up all the new line endings.
git add . # Add all your changed files back, and prepare them for a commit.
git commit -m "Normalize all the line endings" # Commit the changes to your repository.

Смотрите также: @Charles Bailey post .

Кроме того, если вы хотите исключить какие-либо файлы, которые не рассматриваются как текст, отмените их атрибут текста, например

manual.pdf      -text

Или отметьте это явно как двоичный файл:

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Для того, чтобы увидеть некоторые более продвинутый файл мерзавец нормализации, проверьте .gitattributesв ядре Drupal :

# Drupal git normalization
# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# @see https://www.drupal.org/node/1542048

# Normally these settings would be done with macro attributes for improved
# readability and easier maintenance. However macros can only be defined at the
# repository root directory. Drupal avoids making any assumptions about where it
# is installed.

# Define text file attributes.
# - Treat them as text.
# - Ensure no CRLF line-endings, neither on checkout nor on checkin.
# - Detect whitespace errors.
#   - Exposed by default in `git diff --color` on the CLI.
#   - Validate with `git diff --check`.
#   - Deny applying with `git apply --whitespace=error-all`.
#   - Fix automatically with `git apply --whitespace=fix`.

*.config  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.css     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.dist    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.engine  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.html    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html
*.inc     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.js      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.json    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.lock    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.map     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.module  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.php     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.po      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.script  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.sh      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.sql     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.svg     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.theme   text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.twig    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.txt     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.xml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.yml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

# Define binary file attributes.
# - Do not treat them as text.
# - Include binary diff in patches instead of "binary files differ."
*.eot     -text diff
*.exe     -text diff
*.gif     -text diff
*.gz      -text diff
*.ico     -text diff
*.jpeg    -text diff
*.jpg     -text diff
*.otf     -text diff
*.phar    -text diff
*.png     -text diff
*.svgz    -text diff
*.ttf     -text diff
*.woff    -text diff
*.woff2   -text diff

Смотрите также:

kenorb
источник
2
1. text=autoвводит в заблуждение. Вы не можете использовать text=autoи eolвместе. Настройка eolотключает автоматическое обнаружение текстовых файлов. Вот почему вы должны указать все эти типы файлов. Если бы autoбыло включено, вам не нужно все это. 2. Вам не нужно textи eol=lf. eol=lfэффективно устанавливает text.
Бен
2
Во-вторых, @Ben сказал, что эта конфигурация в настоящее время неверна и опасна, если вы явно не отметите все двоичные файлы.
Майкл Р
1
Я читал, что * text=auto eol=lfпервый text=autoотменяется eol=lf. Где вы нашли эту функцию? Вот мой источник: stackoverflow.com/questions/29435156/…
CMCDragonkai
Удалено * text=auto eol=lfиз примера, поскольку оно было удалено и из Drupal. Также рассмотрите возможность удаления комментариев.
Кенорб
4
Важно отметить, что то, что сказал @Ben, больше не соответствует действительности и всегда было ошибкой, а не предполагаемым поведением.
Семмел