1 puan yazan GN⁺ 9 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Gradle ekibi, Git uyumlu VCS olan Jujutsu(jj)’yi günlük geliştirme süreçlerine dahil etmeye çalıştı; ancak Windows için gradlew.bat dosyasındaki satır sonu işleme nedeniyle benimsemeyi erteledi
  • Temel sorun, jj’nin .gitattributes içindeki dosya bazlı EOL kurallarını okuyamaması ve bu yüzden *.bat text eol=crlf kuralını uygulayamaması
  • Git, gradlew.bat dosyasını depoda LF’ye normalize edip çalışma dizinine CRLF olarak checkout ederken, jj bunu değişiklik olarak algılıyor ve sürekli phantom modification üretiyor
  • gradlew.bat dosyasını CRLF haliyle commit edip *.bat -text olarak değiştirmek bir geçici çözüm olabilir; ancak bir editör dosyayı LF’ye çevirirse Git bunu otomatik olarak düzeltmediği için Windows’ta çalışma kararlılığı riske girebilir
  • Gradle ekibi şimdilik birden fazla çalışma dizinini git worktree ile yönetecek; jj’de eol desteği uygulanınca tekrar denemeyi planlıyor

Benimsemeyi engelleyen gerçek neden: gradlew.bat ve .gitattributes

  • Jujutsu(jj), Git backend’i kullanırken commit’leri ve dosyaları Git’te saklayan, mevcut Git depolarıyla birlikte çalışabilen Git uyumlu bir sürüm kontrol sistemidir
  • jj, staging alanını ortadan kaldırır ve çalışma kopyasını sürekli güncellenen gerçek bir commit olarak temsil eder
  • Commit düzenleme veya yeniden sıralama sonrasında takip eden commit’leri otomatik olarak rebase eder; çakışmalar işi durdurmak yerine kayıtta tutulabilir ve çalışma günlüğünden geri alma yapılabilir
  • Bir Gradle mühendisinin git yerine jj kullanma girişimi, jj’nin modelinden değil, Gradle projesinin diskte nasıl durduğuna dair küçük bir ayrıntıdan dolayı engellendi

Windows’ta gradlew.bat CRLF’ye ihtiyaç duyuyor

  • Tipik bir Gradle deposunda Gradle Wrapper ile birlikte gradlew.bat bulunur
  • gradlew.bat, label ve goto kullanır; cmd.exe, yalnızca LF satır sonlarına sahip batch dosyalarını hatalı işleyebilir
  • Windows’ta kararlı şekilde çalışması için gradlew.bat dosyasının CRLF olarak checkout edilmesi gerekir
  • Gradle projeleri bu gereksinimi .gitattributes ile zorunlu kılar
*.bat text eol=crlf
  • Git’te bu davranış standart akıştır
    • Dosya indekste normalize edilmiş biçimde saklanır
    • eol=crlf özelliği, checkout sırasında çalışma kopyasında CRLF’yi somutlaştırır
    • Düzenlenen içerik tekrar kaydedilirken normalize edilir

jj’nin .gitattributes desteği olmamasının yarattığı phantom diff

  • jj, .gitattributes dosyasını okumadığı için dosya bazlı satır sonu kurallarını uygulayamaz
  • İlgili özellik, eski bir issue olan jj-vcs/jj#53 üzerinden takip ediliyor; en azından eol özelliği desteği tartışılıyor
  • Şu anda jj içinde kullanılabilen araç yalnızca global ayar olan working-copy.eol-conversion
    • Git’teki core.autocrlf gibi tüm dosyalara topluca uygulanır
    • Yalnızca .bat dosyalarını ayrı olarak belirlemek mümkün değildir
  • Colocated repo’da sorun hemen görünür hale gelir
    • Git, gradlew.bat dosyasını LF olarak saklar ve CRLF olarak checkout eder
    • jj, bu özelliğe uymadığı için diskteki CRLF’yi Git’teki LF blob’a göre değişiklik olarak kaydeder
    • Etkilenen Gradle projelerinde gradlew.bat için sürekli sahte değişiklikler oluşur
  • Bu sorun yalnızca Gradle ekibine özgü bir örnek değil
    • Bir kullanıcı, altı haneli sayıda dosyada phantom change oluştuğu için jj kullanmaktan vazgeçti

Önerilen geçici çözümler ve sınırları

  • jj’nin yazarı issue’da non-colocated workspace’i bir yol olarak önerdi
    • Örnek: Git çalışma kopyasının dışında jj git init --git-repo=<path> kullanmak
  • Gradle mühendisi bu yöntemin de sorunu çözmediğini düşünüyor
    • jj, saklanan LF blob’dan gradlew.bat dosyasını somutlaştırırsa dosya diske LF olarak iner
    • LF biçimindeki gradlew.bat Windows’ta çalışmaz
  • Global ayar working-copy.eol-conversion = input-output ile CRLF zorunlu kılınabilir
    • Ancak bu, tüm metin dosyalarını checkout sırasında CRLF olarak yeniden yazdığı için ayrı bir sorun yaratır

Çalışan ama kırılgan çözüm

  • Gerçekten çalışan yöntem, gradlew.bat dosyasını depoya CRLF haliyle commit etmek ve normalizasyonu durdurmaktır
  • Kural şöyle değişir
    • Eski: *.bat text eol=crlf
    • Yeni: *.bat -text
  • Böylece Git ve jj, hem saklanan ağaçta hem de çalışma kopyasında CRLF konusunda anlaşır
    • Dönüştürme ortadan kalkar
    • Phantom diff de kaybolur
    • Windows’ta çalışma da korunur
  • Buna karşılık *.bat -text, text eol=crlf kuralının sunduğu otomatik düzeltmeden vazgeçmek anlamına gelir
    • Önceden yanlışlıkla LF gelse bile commit sırasında sessizce yeniden normalize edilirdi
    • Artık LF olduğu gibi kalabilir ve gradlew.bat Windows’ta sessizce bozulabilir
  • Bu dönüşümün yalnızca bir kez yapılması gerekir ve hatalı düzenlemeler genellikle review sırasında yakalanabilir
  • Yine de Gradle ekibi, tüm Gradle projelerinin CRLF’yi doğrudan commit edeceği ve hiçbir editörün bunu sessizce değiştirmeyeceği varsayımını ekosistem genelinde riske atmanın zor olduğuna karar verdi

Şimdilik korunan alternatif: git worktree

  • jj’nin workspace’i, tek bir depoyu paylaşan birden fazla çalışma dizini sunarak uzun CI çalışmaları veya devam eden değişikliklerin sonraki işleri engellememesini sağlar
  • Gradle ekibi aynı ihtiyacı zaten git worktree ile yeterince karşılıyor
git worktree add ../gradle-feature-x feature-x
git worktree add ../gradle-hotfix    hotfix-7.6
  • Bu yöntem iki checkout ve tek bir object store kullanır
  • Stash veya ikinci bir clone olmadan paralel işler ve uzun süre korunan main checkout’u birlikte yürütülebilir
  • Gradle ekibi bu kalıbı yıllardır kullanıyor

jj’yi yeniden değerlendirme olasılığı

  • Bu örnek, Gradle projesinde jj’nin kendisi hakkında nihai bir karar değil
  • Yalnızca jj’nin operation log özelliği bile daha derin incelemeye değer
  • eol desteği çözülebilir bir sorun olarak ele alınıyor; issue’da gix-filter üzerinden uygulama tartışmaları da var
  • Bu destek geldiğinde Gradle ekibi yeniden denemeyi planlıyor
  • O zamana kadar gradlew.bat nedeniyle Git kullanılmaya devam edecek ve gerekli rolü git worktree üstlenecek

1 yorum

 
GN⁺ 9 시간 전
Lobste.rs yorumları
  • Git’in autocrlf ayarı ve ardından gelen .gitattributes ayarının en başından beri bir hata olduğunu ve bundan sonra da öyle kalacağını düşünüyorum
    Bir sürüm kontrol sistemi, depodaki dosyaları diskteki dosyalardan farklı şekilde saklamamalı
    Bir dosya biçimini zorunlu kılmak istiyorsanız bu linter’ların, commit hook’larının ve merge hook’larının işi; sürüm kontrol sisteminin rolü değil

    • En başından beri hata olduğunu düşünen tarafa yakınım, ama artık bunun açıkça hata ilan edilmesi ve özellikle core.{eol, safecrlf, autocrlf} ayarlarının kullanımdan kaldırılacaklar arasına alınması gerektiğini düşünüyorum
      Satır sonu dönüşümünün eklenmesinin tek nedeni Windows’tu; yalnızca ␍ kullanımı Git’ten önce zaten ölmüştü ve Windows dışında herkes yalnızca ␊ üzerinde karar kılmıştı
      Artık ␍␊’ye gerçekten önem veren başlıca şeyin batch dosyaları olduğunu sanıyorum
      Tüm diller ␍␊’yi desteklemeye çalışıyor, ama artık bunu gerektiren ya da üreten neredeyse hiçbir şey yok
      Notepad hâlâ varsayılan olarak ␍␊ kullanıyorsa ya da yalnızca bunu destekliyorsa, Notepad kullanan kişi bunun sonuçlarına katlanmalı
      Windows uyumluluğunda daha ilginç alan dosya modları
      Git Unix modlarını aldı ve bunun izleri kaldı; bu yüzden Windows’ta çalışırken istemeden mod hataları oluşabiliyor
    • Ben tam tersine, sürüm kontrolünün bu tür işleri daha az değil, daha fazla yapması gerektiğini hissediyorum
      Araçlar yeterince iyi hâle gelip checkout sırasında otomatik olarak boşluk kullanır ya da birinin çok inatla savunduğu garip derecede belirli boşluk sayısına uydurursa, tab ve boşluk tartışmasını bırakabiliriz
      Hatta daha ileri gidip sürüm kontrol sistemlerinin ham metin yerine soyut sözdizim ağacı (AST) saklaması gerektiği bile söylenebilir
      Şu anda ikna etmesi zor olurdu, ama bunun çok doğal geldiği başka bir zaman çizgisini ya da geleceği hayal etmek mümkün
  • .bat dosyasının Windows değilse nerede çalıştırılacağını bilmiyorum
    Farklı bir davranışın az da olsa arzu edilir olduğu bir yer var mı, o da şüpheli

  • Bir dosyayı ihtiyaç duyduğu satır sonu biçimiyle commit’lememek gerektiği argümanı beni ikna etmiyor
    Ana fikir “birisi satır sonlarını bozup commit’ler ve kod incelemesinden geçerek bozuk bir script içeri girebilir” gibi görünüyor
    Bunların hepsi doğru, ama zaten CI lint kontrolleri bunun için yok mu?
    İlgili dosyada CRLF olmayan satır sonlarını tarayıp bulunursa CI’ı başarısız yaparsanız, satır sonlarını bozan değişiklik pull request aşamasını geçemez

    • Bu yazının amacının yalnızca Gradle’daki jj’yi ele almak değil, JVM ekosisteminde jj kullanmak isteyen herkes ve her proje için bu sorunun ilgili olduğunu göstermek olduğunu düşünüyorum
      “Sadece CI ekleyin” yanıtı yeterli değil
      İlgili proje nispeten acemi birinin yaptığı Minecraft modu olabilir ve içlerinden herhangi biri gradle.bat dosyasını bozup bunu fark etmeyebilir
      Benim de acemilerin başlaması için CLI Git’ten çok daha iyi olduğunu söyleyerek jj’yi alternatif olarak tanıtmış olma sorumluluğum var
  • gradlew.batten gradlew.ps1e geçmek, yani cmd.exe/batch dosyalarından PowerShell’e geçmek bir seçenek olabilir mi?

    • Gradle’a dahil olmadım, ama birkaç yıl önce Leiningen’de bunu denemiştim ve o zamanlar tamamen karmaşaydı, hiç pratik değildi
      Şimdi BELKİ Windows kurulu tabanının %90’ında yeterince güncel PowerShell bulunduğunu varsayabiliriz
      Ama varsayılan çalıştırma izinlerini yükseltmek gerekebildiği durumlar hâlâ var ve kurumsal ortamlarda kilitli olabilir
      PowerShell’i ne kadar kullandınız bilmiyorum ama “bash var, o hâlde .sh dosyasını çalıştırırsınız” gibi bir his değildi
      Windows sürümlerine göre özellik setleri değiştiğinden, ksh ile bash4ü karşılaştırıyormuşsunuz gibi hissettiriyordu