git-diff bỏ qua ^ M


474

Trong một dự án nơi một số tệp chứa ^ M làm dấu phân cách dòng mới. Việc khuếch tán các tệp này rõ ràng là không thể, vì git-diff thấy nó vì toàn bộ tệp chỉ là một dòng.

Làm thế nào để một khác với phiên bản trước?

Có một tùy chọn như "coi ^ M là dòng mới khi khác biệt" không?

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>

CẬP NHẬT:

bây giờ tôi đã viết một tập lệnh Ruby kiểm tra 10 bản sửa đổi mới nhất và chuyển đổi CR thành 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

7
bạn có thể đã muốn git diff -b- Tôi đã trình bày điều này trong stackoverflow.com/a/46265081/58794
Jason Pyeron

6
Với Git 2.16 (Q1 2018), bạn sẽ có git diff --ignore-cr-at-eol. Xem câu trả lời của tôi dưới đây .
VonC

7
@JasonPyeron và cho các nhân viên Google trong tương lai: Tôi đã phải tìm kiếm nó git diff -bgiống hệt git diff --ignore-space-change.
Gogowitsch

Câu trả lời:


392

GitHub gợi ý rằng bạn nên đảm bảo chỉ sử dụng \ n làm ký tự dòng mới trong các repos được xử lý bởi git. Có một tùy chọn để tự động chuyển đổi:

$ git config --global core.autocrlf true

Tất nhiên, điều này được cho là chuyển đổi crlf sang lf, trong khi bạn muốn chuyển đổi cr thành lf. Tôi hy vọng điều này vẫn hoạt động

Và sau đó chuyển đổi tập tin của bạn:

# 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 được mô tả trên trang man .


1
Không, tất nhiên là không, một khi cài đặt ở đó, nó sẽ âm thầm chuyển đổi theo cam kết. Nếu mọi thứ hoạt động theo cách tôi nghĩ, thì đó là
Mạnh

1
Vấn đề là tôi đã có một số tệp trong kho lưu trữ có kết thúc CRLF và các tệp khác thì không. Tôi nghi ngờ rằng Adobe Flash thêm CRLF mặc dù tôi đang sử dụng phiên bản Mac. Tôi cần so sánh với các phiên bản cũ hơn của các tệp này. Chuyển đổi kết thúc dòng bắt đầu từ bây giờ không giải quyết được vấn đề với các phiên bản cũ hơn: - /
neoneye

65
Bạn không làm việc với các tệp CRLF ở đây, ít nhất là không phải trong ví dụ bạn đã đăng. Đó là một tệp mac kiểu cũ (chỉ sử dụng \ r cho EOL). Đó là lý do tại sao khác biệt được hiển thị trên một dòng. Một tệp sử dụng dos EOL sẽ hiển thị từng dòng rõ ràng với dấu ^ M, mà bạn có thể yêu cầu xử lý thông qua git config core.whitespace cr-at-eol.
jamessan

12
Tôi đang thử điều này, nhưng tôi tiếp tục warning: LF will be replaced by CRLFthay vì warning: CRLF will be replaced by LFvà tôi đang ở trong Linux. Bất cứ ý tưởng tại sao? Tôi muốn tất cả kết thúc với LF, không phải CRLF!
trusktr

5
@trusktr, nó cũng xảy ra như vậy với tôi. Trong linux, với CRLF tình cờ, hãy sử dụng git config --global core.autocrlf input, thực hiện các bước trong câu trả lời này (rm, thêm, cam kết) và bạn sẽ nhận được warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Xóa các tệp (vì chúng có CRLF gốc, sai) và kiểm tra lại chúng từ lần xác nhận "Khắc phục CRLF" cuối cùng.
jmmut

370

Phát triển trên Windows, tôi gặp phải vấn đề này khi sử dụng git tfs. Tôi đã giải quyết nó theo cách này:

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

Điều này về cơ bản cho Git biết rằng CR cuối dòng không phải là lỗi. Kết quả là, những người gây phiền nhiễu ^Mnhân vật không còn xuất hiện ở phần cuối của dòng trong git diff, git showvv

Nó xuất hiện để lại các thiết lập khác như hiện trạng; chẳng hạn, khoảng trắng thừa ở cuối dòng vẫn hiển thị dưới dạng lỗi (được tô sáng màu đỏ) trong khác biệt.

(Các câu trả lời khác đã ám chỉ điều này, nhưng ở trên chính xác là cách đặt cài đặt. Để đặt cài đặt cho chỉ một dự án, hãy bỏ qua --global.)

CHỈNH SỬA :

Sau nhiều chuyến đi kết thúc, tôi đã gặp may mắn nhất, khi làm việc trong nhóm .NET, với các cài đặt sau:

  • KHÔNG cài đặt core.eol
  • KHÔNG cài đặt core.whitespace
  • KHÔNG cài đặt core.autocrlf
  • Khi chạy trình cài đặt Git cho Windows, bạn sẽ nhận được ba tùy chọn sau:
    • Thanh toán kiểu kết thúc Windows, cam kết kết thúc dòng kiểu Unix <- chọn mục này
    • Thanh toán theo nguyên trạng, cam kết kết thúc dòng kiểu Unix
    • Thanh toán nguyên trạng, cam kết nguyên trạng

Nếu bạn cần sử dụng cài đặt khoảng trắng, có lẽ bạn chỉ nên kích hoạt nó trên cơ sở từng dự án nếu bạn cần tương tác với TFS. Chỉ cần bỏ qua --global:

git config core.whitespace cr-at-eol

Nếu bạn cần xóa một số cài đặt lõi. *, Cách dễ nhất là chạy lệnh này:

git config --global -e

Thao tác này sẽ mở tệp .gitconfig toàn cầu của bạn trong trình soạn thảo văn bản và bạn có thể dễ dàng xóa các dòng bạn muốn xóa. (Hoặc bạn có thể đặt '#' trước mặt họ để nhận xét họ.)


30
Đối với những người tìm thấy điều này bây giờ, đó là đáng chú ý là Thanh toán Windows-phong cách, cam Unix-phong cách kết thúc dòng tự động bộ core.autocrlfđếntrue
K. Carpenter

14
Lưu ý rằng dòng git config --global core.whitespace cr-at-eolsẽ tắt các cài đặt khác mặc định. Có ba giá trị mặc định: blank-at-eol, blank-at-eof và dấu cách-trước-tab. Vì vậy, để kích hoạt cr-at-eol trong khi giữ những người khác bạn sẽ cần sử dụng git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax

2
Đối với dự án của tôi (đó là thanh toán trên Windows và tôi đang xem nó trên Linux), cr-at-eolđã loại bỏ ^Mở cuối dòng git diff, nhưng GIT vẫn hiển thị các dòng đó là khác nhau, mặc dù kết thúc dòng là khác biệt duy nhất.
Jāni Elmeris

SourceInsight tiếp tục đẩy ký tự ^ M và git vẫn hiển thị sự khác biệt ở cuối dòng. Lệnh của @ Zitrax là câu trả lời đúng cho trường hợp của tôi, git diff hiển thị đầu ra đẹp và sạch.
Lê Quang Duy

3
Tôi nghĩ rằng git cần phức tạp hơn một chút, một vài cài đặt xung đột hơn cho đến cuối dòng. Tôi nghĩ rằng git nên quan tâm nhiều hơn về khoảng trắng của tôi. Ví dụ, ném một lỗi nghiêm trọng không liên quan và khiến kho lưu trữ ở trạng thái bị hỏng khi gặp các kết thúc dòng Mac trên máy Windows (nhưng không phải Linux). Ý tôi là tại sao tôi lại sử dụng một VCS có liên quan đến việc kinh doanh và cho phép tôi sử dụng bất kỳ kết thúc dòng nào tôi muốn? Tôi thấy họ đang cố gắng, nhưng họ nên thực hiện thêm nửa tá hành vi kết thúc dòng, để giải quyết vấn đề không tồn tại. Họ sắp đến rồi! Giữ nó lên
Rolf

125

Hãy thử git diff --ignore-space-at-eol, hoặc git diff --ignore-space-change, hoặc git diff --ignore-all-space.


22
Không ai trong số đó thực sự ảnh hưởng đến nhân vật xác định dòng mới.
nes1983

4
Tôi cũng đã thử với "-w" nhưng không có may mắn, vẫn coi nó là một dòng duy nhất. Dự án tiếp theo tôi phải nhớ là không bao giờ nhận bất kỳ CR nào vào mã nguồn.
neoneye

3
Chỉ cần nhớ git config --global core.autocrlf đúng hoặc sửa lỗi git folks cho đến khi chúng biến nó thành mặc định :)
nes1983

10
Điều này đã giải quyết vấn đề của tôi mà không phải thay đổi autocrlfcài đặt của tôi . Cảm ơn!
nneonneo

11
những lá cờ này không có tác dụng đối với tôi ... vẫn hiển thị ^ M như diffs
Magnus

103

Cũng thấy:

core.whitespace = cr-at-eol

hoặc tương đương,

[core]
    whitespace = cr-at-eol

trong đó whitespacecó trước một ký tự tab .


4
Đúng, điều này làm cho công cụ git diff (cũng được sử dụng git show) ngừng làm phiền tôi về các ^Ms trên các dòng thay đổi! :)
Rijk

2
vì bất cứ lý do gì điều này không làm việc cho tôi. Đã thử cả hai với dấu = và không =. git diffvẫn hiển thị ^ M ký tự.
Dennis

6
Hai cách để làm điều này: một, thêm dòng trên nguyên văn vào .gitconfig của bạn trong .git / config hoặc trong ~ / .gitconfig; hai, git config --global core.whitespace cr-at-eol(trong đó --global là tùy chọn nếu bạn chỉ muốn nó trên repo bạn đang bật)
K. Carpenter

Điều này làm việc cho tôi trên Windows 7, mặc dù tôi chỉ đặt nó bên dưới [core]để tôi có thể thay thế core.tiền tố bằng ký tự TAB.
Rufflewind

Câu hỏi này là ở trên làm thế nào để ẩn ^Mtrong git diff, không phải về cách không đặt ^ M ở vị trí đầu tiên. Điều đó có nghĩa là câu trả lời được chấp nhận về việc thay đổi core.autocrlfkhông phải là tốt nhất vì nó âm thầm thay đổi các tệp mà không cần xác nhận của người dùng.
depdebme

45

Tại sao bạn có được những thứ này ^Mtrong của bạn git diff?

Trong trường hợp của tôi, tôi đang thực hiện một dự án được phát triển trong Windows và tôi đã sử dụng OS X. Khi tôi thay đổi một số mã, tôi thấy ^Mở cuối dòng tôi đã thêm vào git diff. Tôi nghĩ rằng ^Mđã được hiển thị bởi vì chúng là kết thúc dòng khác nhau so với phần còn lại của tập tin. Bởi vì phần còn lại của tệp được phát triển trong Windows, nó đã sử dụng CRkết thúc dòng và trong OS X, nó sử dụng LFkết thúc dòng.

Rõ ràng, nhà phát triển Windows đã không sử dụng tùy chọn " Thanh toán kiểu Windows, cam kết kết thúc dòng kiểu Unix " trong quá trình cài đặt Git.

Vậy chúng ta nên làm gì về điều này?

Bạn có thể yêu cầu người dùng Windows cài đặt lại git và sử dụng tùy chọn " Thanh toán kiểu Windows, cam kết kết thúc dòng kiểu Unix ". Đây là những gì tôi thích, bởi vì tôi thấy Windows là một ngoại lệ trong các ký tự kết thúc dòng của nó và Windows khắc phục vấn đề của riêng mình theo cách này.

Nếu bạn chọn tùy chọn này, tuy nhiên, bạn nên sửa các tệp hiện tại (vì chúng vẫn đang sử dụng CRkết thúc dòng). Tôi đã làm điều này bằng cách làm theo các bước sau:

  1. Xóa tất cả các tệp khỏi kho lưu trữ, nhưng không xóa khỏi hệ thống tệp của bạn.

    git rm --cached -r .
    
  2. Thêm một .gitattributes tệp thực thi một số tệp nhất định để sử dụng LFlàm kết thúc dòng. Đặt cái này trong tập tin:

    *.ext text eol=crlf
    

    Thay thế .extbằng các phần mở rộng tập tin bạn muốn phù hợp.

  3. Thêm tất cả các tập tin một lần nữa.

    git add .
    

    Điều này sẽ hiển thị các thông báo như thế này:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Bạn có thể xóa .gitattributestệp trừ khi bạn có những người dùng Windows cứng đầu không muốn sử dụng " Thanh toán theo kiểu Windows, cam kết kết thúc dòng kiểu Unix ".

  5. Cam kết và đẩy tất cả.

  6. Xóa và kiểm tra các tệp áp dụng trên tất cả các hệ thống mà chúng được sử dụng. Trên các hệ thống Windows, đảm bảo giờ đây chúng sử dụng tùy chọn " Thanh toán kiểu Windows, cam kết kết thúc dòng kiểu Unix ". Bạn cũng nên làm điều này trên hệ thống nơi bạn đã thực hiện các tác vụ này bởi vì khi bạn thêm các tệp git đã nói:

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

    Bạn có thể làm một cái gì đó như thế này để loại bỏ các tập tin:

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

    Và sau đó, điều này để đưa chúng trở lại với kết thúc dòng chính xác:

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

    Tất nhiên thay thế .ext bằng phần mở rộng bạn muốn.

Bây giờ dự án của bạn chỉ sử dụng LF ký tự cho các kết thúc dòng và các CRký tự khó chịu sẽ không bao giờ quay trở lại :).

Tùy chọn khác là để thực thi kết thúc dòng cửa sổ. Bạn cũng có thể sử dụng.gitattributes tập tin cho việc này.

Thông tin thêm: https://help.github.com/articles/deals-with-line-endings/#pl platform-all


4
Để sửa tất cả các kết thúc dòng trong một tệp cụ thể, nếu sử dụng Sublime Text, bạn có thể truy cập View-> Line Endingsvà nhấp vào Unix.
Topher Hunt

Chính xác thì điều này ^Mcó nghĩa là gì? Nó là một cửa sổ mới hoặc linux mới? Hay nó chỉ là một dòng mới "khác" so với các dòng mới khác trong tệp?
buhtz

Tốt, tôi nghĩ đó chỉ là một dòng mới "khác" (khác với hầu hết những người khác)
gitaarik

-1 khi cài đặt lại git để thực hiện git config --global core.autocrlf truelà quá mức cần thiết và CRchiến dịch chống Windows / chống chiến dịch dường như tiếp tuyến với câu hỏi.
RJFalconer

41

Có một tùy chọn như "coi ^ M là dòng mới khi khác biệt" không?

Sẽ có một với Git 2.16 (Q1 2018), vì họ " diff" các lệnh được học để bỏ qua sự khác biệt về lợi nhuận vận chuyển ở cuối dòng.

Xem cam kết e9282f0 (ngày 26 tháng 10 năm 2017) của Junio ​​C Hamano ( gitster) .
Được giúp đỡ: Julian Schindelin ( dscho) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 10f65c2 , ngày 27 tháng 11 năm 2017)

khác biệt --ignore-cr-at-eol

Một tùy chọn mới --ignore-cr-at-eolcho máy móc khác biệt xử lý trở lại vận chuyển ở cuối dòng (hoàn chỉnh) như thể nó không tồn tại.

Cũng giống như các --ignore-*tùy chọn " " khác để bỏ qua các loại khác biệt về khoảng trắng, điều này sẽ giúp xem xét các thay đổi thực sự bạn đã thực hiện mà không bị phân tâm bởi CRLF<->LFchuyển đổi giả được thực hiện bởi chương trình soạn thảo của bạn.


@kaartic Cảm ơn bạn đã chỉnh sửa câu trả lời và tham khảo đúng cam kết!
VonC

3
Mặc dù thông thường tốt để đặt git config --global core.autocrlf truenhư trong câu trả lời được chấp nhận, nhưng câu trả lời này của OP trực tiếp hơn: 'Có tùy chọn nào như "coi ^ M là dòng mới khi khác biệt" không?
drkvogel

1
Kể từ Git 2.20, điều này không che giấu ^ M's
user1944491

@ user1944491 Tôi không nhận thấy bất kỳ hồi quy nào, có nghĩa là nó sẽ bỏ qua eol khi khác với tùy chọn này trong Git 2.26.
VonC

@VonC Sử dụng đối số này trong lệnh git diff không hoạt động. Cũng không đặt giá trị core.whitespace của tôi git version 2.20.1 (Apple Git-117)nhưng thêm câu trả lời core.pager của Jason Pyeron đã sửa nó. YMMV rõ ràng.
dùng1944491

26

TL; DR

Thay đổi core.pagerthành "tr -d '\r' | less -REX", không phải mã nguồn

Đây là lý do tại sao

Những pesky ^ M hiển thị là một tạo tác của màu sắc và máy nhắn tin. nhập mô tả hình ảnh ở đây Nó được gây ra bởi less -R, một tùy chọn git pager mặc định. (máy nhắn tin mặc định của git là less -REX)

Điều đầu tiên cần lưu ý là git diff -bsẽ không hiển thị các thay đổi trong khoảng trắng (ví dụ: \ r \ n vs \ n)

thiết lập:

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

Thử nghiệm nhanh để tạo tệp unix và thay đổi kết thúc dòng sẽ cho thấy không có thay đổi nào với 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

Chúng tôi lưu ý rằng việc buộc một đường ống ít hơn không hiển thị ^ M, nhưng cho phép màu sắc và less -Rkhông:

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

Khắc phục được hiển thị bằng cách sử dụng đường ống để tách \ r (^ M) khỏi đầu ra:

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

Một cách thay thế không khôn ngoan là sử dụng less -r, bởi vì nó sẽ đi qua tất cả các mã kiểm soát, không chỉ các mã màu.

Nếu bạn muốn chỉnh sửa trực tiếp tệp cấu hình git của mình, đây là mục để cập nhật / thêm:

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

Tôi đã gặp vấn đề này trong một repo trong đó một số tệp có \r\nkết thúc dòng và một số có \nkết thúc dòng (tôi không biết nếu điều đó có liên quan); khác biệt trước đây cho thấy ^Mtrong các dòng sửa đổi (đó là, các +dòng). core.autocrlfđã được đặt thành true. Chạy git config core.pager "tr -d '\r' | less -REX"đã thoát khỏi pesky ^Ms. Cảm ơn!
labreuer

5
Cám ơn vì cái này. Đây là câu trả lời duy nhất nếu bạn phải làm việc với các kết thúc dòng khác nhau trong (các) repo của mình - ví dụ: bạn sử dụng thanh toán theo nguyên trạng, cam kết nguyên trạng.
Mike

git diff -blà những gì tôi đang tìm kiếm, nhưng tôi đánh giá cao sự giải thích kỹ lưỡng.
Martin Burch

Đây là câu trả lời! Cảm ơn bạn. cờ -b không làm việc cho tôi.
Chris

Đúng! Trong tất cả các câu trả lời cho câu hỏi này, sửa đổi phần git "config" của tệp [core]bằng cách thêm pager = tr -d '\\r' | less -REXlà câu trả lời duy nhất phù hợp với tôi. Cảm ơn bạn!
Rashiki

13

Tôi đã vật lộn với vấn đề này trong một thời gian dài. Cho đến nay, giải pháp đơn giản nhất là không lo lắng về các ký tự ^ M và chỉ cần sử dụng một công cụ tìm khác biệt có thể xử lý chúng.

Thay vì gõ:

git diff <commitHash> <filename>

thử:

git difftool <commitHash> <filename>

1
Cảm ơn! Ngoài ra, tôi chỉ chạy "git Difftool" và về cơ bản nó đã so sánh tất cả các tệp đã thay đổi trong một vòng lặp
Bhanuprakash D


2

Theo ghi nhận của VonC, điều này đã được đưa vào git 2.16+. Thật không may, tên của tùy chọn ( --ignore-cr-at-eol) khác với tên được sử dụng bởi GNU diff mà tôi đã sử dụng ( --strip-trailing-cr).

Khi tôi phải đối mặt với vấn đề này, giải pháp của tôi là gọi GNU diff thay vì diff được tích hợp sẵn của git, bởi vì git của tôi cũ hơn 2,16. Tôi đã làm điều đó bằng cách sử dụng dòng lệnh này:

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

Điều đó cho phép sử dụng --strip-trailing-crvà bất kỳ tùy chọn khác GNU.

Cũng có cách khác:

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

nhưng nó không sử dụng các thiết lập máy nhắn tin được cấu hình, đó là lý do tại sao tôi thích cái trước.


Thay thế thú vị cho câu trả lời của tôi. Nâng cao.
VonC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.