git-diff untuk mengabaikan ^ M

474

Dalam proyek di mana beberapa file berisi ^ M sebagai pemisah baris baru. Diffing file-file ini tampaknya tidak mungkin, karena git-diff melihatnya sebagai seluruh file hanya satu baris.

Bagaimana seseorang berbeda dengan versi sebelumnya?

Apakah ada opsi seperti "memperlakukan ^ M sebagai baris baru saat berbeda"?

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>

MEMPERBARUI:

sekarang saya telah menulis skrip Ruby yang memeriksa 10 revisi terbaru dan mengonversi CR ke 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
sumber
7
Anda mungkin ingin git diff -b- Saya menunjukkan ini di stackoverflow.com/a/46265081/58794
Jason Pyeron
6
Dengan Git 2.16 (Q1 2018), Anda akan memilikinya git diff --ignore-cr-at-eol. Lihat jawaban saya di bawah ini .
VonC
7
@JasonPyeron dan untuk Googlers masa depan: Saya harus mencari yang git diff -bidentik dengan git diff --ignore-space-change.
Gogowitsch

Jawaban:

392

GitHub menyarankan agar Anda hanya menggunakan \ n sebagai karakter baris baru dalam repo yang ditangani git. Ada opsi untuk melakukan konversi otomatis:

$ git config --global core.autocrlf true

Tentu saja, ini dikatakan untuk mengkonversi crlf ke lf, sementara Anda ingin mengonversi crlf ke lf. Saya harap ini masih berfungsi ...

Dan kemudian konversikan file Anda:

# 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 dijelaskan di halaman manual .

nes1983
sumber
1
Tidak, tentu saja tidak, setelah pengaturan itu ada, itu akan diam-diam dikonversi pada komit. Jika semuanya bekerja dengan cara yang saya pikir tidak, yang ...
nes1983
1
Masalahnya adalah bahwa saya sudah memiliki beberapa file dalam repositori yang memiliki akhiran CRLF dan yang lainnya tidak. Saya menduga bahwa Adobe Flash menambahkan CRLF meskipun saya menggunakan versi Mac. Saya perlu membandingkan dengan revisi yang lebih lama dari file-file ini. Mengonversi ujung garis yang dimulai dari sekarang tidak menyelesaikan masalah dengan revisi yang lebih lama: - /
neoneye
65
Anda tidak bekerja dengan file CRLF di sini, setidaknya tidak dalam contoh yang Anda posting. Itu file mac gaya lama (hanya menggunakan \ r untuk EOL). Itu sebabnya perbedaan ditampilkan pada satu baris. Sebuah file yang menggunakan dos EOL akan menunjukkan setiap baris dengan jelas dengan trailing ^ M, yang bisa Anda sampaikan git config core.whitespace cr-at-eol.
jamessan
12
Saya mencoba ini, tapi saya terus mendapatkan warning: LF will be replaced by CRLFbukan warning: CRLF will be replaced by LF, dan aku di Linux. Ada yang tahu kenapa? Saya ingin semua diakhiri dengan LF, bukan CRLF!
trusktr
5
@trusktr, hal yang sama terjadi pada saya. Di linux, dengan CRLF yang tidak disengaja, gunakan git config --global core.autocrlf input, lakukan langkah-langkah dalam jawaban ini (rm, tambah, komit), dan Anda akan mendapatkannya warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Hapus file (karena mereka memiliki CRLF asli, salah) dan checkout lagi dari komit terakhir "Perbaiki CRLF".
jmmut
370

Berkembang di Windows, saya mengalami masalah ini saat menggunakan git tfs. Saya memecahkannya dengan cara ini:

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

Ini pada dasarnya memberitahu Git bahwa CR end-of-line bukan kesalahan. Akibatnya, mereka mengganggu ^Mkarakter tidak lagi muncul di akhir baris dalam git diff, git showdll

Tampaknya meninggalkan pengaturan lain apa adanya; misalnya, spasi tambahan di akhir baris masih menunjukkan kesalahan (disorot dengan warna merah) di diff.

(Jawaban lain menyinggung ini, tetapi di atas adalah persis bagaimana mengatur pengaturan. Untuk mengatur pengaturan hanya satu proyek, abaikan --global.)

EDIT :

Setelah banyak kesusahan akhir baris, saya memiliki keberuntungan terbaik, ketika bekerja pada tim .NET, dengan pengaturan ini:

  • TIDAK ada pengaturan core.eol
  • TIDAK ada pengaturan core.whitespace
  • TIDAK ADA pengaturan core.autocrlf
  • Saat menjalankan installer Git untuk Windows, Anda akan mendapatkan tiga opsi ini:
    • Checkout bergaya Windows, komit ujung garis gaya Unix <- pilih yang ini
    • Checkout apa adanya, komit akhiran garis gaya Unix
    • Periksa apa adanya, komit apa adanya

Jika Anda perlu menggunakan pengaturan spasi, Anda mungkin harus mengaktifkannya hanya berdasarkan per proyek jika Anda perlu berinteraksi dengan TFS. Hapus saja --global:

git config core.whitespace cr-at-eol

Jika Anda perlu menghapus beberapa pengaturan inti. *, Cara termudah adalah dengan menjalankan perintah ini:

git config --global -e

Ini membuka file .gitconfig global Anda dalam editor teks, dan Anda dapat dengan mudah menghapus baris yang ingin Anda hapus. (Atau Anda dapat menempatkan '#' di depan mereka untuk berkomentar.)

Ryan Lundy
sumber
30
Bagi mereka yang menemukan ini sekarang, perlu dicatat bahwa Checkout Windows-style, melakukan auto-set core.autocrlftrue
K. Carpenter
14
Perhatikan bahwa saluran git config --global core.whitespace cr-at-eolakan mematikan pengaturan lain yang default. Ada tiga default: blank-at-eol, blank-at-eof dan space-before-tab. Jadi untuk mengaktifkan cr-at-eol sambil menjaga yang lain Anda harus menggunakan git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax
2
Untuk proyek saya (itu keluar pada Windows dan saya melihatnya di Linux), cr-at-eolmenyingkirkan ^Mdi akhir baris dengan git diffbenar, tetapi GIT masih menunjukkan garis-garis itu berbeda, meskipun garis berakhir adalah satu-satunya perbedaan.
Jānis Elmeris
SourceInsight terus mendorong karakter ^ M, dan git masih menunjukkan perbedaan pada akhir baris. @ Perintah Zitrax adalah jawaban yang tepat untuk kasus saya, git diff menunjukkan hasil yang bagus dan bersih.
Lê Quang Duy
3
Saya pikir git membutuhkan sedikit lebih banyak kompleksitas, beberapa pengaturan yang lebih saling bertentangan untuk end of line. Saya pikir git harus lebih peduli tentang ruang putih saya. Misalnya melempar kesalahan fatal yang tidak terkait dan meninggalkan repositori dalam keadaan korup ketika menemui ujung garis Mac pada mesin Windows (tetapi bukan Linux). Maksud saya, mengapa saya menggunakan VCS yang akan memusingkan bisnisnya dan biarkan saya menggunakan ujung jalur yang saya inginkan? Saya melihat mereka sedang mencoba, tetapi mereka harus membuang setengah lusin perilaku yang berakhir garis, untuk memecahkan masalah yang tidak ada. Mereka hampir sampai! Teruskan.
Rolf
125

Coba git diff --ignore-space-at-eol, atau git diff --ignore-space-change, atau git diff --ignore-all-space.

Jakub Narębski
sumber
22
Tidak ada yang benar-benar memengaruhi karakter yang mengidentifikasi baris baru.
nes1983
4
Saya juga mencoba dengan "-w" tetapi tidak berhasil, masih memperlakukannya sebagai satu baris. Proyek selanjutnya saya harus ingat untuk tidak pernah mendapatkan CR ke dalam kode sumber.
neoneye
3
Hanya ingat git config --global core.autocrlf benar, atau bug orang-orang git sampai mereka menjadikannya default :)
nes1983
10
Ini menyelesaikan masalah saya tanpa harus mengubah autocrlfpengaturan saya . Terima kasih!
nneonneo
11
bendera ini tidak berpengaruh bagi saya ... masih menunjukkan ^ M sebagai diffs
Magnus
103

Lihat juga:

core.whitespace = cr-at-eol

atau yang setara,

[core]
    whitespace = cr-at-eol

di mana whitespacedidahului oleh karakter tab .

Vladimir Panteleev
sumber
4
Yap, ini membuat alat git diff (juga digunakan dalam git show) berhenti menggangguku tentang ^Ms pada baris yang diubah! :)
Rijk
2
untuk alasan apa pun ini tidak berhasil untuk saya. Mencoba keduanya dengan tanda = dan tanpa =. git diffmasih menunjukkan ^ M karakter.
Dennis
6
Dua cara untuk melakukan ini: satu, tambahkan baris di atas kata demi kata ke .gitconfig Anda dalam .git / config, atau di ~ / .gitconfig; dua, git config --global core.whitespace cr-at-eol(di mana - global adalah opsional jika Anda hanya ingin di repo Anda berada)
K. Carpenter
Ini bekerja untuk saya di Windows 7, meskipun saya hanya meletakkannya di bawah [core]sehingga saya dapat mengganti core.awalan dengan karakter TAB.
Rufflewind
Pertanyaan ini adalah di atas bagaimana menyembunyikan ^Mdi git diff, bukan tentang bagaimana untuk tidak dimasukkan ke dalam ^ M di tempat pertama. Itu berarti jawaban perubahan yang diterima core.autocrlfbukan yang terbaik karena secara diam-diam mengubah file tanpa konfirmasi pengguna.
deddebme
45

Mengapa Anda mendapatkan ini ^Mdi Anda git diff?

Dalam kasus saya, saya sedang mengerjakan proyek yang dikembangkan di Windows dan saya menggunakan OS X. Ketika saya mengubah beberapa kode, saya melihat ^Mdi akhir baris yang saya tambahkan git diff. Saya pikir ^Mitu muncul karena mereka akhiran baris yang berbeda dari sisa file. Karena sisa file dikembangkan di Windows menggunakan CRujung baris, dan di OS X menggunakan LFujung garis.

Rupanya, pengembang Windows tidak menggunakan opsi " Checkout Windows-style, komit ujung garis Unix-style " selama instalasi Git.

Jadi apa yang harus kita lakukan?

Anda dapat meminta pengguna Windows menginstal ulang git dan menggunakan opsi " Checkout Windows-style, commit Unix-style endings ". Inilah yang saya inginkan, karena saya melihat Windows sebagai pengecualian dalam karakter akhir barisnya dan Windows memperbaiki masalahnya sendiri dengan cara ini.

Jika Anda memilih opsi ini, Anda harus memperbaiki file saat ini (karena mereka masih menggunakan CRakhiran baris). Saya melakukan ini dengan mengikuti langkah-langkah ini:

  1. Hapus semua file dari repositori, tetapi tidak dari sistem file Anda.

    git rm --cached -r .
    
  2. Tambahkan .gitattributesfile yang memberlakukan file tertentu untuk menggunakan LFujung baris sebagai. Masukkan ini ke dalam file:

    *.ext text eol=crlf
    

    Ganti .extdengan ekstensi file yang ingin Anda cocokkan.

  3. Tambahkan semua file lagi.

    git add .
    

    Ini akan menampilkan pesan seperti ini:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Anda dapat menghapus .gitattributesfile kecuali jika Anda memiliki pengguna Windows yang keras kepala yang tidak ingin menggunakan opsi " Checkout Windows-style, commit Unix-style endings ".

  5. Komit dan dorong semuanya.

  6. Hapus dan periksa file yang berlaku di semua sistem tempat mereka digunakan. Pada sistem Windows, pastikan mereka sekarang menggunakan opsi " Checkout Windows-style, commit Unix-style endings ". Anda juga harus melakukan ini pada sistem di mana Anda menjalankan tugas-tugas ini karena ketika Anda menambahkan file git berkata:

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

    Anda dapat melakukan sesuatu seperti ini untuk menghapus file:

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

    Dan kemudian ini untuk mendapatkan mereka kembali dengan ujung garis yang benar:

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

    Tentu saja mengganti .extdengan ekstensi yang Anda inginkan.

Sekarang proyek Anda hanya menggunakan LFkarakter untuk akhiran baris, dan CRkarakter jahat tidak akan pernah kembali :).

Pilihan lainnya adalah untuk menegakkan akhiran garis gaya windows. Anda juga dapat menggunakan .gitattributesfile untuk ini.

Info lebih lanjut: https://help.github.com/articles/dealing-with-line-endings/#platform-all

gitaarik
sumber
4
Untuk memperbaiki semua akhiran baris dalam file tertentu, jika menggunakan Sublime Text, Anda dapat pergi ke View-> Line Endingsdan klik Unix.
Topher Hunt
Apa sebenarnya artinya ini ^M? Apakah ini baris baru windows atau linux? Atau itu hanya baris "berbeda" dibandingkan dengan baris baru lainnya dalam file?
buhtz
Bagus, saya pikir itu hanya baris "berbeda" (berbeda dari kebanyakan yang lain)
gitaarik
-1 sebagai menginstal ulang git untuk menyelesaikannya git config --global core.autocrlf trueadalah berlebihan, dan anti-Windows / anti- CRkampanye tampaknya bersinggungan dengan pertanyaan.
RJFalconer
41

Apakah ada opsi seperti "memperlakukan ^ M sebagai baris baru saat berbeda"?

Akan ada satu dengan Git 2.16 (Q1 2018), ketika keluarga " diff" perintah belajar untuk mengabaikan perbedaan dalam carriage return di akhir baris.

Lihat komit e9282f0 (26 Okt 2017) oleh Junio ​​C Hamano ( gitster) .
Dibantu-oleh: Johannes Schindelin ( dscho) .
(Digabung oleh Junio ​​C Hamano - gitster- dalam komit 10f65c2 , 27 Nov 2017)

beda: --ignore-cr-at-eol

Opsi baru --ignore-cr-at-eolmemberi tahu mesin berbeda untuk memperlakukan carriage-return di akhir baris (lengkap) seolah-olah tidak ada.

Sama seperti --ignore-*opsi " " lain untuk mengabaikan berbagai macam perbedaan spasi putih, ini akan membantu meninjau perubahan nyata yang Anda buat tanpa terganggu oleh CRLF<->LFkonversi palsu yang dibuat oleh program editor Anda.

VONC
sumber
@kaartic Terima kasih telah mengedit jawaban dan merujuk komit yang tepat!
VonC
3
Sementara itu umumnya praktik yang baik untuk ditetapkan git config --global core.autocrlf trueseperti dalam jawaban yang diterima, ini menjawab pertanyaan OP lebih langsung: 'Apakah ada opsi seperti "memperlakukan ^ M sebagai baris baru ketika berbeda"?'
drkvogel
1
Pada Git 2.20 ini tidak menyembunyikan ^ M
user1944491
@ user1944491 Saya tidak melihat adanya regresi, berarti masih mengabaikan eol ketika berbeda dengan opsi ini di Git 2.26.
VonC
@VonC Menggunakan argumen ini dalam perintah git diff tidak berfungsi. Juga tidak menetapkan nilai core.whitespace saya git version 2.20.1 (Apple Git-117)tetapi menambahkan jawaban core.pager Jason Pyeron memperbaikinya. YMMV jelas.
user1944491
26

TL; DR

Ubah core.pagerke "tr -d '\r' | less -REX", bukan kode sumber

Ini sebabnya

Orang-orang sial yang ditampilkan adalah artefak pewarnaan dan pager. masukkan deskripsi gambar di sini Ini disebabkan oleh less -R, opsi pager git default. (Pager default git adalah less -REX)

Hal pertama yang perlu diperhatikan adalah bahwa git diff -btidak akan menampilkan perubahan dalam ruang putih (mis. \ R \ n vs \ n)

mendirikan:

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

Tes cepat untuk membuat file unix dan mengubah akhir baris tidak akan menunjukkan perubahan dengan 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

Kami mencatat bahwa memaksa pipa lebih sedikit tidak menunjukkan ^ M, tetapi memungkinkan warna dan less -Rtidak:

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

Perbaikan ditunjukkan dengan menggunakan pipa untuk menghapus \ r (^ M) dari output:

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

Alternatif yang tidak bijaksana adalah menggunakan less -r, karena akan melewati semua kode kontrol, bukan hanya kode warna.

Jika Anda ingin mengedit file konfigurasi git Anda secara langsung, ini adalah entri untuk memperbarui / menambahkan:

[core]
        pager = tr -d '\\r' | less -REX
Jason Pyeron
sumber
Saya punya masalah ini dalam repo di mana beberapa file memiliki \r\nakhiran baris dan beberapa \nakhiran baris (saya tidak tahu apakah itu relevan); Perbedaan dari yang pertama menunjukkan ^Mdalam garis yang dimodifikasi (yaitu, +garis). core.autocrlfdiatur ke true. Berlari git config core.pager "tr -d '\r' | less -REX"menyingkirkan sial ^M. Terima kasih!
labreuer
5
Terima kasih untuk ini. Ini adalah satu-satunya jawaban jika Anda harus bekerja dengan akhiran baris yang berbeda dalam repo Anda - mis. Anda menggunakan checkout apa adanya, komit apa adanya, dengan sengaja.
Mike
git diff -badalah apa yang saya cari, tetapi saya sangat menghargai penjelasan yang menyeluruh.
Martin Burch
Ini jawabannya! Terima kasih. bendera -b tidak bekerja untuk saya.
Chris
Iya! Dari semua jawaban untuk pertanyaan ini, memodifikasi bagian file git "config" [core]dengan menambahkan pager = tr -d '\\r' | less -REXadalah satu-satunya jawaban yang bekerja untuk saya. Terima kasih!
Rashiki
13

Saya berjuang dengan masalah ini untuk waktu yang lama. Sejauh ini solusi termudah adalah tidak perlu khawatir tentang karakter ^ M dan hanya menggunakan alat diff visual yang dapat menangani mereka.

Alih-alih mengetik:

git diff <commitHash> <filename>

mencoba:

git difftool <commitHash> <filename>
Ian Wojtowicz
sumber
1
Terima kasih! Juga saya hanya menjalankan "git difftool" dan pada dasarnya membandingkan semua file yang diubah dalam satu lingkaran
Bhanuprakash D
2

Seperti dicatat oleh VonC, ini sudah termasuk dalam git 2.16+. Sayangnya, nama opsi ( --ignore-cr-at-eol) berbeda dari yang digunakan oleh GNU diff yang saya terbiasa ( --strip-trailing-cr).

Ketika saya dihadapkan dengan masalah ini, solusi saya adalah untuk memanggil GNU diff daripada built-in diff git, karena git saya lebih tua dari 2,16. Saya melakukannya menggunakan baris perintah ini:

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

Itu memungkinkan penggunaan --strip-trailing-crdan semua opsi GNU lainnya.

Ada juga cara lain ini:

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

tetapi tidak menggunakan pengaturan pager yang sudah dikonfigurasi, itulah sebabnya saya lebih suka yang pertama.

Pedro Gimeno
sumber
Alternatif menarik untuk jawaban saya. Terpilih.
VonC