git-diff игнорировать ^M

В проекте, где некоторые файлы содержат ^M в качестве разделителей новой строки. Различить эти файлы, по-видимому, невозможно, так как git-diff видит это, поскольку весь файл представляет собой одну строку.

Как отличается от предыдущей версии?

Есть ли такая опция, как "трактовать ^M как перевод строки при изменении"?

prompt> git-diff "HEAD^" -- MyFile.as 
diff --git a/myproject/MyFile.as b/myproject/MyFile.as
index be78321..a393ba3 100644
--- a/myproject/MyFile.cpp
+++ b/myproject/MyFile.cpp
@@ -1 +1 @@
-<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
+<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
prompt>

ОБНОВИТЬ:

Теперь я написал скрипт, который проверяет последние 10 ревизий и конвертирует CR в LF.

require 'fileutils'

if ARGV.size != 3
  puts "a git-path must be provided"
  puts "a filename must be provided"
  puts "a result-dir must be provided"
  puts "example:"
  puts "ruby gitcrdiff.rb project/dir1/dir2/dir3/ SomeFile.cpp tmp_somefile"
  exit(1)
end

gitpath = ARGV[0]
filename = ARGV[1]
resultdir = ARGV[2]

unless FileTest.exist?(".git")
  puts "this command must be run in the same dir as where .git resides"
  exit(1)
end

if FileTest.exist?(resultdir)
  puts "the result dir must not exist"
  exit(1)
end
FileUtils.mkdir(resultdir)

10.times do |i|
  revision = "^" * i
  cmd = "git show HEAD#{revision}:#{gitpath}#{filename} | tr '\\r' '\\n' > #{resultdir}/#{filename}_rev#{i}"
  puts cmd 
  system cmd
end

14 ответов

Решение

GitHub предлагает вам обязательно использовать \n в качестве символа новой строки в репозиториях с git-обработкой. Существует возможность автоматического преобразования:

$ git config --global core.autocrlf true

Конечно, говорят, что это конвертирует crlf в lf, а вы хотите конвертировать cr в lf. Я надеюсь, что это все еще работает...

А затем конвертировать ваши файлы:

# Remove everything from the index
$ git rm --cached -r .

# 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 "Fix CRLF"

core.autocrlf описан на странице руководства.

Разрабатывая на Windows, я столкнулся с этой проблемой при использовании git tfs, Я решил это так:

git config --global core.whitespace cr-at-eol

Это в основном говорит Git, что CR конца строки не является ошибкой. В результате эти раздражающие ^M символы больше не появляются в конце строк git diff, git show, так далее.

Кажется, чтобы оставить другие настройки как есть; например, дополнительные пробелы в конце строки по-прежнему отображаются как ошибки (выделены красным) в diff.

(В других ответах упоминалось об этом, но выше указано, как именно установить настройку. Чтобы установить настройку только для одного проекта, опустите --global.)

РЕДАКТИРОВАТЬ:

После многих трудностей, связанных с окончанием строки, мне больше всего повезло при работе в команде.NET с этими настройками:

  • Нет настройки core.eol
  • Нет настройки core.whitespace
  • Нет настройки core.autocrlf
  • При запуске установщика Git для Windows вы получите следующие три варианта:
    • Оформить заказ в стиле Windows, зафиксировать окончания строк в стиле Unix <- выберите этот
    • Оформить заказ как есть, зафиксировать окончания строки в стиле Unix
    • Оформить заказ как есть, зафиксировать как есть

Если вам нужно использовать параметр пробелов, вам, вероятно, следует включить его только для каждого проекта, если вам нужно взаимодействовать с TFS. Просто опустите --global:

git config core.whitespace cr-at-eol

Если вам нужно удалить некоторые настройки core.*, Самый простой способ - запустить эту команду:

git config --global -e

Это откроет ваш глобальный файл.gitconfig в текстовом редакторе, и вы сможете легко удалить строки, которые хотите удалить. (Или вы можете поставить "#" перед ними, чтобы закомментировать их.)

Пытаться git diff --ignore-space-at-eol, или же git diff --ignore-space-change, или же git diff --ignore-all-space,

Также см:

core.whitespace = cr-at-eol

или эквивалентно,

[core]
    whitespace = cr-at-eol

где whitespace предшествует символ табуляции.

Почему вы получаете это ^M в вашем git diff?

В моем случае я работал над проектом, который был разработан в Windows, и я использовал OS X. Когда я изменил некоторый код, я увидел ^M в конце строк я добавил в git diff, я думаю ^M появлялись, потому что они были разными окончаниями строк, чем остальная часть файла. Поскольку остальная часть файла была разработана в Windows, она использовала CR окончания строк, а в OS X он использует LF окончания строки.

Очевидно, разработчик Windows не использовал опцию "Оформить заказ в стиле Windows, зафиксировать окончания строк в стиле Unix" во время установки Git.

Так что же нам с этим делать?

Вы можете заставить пользователей Windows переустанавливать git и использовать опцию "Оформлять заказ в стиле Windows, фиксировать окончания строк в стиле Unix". Это то, что я бы предпочел, потому что я вижу Windows как исключение в символах окончания строки, и Windows исправляет свою проблему таким образом.

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

  1. Удалите все файлы из хранилища, но не из вашей файловой системы.

    git rm --cached -r .
    
  2. Добавить .gitattributes файл, который заставляет определенные файлы использовать LF как окончания строки. Поместите это в файл:

    *.ext text eol=crlf
    

    замещать .ext с расширениями файлов, которые вы хотите сопоставить.

  3. Добавьте все файлы еще раз.

    git add .
    

    Это покажет такие сообщения:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Вы можете удалить .gitattributes файл, если у вас нет упрямых пользователей Windows, которые не хотят использовать опцию "Оформлять заказ в стиле Windows, фиксировать окончания строк в стиле Unix".

  5. Зафиксируйте и продвиньте все это.

  6. Удалите и извлеките соответствующие файлы во всех системах, где они используются. В системах Windows убедитесь, что теперь они используют опцию "Оформлять заказ в стиле Windows, фиксировать окончания строк в стиле Unix". Вы должны также сделать это в системе, где вы выполняли эти задачи, потому что, когда вы добавляли файлы, git сказал:

    The file will have its original line endings in your working directory.
    

    Вы можете сделать что-то вроде этого, чтобы удалить файлы:

    git ls | grep ".ext$" | xargs rm -f
    

    И затем это, чтобы вернуть их с правильными окончаниями строки:

    git ls | grep ".ext$" | xargs git checkout
    

    Конечно замена .ext с расширением, которое вы хотите.

Теперь ваш проект использует только LF символы для окончаний строк и противные CR персонажи никогда не вернутся:).

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

Дополнительная информация: https://help.github.com/articles/dealing-with-line-endings/

Есть ли такая опция, как "трактовать ^M как перевод строки при изменении"?

Будет один с Git 2.16 (Q1 2018), как " diff "Семейство команд научилось игнорировать различия в возврате каретки в конце строки.

См. Коммит e9282f0 (26 октября 2017 г.) от Junio ​​C Hamano ( gitster )
Помогает: Йоханнес Шинделин ( dscho )
(Объединено Юнио С Хамано - gitster - в коммите 10f65c2, 27 ноября 2017 г.)

Diff: --ignore-cr-at-eol

Новая опция --ignore-cr-at-eol говорит механизму diff обрабатывать возврат каретки в конце (полной) строки, как если бы он не существовал.

Так же, как другие " --ignore-* варианты игнорирования различий между пробелами, это поможет вам рассмотреть реальные изменения, которые вы сделали, не отвлекаясь на ложные CRLF<->LF преобразование сделано вашим редактором программы.

В моем случае это была команда:

git config  core.whitespace cr-at-eol

Источник: https://public-inbox.org/git/8d7e4807-9a79-e357-8265-95f22ab716e0@web.de/T/

TL;DR

Изменить core.pager в "tr -d '\r' | less -REX", а не исходный код

Вот почему

Эти показные ^M являются артефактом раскрашивания и пейджера. Это вызвано less -R опция по умолчанию для git-пейджера. (Git по умолчанию пейджер less -REX)

Первое, что нужно отметить, это то, что git diff -b не будет отображать изменения в пустом пространстве (например, \r\n vs \n)

настроить:

git clone https://github.com/CipherShed/CipherShed
cd CipherShed

Быстрый тест для создания файла Unix и изменения концов строк не покажет изменений с git diff -b:

echo -e 'The quick brown fox\njumped over the lazy\ndogs.' > test.txt
git add test.txt
unix2dos.exe test.txt
git diff -b test.txt

Мы отмечаем, что при наведении на трубу меньше не отображается ^M, но включается цвет и less -R делает:

git diff origin/v0.7.4.0 origin/v0.7.4.1 | less
git -c color.ui=always diff origin/v0.7.4.0 origin/v0.7.4.1 | less -R

Исправление показано с помощью канала для удаления \r (^M) из вывода:

git diff origin/v0.7.4.0 origin/v0.7.4.1
git -c core.pager="tr -d '\r' | less -REX"  diff origin/v0.7.4.0 origin/v0.7.4.1

Неразумной альтернативой является использование less -r потому что он будет проходить через все управляющие коды, а не только цветовые коды.

Если вы хотите просто отредактировать файл конфигурации git напрямую, это запись для обновления / добавления:

[core]
        pager = tr -d '\\r' | less -REX

Я долго боролся с этой проблемой. Безусловно, самое простое решение - не беспокоиться о символах ^M и просто использовать визуальный инструмент сравнения, который может их обработать.

Вместо ввода:

git diff <commitHash> <filename>

пытаться:

git difftool <commitHash> <filename>

Если вам просто нужна быстрая линия, которая делает git diffно не показывает разные концовки (поэтому ^M) используйте тот, что в первых комментариях к исходному вопросу, у меня это сработало:

       git diff -b

Учтите, что в конечном итоге вы должны правильно настроить окончания строк, как предполагают все другие ответы.

Как отмечает VonC, это уже включено в git 2.16+. К сожалению, название опции (--ignore-cr-at-eol) отличается от используемого GNU diff, к которому я привык (--strip-trailing-cr).

Когда я столкнулся с этой проблемой, моим решением было вызвать GNU diff вместо встроенного в git diff, потому что мой git старше 2.16. Я сделал это с помощью этой командной строки:

GIT_EXTERNAL_DIFF='diff -u --strip-trailing-cr "$2" "$5";true;#' git diff --ext-diff

Это позволяет использовать --strip-trailing-cr и любые другие варианты GNU diff.

Есть и другой способ:

git difftool -y -x 'diff -u --strip-trailing-cr'

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

Если патч git уже сгенерирован на компьютере с Windows и вы его используете, вы можете отформатировать патч с помощью утилиты dos2unix в Linux.

      find -name "*.patch"| xargs dos2unix

Это решит ^M в EOL, и вы сможете применить патч git на своем компьютере с Linux.

Объединитеcore.autocrlf=trueнастройка с помощью--ignore-space-at-eolпараметрер, чтобы игнорировать изменения конца строки:

      git -c "core.autocrlf=true" diff --ignore-space-at-eol

Если вы используете Eclipse, вы можете сделать ^M исчезнуть из git diff установив File > Convert Line Delimiter To > Unix (LF, \n, 0A, ¶)

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