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

474

В проекте, где некоторые файлы содержат ^ 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>

ОБНОВИТЬ:

Теперь я написал скрипт на Ruby, который проверяет последние 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
neoneye
источник
7
Вы, возможно, хотели git diff -b- я показал это в stackoverflow.com/a/46265081/58794
Джейсон Пиерон
6
С Git 2.16 (Q1 2018) у вас будет git diff --ignore-cr-at-eol. Смотрите мой ответ ниже .
VonC
7
@JasonPyeron и для будущих Googlers: мне пришлось искать, что git diff -bидентично git diff --ignore-space-change.
Gogowitsch

Ответы:

392

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 описан на странице руководства .

nes1983
источник
1
Нет, конечно, нет, как только настройка будет установлена, она будет автоматически преобразовываться при фиксации. Если все работает так, как я думаю, то есть ...
nes1983
1
Проблема в том, что у меня уже есть некоторые файлы в хранилище, которые имеют окончания CRLF, а другие нет. Я подозреваю, что Adobe Flash добавляет CRLF, хотя я использую версию для Mac. Мне нужно сравнить со старыми версиями этих файлов. Преобразование концов строк, начиная с этого момента, не решает проблему со старыми ревизиями: - /
neoneye
65
Вы не работаете с файлами CRLF здесь, по крайней мере, в примере, который вы опубликовали. Это Mac-файл старого стиля (просто использует \ r для EOL). Вот почему разница отображается на одной строке. В файле, использующем dos EOL, каждая строка будет четко отображаться с завершающим ^ M, через который вы можете указать, как обработать git config core.whitespace cr-at-eol.
Jamessan
12
Я пытаюсь это, но я продолжаю получать warning: LF will be replaced by CRLFвместо warning: CRLF will be replaced by LF, и я в Linux. Есть идеи почему? Я хочу, чтобы все заканчивалось LF, а не CRLF!
trusktr
5
@trusktr, со мной случилось то же самое. В linux, со случайным CRLF, используйте git config --global core.autocrlf input, выполните шаги в этом ответе (rm, add, commit), и вы получите warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Удалите файлы (поскольку они имеют исходный, неправильный CRLF) и извлеките их снова из последнего коммита «Fix CRLF».
jmmut
370

Разрабатывая на 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 в текстовом редакторе, и вы сможете легко удалить строки, которые хотите удалить. (Или вы можете поставить «#» перед ними, чтобы закомментировать их.)

Райан Ланди
источник
30
Для тех , кто находит это сейчас, это стоит отметить , что Checkout Windows-стиль, совершают Unix-стиль линия окончания авто-наборы core.autocrlfдляtrue
К. Карпентер
14
Обратите внимание, что линия git config --global core.whitespace cr-at-eolотключит другие настройки, которые по умолчанию. Существует три значения по умолчанию: blank-at-eol, blank-at-eof и пробел перед вкладкой. Таким образом, чтобы включить cr-at-eol, оставив другие, которые вам нужно использовать git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Цитрак
2
Для моего проекта (это было оформление заказа в Windows, и я просматриваю его в Linux), cr-at-eolизбавился от ^Mконца строк в git diffцелом, но GIT по-прежнему показывал эти строки как разные, хотя окончание строки было единственным отличием.
Янис Элмерис
SourceInsight продолжает нажимать символ ^ M, и git по-прежнему показывает разницу в конце строки. Команда @ Zitrax - правильный ответ на мой случай, git diff показывает хороший и чистый вывод.
Ле Куанг Дуй
3
Я думаю, что git нужно немного больше сложности, несколько более противоречивых настроек для конца строки. Я думаю, что git должен быть более обеспокоен моими пробелами. Например, выдайте несвязанную фатальную ошибку и оставьте репозиторий в поврежденном состоянии при обнаружении концов строк Mac на компьютере с Windows (но не с Linux). Я имею в виду, почему я должен использовать VCS, который возражал бы против его бизнеса и позволял бы мне использовать любые окончания строк, которые я хочу? Я вижу, что они пытаются, но им нужно добавить еще полдюжины вариантов поведения в конце строки, чтобы решить проблему, которой не существует. Они почти у цели! Так держать.
Рольф
125

Попробуй git diff --ignore-space-at-eol, или git diff --ignore-space-change, или git diff --ignore-all-space.

Якуб Наребски
источник
22
Ничто из этого не влияет на характер, который определяет новую строку.
nes1983
4
Я также попытался с "-w", но не повезло, все еще обрабатывает его как одну строку. Следующий проект, который я должен помнить, никогда не включать CR в исходный код.
neoneye
3
Просто запомните git config --global core.autocrlf true или сообщайте об ошибках git, пока они не
установят
10
Это решило мою проблему без необходимости менять мои autocrlfнастройки. Спасибо!
nneonneo
11
эти флаги не влияют на меня ... все еще показывает ^ M в виде различий
Магнус
103

Также см:

core.whitespace = cr-at-eol

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

[core]
    whitespace = cr-at-eol

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

Владимир Пантелеев
источник
4
Да, это заставило инструмент git diff (также используемый в git show) перестать беспокоить меня о ^Ms на измененных строках! :)
Рейк
2
по какой-то причине это не сработало для меня. Пробовал и со знаком = и без =. git diffпо-прежнему показывает ^ M символов.
Деннис
6
Это можно сделать двумя способами: во-первых, добавить строку выше дословно к вашему .gitconfig либо в .git / config, либо в ~ / .gitconfig; два git config --global core.whitespace cr-at-eol(где --global необязателен, если вы просто хотите, чтобы он был в репо, на котором вы находитесь)
К. Карпентер
Это работало для меня в Windows 7, хотя я просто включил его, [core]чтобы я мог заменить core.префикс символом TAB.
Rufflewind
Этот вопрос был выше , как спрятаться ^Mв git diff, а не о том , как не ставить в ^ М , в первую очередь. Это означает, что принятый ответ об изменении core.autocrlfне самый лучший, потому что он молча изменяет файлы без подтверждения пользователя.
deddebme
45

Почему вы получаете это ^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/#platform-all

gitaarik
источник
4
Чтобы исправить все окончания строк в определенном файле, если вы используете Sublime Text, вы можете перейти к View-> Line Endingsи нажать на Unix.
Тофер Хант
Что именно это ^Mзначит? Это новая строка для Windows или Linux? Или это просто "другая" новая строка по сравнению с другими новыми строками в файле?
buhtz
Хороший, я думаю, что это просто «другой»
перевод
-1, поскольку переустановка git для выполнения git config --global core.autocrlf true- это перебор, а анти-Windows / анти- CRкампания кажется касательной к этому вопросу.
RJFalconer
41

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

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

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

Diff: --ignore-cr-at-eol

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

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

VonC
источник
@kaartic Спасибо за редактирование ответа и ссылку на правильный коммит!
VonC
3
Несмотря на то, что, как правило, рекомендуется задавать, git config --global core.autocrlf trueкак в принятом ответе, это отвечает на вопрос ОП более прямо: «Есть ли такая опция, как« трактовать ^ M как новую строку при рассчете »?
drkvogel
1
Начиная с Git 2.20 это не скрывает ^ M's
user1944491
@ user1944491 Я не заметил какой-либо регрессии, то есть он игнорирует eol при использовании этой опции в Git 2.26.
VonC
@VonC Использование этого аргумента в команде git diff не сработало. Также не было установки значения core.whitespace, git version 2.20.1 (Apple Git-117)но добавление ответа core.pager Джейсона Пиерона исправило его. YMMV очевидно.
user1944491
26

TL; DR

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

Вот почему

Эти показные ^ M являются артефактом раскрашивания и пейджера. введите описание изображения здесь Это вызвано less -Rпараметром git pager по умолчанию. (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

Мы отмечаем, что при принудительном использовании pipe к параметру less не отображается ^ 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
Джейсон Пиерон
источник
У меня была эта проблема в репозитории, где у некоторых файлов были \r\nокончания строк, а у некоторых - \nокончания строк (я не знаю, уместно ли это); различия первых показали ^Mв измененных строках (то есть в +строках). core.autocrlfбыл установлен в true. Бег git config core.pager "tr -d '\r' | less -REX"избавился от надоедливых ^Mс. Спасибо!
labreuer
5
Спасибо за это. Это единственный ответ, если вы должны работать с разными окончаниями строк в своем репо (-ах) - например, вы целенаправленно используете извлечение как есть, фиксируйте как есть.
Майк
git diff -bэто то, что я искал, но я ценю подробное объяснение.
Мартин Берч
Это ответ! Спасибо. флаг -b не работает для меня.
Крис
Да! Из всех ответов на этот вопрос, изменение [core]раздела файла git «config» путем добавления pager = tr -d '\\r' | less -REXбыло единственным ответом, который работал для меня. Спасибо!
Рашики
13

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

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

git diff <commitHash> <filename>

пытаться:

git difftool <commitHash> <filename>
Ян Войтович
источник
1
Спасибо! Также я просто запустил "git difftool", и он в основном сравнил все измененные файлы в цикле
Bhanuprakash D
2

Как отмечает 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'

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

Педро Химено
источник
Интересная альтернатива моему ответу. Upvoted.
VonC