Как нормализовать рабочие окончания строк дерева в Git?

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

warning: CRLF will be replaced by LF in FILE.
The file will have its original line endings in your working directory.

Как я могу заставить git нормализовать мою рабочую копию файла для меня? Предпочтительно, чтобы git нормализовал все рабочее дерево.


person user11171    schedule 26.03.2013    source источник
comment
Для людей, которые ответят на этот вопрос в 2019 году, обратите внимание, что второй ответ (от @philippn) теперь лучше, чем принятый в настоящее время.   -  person CharlieB    schedule 21.01.2019


Ответы (6)


В клиенте Git версии 2.16 и выше сделать это стало намного проще. Просто используйте:

git add --renormalize .

Примечание: лучше делать это с чистой рабочей областью. Подробнее см.:

person philippn    schedule 01.06.2018
comment
Я только что попробовал это на Git Bash для Windows, и он подготовил каждый файл в репо для фиксации. - person william.berg; 29.05.2019
comment
У меня есть сообщение об ошибке: error: unknown option 'renormalize' - person Ryan Nghiem; 25.07.2019
comment
@RyanNghiem Что говорит git --version? Я предполагаю, что он просто старше 2.16, и вам нужно обновить его. ХТН - person philippn; 29.07.2019
comment
@cja Очистите рабочее пространство, как в: команда git status возвращает что-то вроде nothing to commit, working tree clean - person philippn; 05.07.2020
comment
Это просто ничего не делает для меня. :-/ - person Timmmm; 01.10.2020

Для тех, кто использует v2.16 или выше, вы можете просто использовать:

git add --renormalize .  # Update index with renormalized files
git status               # Show the files that will be normalized
git commit -m "Introduce end-of-line normalization"

Эти указания взяты прямо из gitattributes. Для более старых версий документы (до версии 2.12) предоставляют другой ответ:

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"

Выполните эту последовательность после того, как вы отредактировали .gitattributes.

Обновлять

Похоже, у некоторых пользователей возникли проблемы с приведенными выше инструкциями. В обновленной документации для gitattributes (с 2.12 по 2.14) представлен новый набор инструкций. (после редактирования файлов .gitattributes):

git read-tree --empty   # Clean index, force re-scan of working directory
git add .
git status        # Show files that will be normalized
git commit -m "Introduce end-of-line normalization"

Спасибо @vossad01 за указание на это.

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

git rm --cached -r .
git reset --hard

Теперь окончания строк в вашем рабочем дереве будут правильными.

person John Szakmeister    schedule 26.03.2013
comment
Это сработало, спасибо! Я просматривал документацию по gitattributes, но читать было так много, что я как бы проглядел ее и не смог найти то, что искал. Я чувствую себя глупо сейчас. - person user11171; 27.03.2013
comment
Не беда, бывает! Найти его не так просто, как должно быть. :-) - person John Szakmeister; 27.03.2013
comment
Это работает при первом добавлении .gitattributes или изменении настройки, но не работает, если рабочее дерево имеет другой EOL (по крайней мере, с MsysGit это не так). Для этого кажется, что git rm --cached -r ., а затем git reset --hard сработали (предупреждение: разрушает ваше рабочее дерево). Из help.github.com/articles/dealing-with-line-endings. - person waddlesplash; 15.02.2014
comment
Что-то изменилось с Git, что сломало это? Я использовал это много раз, но сейчас нахожусь в репозитории, где он не работает (git 2.13.0, linux). Вместо этого мне пришлось сделать git add . после удаления индекса (не забывая обо всем в рабочем каталоге, которое ранее не отслеживалось). - person vossad01; 03.06.2017
comment
@ vossad01 Можете ли вы объяснить, что не удалось в процессе? Я не вижу причины, по которой текущий ответ не должен работать. Я, конечно, тоже могу обновить ответ с помощью новой процедуры - я просто хочу немного больше понять проблему. - person John Szakmeister; 27.11.2017
comment
@jszakmeister Он не нормализует никакие файлы, см. мой предыдущий комментарий о том, интересно, изменилось ли что-то в Git, что сломало его. Я не знаю (и у меня нет достаточной мотивации для исследования), что изменилось, но теперь я прыгал между достаточно разными средами, чтобы быть уверенным, что что-то изменилось, что привело к необходимости новых направлений. - person vossad01; 27.11.2017
comment
@vossad01 Интересно. Я предполагаю, что мне придется играть с этим больше и видеть. Спасибо за внимание. - person John Szakmeister; 27.11.2017
comment
@ vossad01 Итак, я пробовал оба способа, и старый способ все еще работает нормально. На самом деле, с обоими способами я получаю абсолютно одинаковые результаты. Я не знаю, что вы сделали, но единственное требование для работы git add -u состоит в том, что у файла уже должна быть версия (он должен быть частью репо). Так, может быть, это то, где что-то терпит неудачу? Я пробовал это с 2.15.0, так что, возможно, была какая-то другая ошибка, влияющая на это в течение короткого времени. - person John Szakmeister; 28.11.2017
comment
У меня сработал только второй способ. Пришел сюда, так как у всех других руководств есть первый метод, который не работал, но метод git read-tree --empty был трюком - person Peter; 08.04.2018
comment
Будьте осторожны с вариантом git read-tree --empty; git add .. Любые отслеживаемые файлы, которые будут игнорироваться .gitignore, будут удалены при его использовании. Документация теперь рекомендует git add --renormalize . - person vossad01; 10.06.2018
comment
Есть ли настройка, которую мне нужно где-то изменить? Я запускал эти команды несколько раз, и в bash он говорит об успешном завершении, но когда я открываю файл в блокноте ++ с отображением строк, он все еще показывает CRLF. - person Roger Far; 18.03.2021
comment
@RogerFar, на какой ОС вы работаете? Окна? Что говорит git config --get core.autocrlf? - person John Szakmeister; 19.03.2021
comment
Там написано false. Но даже когда он пытается преобразовать окончания строк, это происходит слишком быстро, например, 5 секунд для 1000 файлов. В конце концов я использовал notepad++ для глобального поиска и замены. - person Roger Far; 19.03.2021
comment
@RogerFar У вас настроен .gitattributes? Я никогда не видел, чтобы это было реальной проблемой, даже под Windows. Похоже, вы пропустили шаг или что-то происходит с окружающей средой. И 5 секунд на 1000 вполне возможно. Преобразование чертовски просто, и Git ужасно эффективен в том, что он делает. Извините, это было проблемой для вас, хотя. - person John Szakmeister; 20.03.2021
comment
Я настроил .gitattributes да, но это странно. Он что-то зафиксировал, но ошибка git не показала, что он вообще изменил окончания строк, как и блокнот ++. - person Roger Far; 21.03.2021

Альтернативный подход (отличается только используемой командой)

Убедитесь, что у вас нет ожидающих изменений в репозитории:

$ git status
$ git stash

Измените .gitattributes, чтобы интерпретация CRLF изменилась:

$ echo "*.txt  text" >>.gitattributes
$ git commit -m "Made .txt files a subject to CRLF normalization." -- .gitattributes

Удалить данные из индекса и обновить рабочий каталог:

$ git rm --cached -r .
$ git reset --hard

Ознакомьтесь с исправлениями CRLF, которые предлагает Git:

$ git ls-files --eol
$ git status
$ git diff

Согласен с решением Git:

$ git add -u
$ git commit -m "Normalized CRLF for .txt files"

Перезагрузите изменения, как если бы было выполнено чистое клонирование:

$ git rm --cached -r .
$ git reset --hard
person gavenkoa    schedule 07.08.2017
comment
Примечание: опция --eol для git ls-files является новой в Git 2.8 (уже не новой, но некоторые люди все еще страдают от Git 1.7, даже в конце 2018 года!). - person torek; 21.09.2018
comment
git ls-files --eol помогает проверить правильность окончания строк во всех файлах, спасибо! - person forumulator; 05.03.2021

Настройки .gitattributes повлияют только на новые коммиты. Если в этом репозитории нет опубликованной истории (нет других зависящих от него), вы можете просмотреть всю историю. В Unix/Linux вы можете использовать dos2unix(1) для исправления всех файлов в сочетании с find(1) и с помощью перезаписи истории filter-branch (см. обсуждение в git book) можно даже подчистить полную историю проекта.

Используйте с особой осторожностью на свежем клоне. Свяжитесь с любым, у кого может быть клон, и посоветуйте им, что вы хотите сделать.

person vonbrand    schedule 26.03.2013
comment
Обычно я бы не советовал это решение, если не важна безупречная история. Есть так много способов выстрелить себе в ногу, переписав историю. Нормализуйте файлы в репо в одном коммите, и пусть .gitattributes сделает всю работу дальше. - person angularsen; 04.05.2016
comment
@angularsen, если важно опубликовать чистую, полезную историю ... вот почему я советую поработать над чистым, новым клоном и (повторно) опубликовать его, как только он будет проверен. - person vonbrand; 01.06.2020

Опция * text=auto в .gitattributes оставляет репозиторий Git в «недопустимом состоянии», если он содержит файлы с окончаниями строк CRLF (Windows), которые теперь помечены как текст (см. https://marc.info/?l=git&m=154484903528621&w=2). Стандартная опция перенормировки не работает корректно с фильтрами LFS, поэтому инструкции в других ответах или, например, в https://help.github.com/en/articles/dealing-with-line-endings работают некорректно. Вместо этого эти шаги сработали для нас:

Ситуация:

  • В Windows
  • Репозиторий Git содержал файлы с окончаниями строк CR и CRLF.
  • Добавлен * text=auto в .gitattributes (чтобы не зависело от того, установил ли пользователь core.crlf=auto в Windows)
  • Также изменил -crlf на -text для отслеживаемых файлов LFS, не уверен, что это необходимо.

    1. Create a new branch from the branch with the line ending problem (assuming no uncommitted changes there): git checkout -b feature/doing-stuff-fix-eol
    2. Удалите фильтры LFS из .gitattributes (замените все 'filter=lfs diff=lfs merge=lfs' ничем)
    3. Зафиксировать и нажать: git commit -a -m «Отключить фильтры LFS для исправления EOL»
    4. Переместить в папку без git
    5. Удалить LFS глобально: git lfs uninstall
    6. Создайте новый клон репозитория: git clone -b feature/doing-stuff-fix-eol [URL-адрес удаленного репозитория] fix-eol
    7. Нормализуйте окончания строк: git add --renormalize . (обратите внимание на точку, чтобы перенормировать все файлы)
    8. Проверяйте только правильные нормализованные файлы. Он не должен включать файлы, обычно обрабатываемые LFS!
    9. Зафиксировать и нажать (сохранить хэш): git commit -m «Исправить окончания строк»
    10. Переместить в папку без git
    11. Установите LFS глобально: git lfs install
    12. Перейдите к исходному клону репозитория и потяните
    13. Проверьте исходную ветку: git checkout feature/doing-stuff
    14. Cherry выбирает коммит исправления eol и нажимает: git cherry-pick [хэш]
    15. Удалите ветку eol и нажмите
    16. Удалите клон репозитория eol (или сохраните, если вам нужно исправить больше веток)
person Walter Laan    schedule 28.06.2019

Параметр конфигурации merge.renormalize может оказаться полезным.

person Solomon Ucko    schedule 01.06.2020