Попытка исправить окончания строк с помощью git filter-branch, но безуспешно - PullRequest
265 голосов
/ 02 октября 2009

Я был укушен проблемой конца строки Windows / Linux с git. Похоже, через GitHub, MSysGit и другие источники, что лучшее решение - это настроить локальные репозитории на использование окончаний линий в стиле linux, но установить core.autocrlf на true. К сожалению, я не сделал этого достаточно рано, поэтому теперь каждый раз, когда я нажимаю изменения, концы строк обрезаются.

Я думал, что нашел ответ здесь , но я не могу заставить его работать на меня. Мои знания командной строки Linux в лучшем случае ограничены, поэтому я даже не уверен, что строка «xargs fromdos» делает в своем скрипте. Я продолжаю получать сообщения об отсутствии такого файла или каталога, и когда мне удается указать его на существующий каталог, он говорит мне, что у меня нет разрешений.

Я пробовал это с MSysGit на Windows и через терминал Mac OS X.

Ответы [ 8 ]

384 голосов
/ 02 октября 2009

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

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .
183 голосов
/ 13 января 2011

Документация git для gitattributes теперь описывает другой подход для "исправления" или нормализации всех концов строк в вашем проекте. Вот суть этого:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

Если есть файлы, которые не должны быть Нормализованный показ в состоянии GIT, сбросить их текстовый атрибут перед работает git add -u.

manual.pdf -text

И наоборот, текстовые файлы, которые делает git не обнаружить может иметь нормализацию включен вручную.

weirdchars.txt text

Это использует новый флаг --renormalize, добавленный в git v2.16.0, выпущенный в январе 2018. Для более старых версий 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"
11 голосов
/ 04 декабря 2015

Моя процедура работы с окончаниями строк следующая (битва проверена на многих репо):

При создании нового репо:

  • поместите .gitattributes в самый первый коммит вместе с другими типичными файлами, такими как .gitignore и README.md

При работе с существующим репо:

  • Создать / изменить .gitattributes соответственно
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n (--no-verify - пропуск хуков предварительной фиксации)
    • Я должен делать это достаточно часто, чтобы определить его как псевдоним alias fixCRLF="..."
  • повторите предыдущую команду
    • Да, это voodoo, но обычно мне приходится запускать команду дважды: первый раз нормализует некоторые файлы, второй - еще больше файлов. Как правило, лучше всего повторять, пока не будет создан новый коммит:)
  • несколько раз переходите назад и вперед между старой (непосредственно перед нормализацией) и новой веткой. После переключения ветки иногда git находит еще больше файлов, которые нужно перенормировать!

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

Содержание .gitattributes

Мой .gitattributes обычно выглядит так:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

Чтобы выяснить, какие отдельные расширения отслеживаются git в текущем репо, посмотрите здесь

Проблемы после нормализации

Как только это будет сделано, есть еще одна распространенная оговорка.

Скажите, что ваш master уже обновлен и нормализован, а затем вы оформляете заказ outdated-branch. Довольно часто сразу после проверки этой ветки git помечает многие файлы как измененные.

Решение состоит в том, чтобы сделать поддельный коммит (git add -A . && git commit -m 'fake commit') и затем git rebase master. После перебазировки фальшивый коммит должен исчезнуть.

4 голосов
/ 09 марта 2012
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Пояснение:

  • git status --short

    Здесь отображаются все строки, о которых git знает и не знает. Файлы, которые не находятся под контролем git, помечаются в начале строки знаком «?». Измененные файлы помечаются знаком M.

  • grep "^ *M"

    Отфильтровывает только те файлы, которые были изменены.

  • awk '{print $2}'

    Показывает только имя файла без каких-либо маркеров.

  • xargs fromdos

    Это берет имена файлов из предыдущей команды и запускает их через утилиту 'fromdos' для преобразования концов строк.

3 голосов
/ 02 апреля 2015

Вот как я исправил все окончания строк во всей истории, используя git filter-branch. Символ ^M необходимо вводить с помощью CTRL-V + CTRL-M. Я использовал dos2unix для преобразования файлов, так как это автоматически пропускает двоичные файлы.

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'
3 голосов
/ 02 октября 2009

«| xargs fromdos» читает из стандартного ввода (файлы find находят) и использует его в качестве аргументов для команды fromdos, которая преобразует окончания строки. (Является ли стандарт fromdos в этих средах? Я привык к dos2unix). Обратите внимание, что вы можете избежать использования xargs (особенно полезно, если у вас достаточно файлов, так что список аргументов слишком длинный для xargs):

find <path, tests...> -exec fromdos '{}' \;

или

find <path, tests...> | while read file; do fromdos $file; done

Я не совсем уверен насчет ваших сообщений об ошибках. Я успешно проверил этот метод. Какую программу продюсирует каждый? Для каких файлов / каталогов у вас нет прав? Тем не менее, вот попытка угадать, что это может быть:

Один простой способ получить ошибку «file not found» для скрипта - использовать относительный путь - использовать абсолютный путь. Точно так же вы можете получить ошибку прав доступа, если вы не сделали исполняемый скрипт (chmod + x).

Добавьте комментарии, и я постараюсь помочь вам разобраться!

1 голос
/ 30 апреля 2012

окей ... под cygwin у нас нет легкодоступных fromdos, и этот awk substeb взрывается у вас на лице, если у вас есть пробелы в путях к измененным файлам (которые у нас были), поэтому мне пришлось сделать это несколько по-разному:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

спасибо @lloyd за основную часть этого решения

0 голосов
/ 07 мая 2014

Выполните следующие действия, если у вас нет другого ответа:

  1. Если вы работаете в Windows, выполните git config --global core.autocrlf true; если вы работаете в Unix, сделайте git config core.autocrlf input
  2. Выполнить git rm --cached -r .
  3. Удалить файл .gitattributes
  4. Выполнить git add -A
  5. Выполнить git reset --hard

Тогда ваш местный житель должен быть чистым.

...