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

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

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

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

9 ответов

Решение

В документации 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"

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

# 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 .

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

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

  • положил .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, После перебазировки фальшивый коммит должен исчезнуть.

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

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Объяснение:

  • git status --short

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

  • grep "^ *M"

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

  • awk '{print $2}'

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

  • xargs fromdos

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

"| 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).

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

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

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

слава @lloyd для большей части этого решения

У меня была такая же проблема в одном из моих репозиториев. Если вы используете как Windows, так и Linux-системы для одного и того же репозитория кода и одновременно извлекаете и выталкиваете, попробуйте следующее:

Сначала настройте конфигурацию git для Windows следующим образом:

      git config --global core.autocrlf true

Это обеспечит преобразование CRLF в LF при записи в базу данных объектов, а затем снова заменит LF на CRLF при записи в рабочий каталог. В результате ваше репо будет безопасным только с одним типом окончаний строк, и локально у вас будет окончание строки Windows в системе Windows.

Для Linux/MAC установите конфигурацию git следующим образом:

      git config --global core.autocrlf input

Это обеспечит преобразование CRLF в LF при записи в базу данных объектов, но не сделает обратное, сохранив LF, который необходим для linux/MAC.

Для неправильных окончаний строк, которые уже есть на вашем Linux/MAC, используйте dos2unix

Для МАК:

      brew install dos2unix # Installs dos2unix Mac
find . -type f -exec dos2unix {} \; # recursively removes windows related stuff

Для Linux:

      sudo apt-get install -y dos2unix # Installs dos2unix Linux
sudo find . -type f -exec dos2unix {} \; # recursively removes windows related stuff

Надеюсь, это решит вашу проблему.

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

  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

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

Другие вопросы по тегам