Git'i bilgisayarımıza kurduk ve kullanmaya başladık. Daha sonra hiç karşılaşmadığımız bir hata ile karşılaştık ve adına da git satır sonu karakteri sorunu deniliyormuş!
Pek çok geliştirici Git'i kendi bilgisayarına kurduktan sonra auto crlf ayarını yapmaz. Bu normaldir çünkü böyle bir ihtiyaç yoktur. Özellikle tek başına çalışıyorsa. Hatta ekip halinde bile bu sorun olmayabilir; tüm ekip aynı işletim sistemini kullanıyor ise.
Görünmez Karakterlerin Savaşı
Yazıyı hazırlarken bu benzetme geldi aklıma. Biz kodumuzu yazıyoruz ama işletim sistemi o satırı sonlandırmak için görünmez karakterler kullanıyor.
- Windows satırları sonlandırmak için hem Satır Başı (Carriage Return) hem de Satır Besleme (Line Feed) yani crlf kullanır. Bildiğimiz \r\n
- Linux/Unix tabanlı sistemler ise sadece Satır Besleme (Line Feed) kullanır. Bildiğimiz \n
Kısa Bir Nostalji
Bu ayrım aslında eski daktilolardan geliyor.
- CR (Carriage Return): Yazma kafasını satırın başına döndürür.
- LF (Line Feed): Kağıdı bir satır yukarı kaydırır.
Windows bu iki adımı da ayrı ayrı simüle etmeye devam ederken, Unix dünyası "satır bittiyse zaten başa döneceğiz" diyerek sadece LF'yi yeterli görmüştür.
Git Neden Tüm Dosyayı Değişmiş Gibi Gösterir?
Git dosyaları byte byte takip eder. Windows bir dosyayı kaydettiğinde her satırın sonuna \r\n yazar. macOS/Linux'ta ise sadece \n yazılır. İkisi aynı yazıdır hatta görünmez ama byte seviyesinde farklıdır.
Git bu farkı görünce "bu dosya değişmiş" der. Halbuki biz hiçbir şeye dokunmadık. Ama bir VCS (Version Control System) olan Git'e göre her satır değişmiştir. Diff olarak görüntüledik ve 200 satır kırmızı-yeşil. Stajyerler için ilginç bir sürpriz. Git bu hatayı bazen "LF will be replaced by CRLF" veya "CRLF will be replaced by LF" uyarısı olarak gösterir. Bazı geliştiriciler bu problemi "Git line ending warning" olarak bilir.
Bu hata nasıl görünür?
Git genellikle aşağıdaki uyarılardan birini gösterir:
warning: LF will be replaced by CRLF
warning: CRLF will be replaced by LF
Bu uyarı satır sonu karakterlerinin işletim sistemleri arasında farklı olduğunu gösterir.
Örnek Senaryo
- 1- Veli dosyayı Windows'ta kaydetti (satır sonları daktilo \r\n)
- 2- Ayşe aynı dosyayı macOS'te açtı tek harf değiştirdi ve kaydetti (artık satır sonları \n).
- 3- Git bu durumda tüm dosyayı değişmiş görür. Kod değişmese bile her satır farklı bir byte dizisi. Stajyer çocuk şok :)
Git CRLF sorunu nedir ve nasıl çözülür?
İki farklı çözümü vardır ve çok basittir. core.autocrlf ayarı ve gitattributes ayarı ile.
A) Git core.autocrlf Ayarı ile Çözüm
Eğer Windows kullanıyorsak git config --global core.autocrlf true komutunu kullanırız. Peki bu kod ne yapar?
- Repoya yazarken \r\n -> \n olarak sakla
- Dosyayı çıkarırken \n -> \r\n Windows'a uygun ver
Yani Windows her zaman \r\n görür ama repoda her zaman \n olarak saklanır.
Linux/macOS kullanıyorsak git config --global core.autocrlf input
- Repoya yazarken \r\n -> \n olarak sakla
- Dosyayı çıkarırken dokunma
input denmesinin sebebi sadece girişte dönüştür (temizle) çıkışta karışma. Üçüncü bir seçeneğimiz daha var. Eğer gerçekten dönüşüm istemiyorsak git config --global core.autocrlf false komutunu kullanabiliriz fakat ekip uyumuna dikkat edilmesi gerekir.
B) .gitattributes ile Kalıcı Çözüm
Projemizin kök dizininde (aslında Git'in bulunduğu klasör) .gitattributes adında dosya oluşturup içine şunu yazıp commit etmek çoğu durumda yeterlidir. * text=auto bu kod Git'e şunu söyler "Git'e tüm dosyaları text olarak iste ve satır sonlarını normalize et. Repoda her zaman \n saklanır ama kendi bilgisayarımızda işletim sistemine göre uygun dönüştür".
Eğer bize daha spesifik kurallar gerekiyorsa, örneğin gerçekten \r\n veya \n olarak olması gereken dosyalar varsa *.bat text eol=crlf (bat dosyaları Windows'ta çalıştığından \r\n ister), *.sh text eol=lf (sh dosyaları Linux ve Mac'te çalıştığından \n ister) bunun gibi spesifik ayarlar yapmak da mümkündür. Geri kalan her şey * text=auto kuralına girer.
Mevcut Git CRLF ayarını nasıl kontrol ederiz?
git config --global core.autocrlf
Özetle, bu iki yöntem arasındaki fark core.autocrlf kullanıcının bilgisayarında sadece onun için uygulanır. Bu ekibe yeni gelen birinin de aynı ayarları yapmasını gerektirir. .gitattributes yöntemi ile proje bazında ayardır. O repoyu klonlayan herkes o ayara tabi olur.