1 poin oleh GN⁺ 9 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • Tim Gradle sempat ingin mengadopsi Jujutsu (jj), VCS yang kompatibel dengan Git, untuk pengembangan sehari-hari, tetapi menunda adopsinya karena penanganan line ending pada gradlew.bat di Windows
  • Masalah intinya adalah jj tidak bisa membaca aturan EOL per file di .gitattributes, sehingga tidak dapat menerapkan *.bat text eol=crlf
  • Git menormalkan gradlew.bat sebagai LF di repositori dan melakukan checkout sebagai CRLF di working directory, tetapi jj menganggap ini sebagai perubahan dan terus membuat phantom modification
  • Mem-commit gradlew.bat apa adanya dalam CRLF dan mengubahnya menjadi *.bat -text bisa menjadi jalan memutar, tetapi jika editor mengubahnya ke LF, Git tidak lagi memulihkannya secara otomatis sehingga keandalan eksekusi di Windows bisa terganggu
  • Untuk sementara, tim Gradle akan tetap mengelola beberapa working directory dengan git worktree, lalu mencoba lagi saat dukungan eol di jj sudah diimplementasikan

Penyebab sebenarnya yang menghalangi adopsi: gradlew.bat dan .gitattributes

  • Jujutsu (jj) adalah sistem kontrol versi yang kompatibel dengan Git yang, saat memakai backend Git, menyimpan commit dan file ke Git serta dapat bekerja berdampingan dengan repositori Git yang sudah ada
  • jj menghilangkan staging area dan merepresentasikan working copy sebagai commit nyata yang terus diperbarui
  • Setelah pengeditan atau penyusunan ulang commit, commit lanjutan otomatis di-rebase, konflik bisa disimpan dalam riwayat alih-alih menghentikan pekerjaan, dan perubahan juga bisa dibatalkan dari operation log
  • Upaya engineer Gradle untuk mengganti git dengan jj terhambat bukan oleh model jj, melainkan oleh detail kecil tentang bagaimana proyek Gradle ditempatkan di disk

gradlew.bat membutuhkan CRLF di Windows

  • Repositori Gradle pada umumnya menyertakan gradlew.bat bersama Gradle Wrapper
  • gradlew.bat memakai label dan goto, dan cmd.exe bisa salah menangani batch file yang hanya memakai line ending LF
  • Agar berjalan stabil di Windows, gradlew.bat harus di-checkout sebagai CRLF
  • Proyek Gradle memaksakan kebutuhan ini melalui .gitattributes
*.bat text eol=crlf
  • Di Git, perilaku ini adalah alur standar
    • File disimpan dalam bentuk yang sudah dinormalisasi di index
    • Atribut eol=crlf mewujudkan CRLF ke working copy saat checkout
    • Hasil edit kembali dinormalisasi saat disimpan lagi

Dukungan .gitattributes yang belum ada di jj memunculkan phantom diff

  • jj tidak membaca .gitattributes, sehingga tidak bisa menerapkan aturan line ending per file
  • Fitur terkait sedang dilacak di isu lama jj-vcs/jj#53, dan setidaknya dukungan untuk atribut eol sedang dibahas
  • Saat ini, satu-satunya mekanisme yang bisa dipakai di jj adalah konfigurasi global working-copy.eol-conversion
    • Mirip core.autocrlf di Git, tetapi diterapkan ke semua file sekaligus
    • Tidak bisa menetapkan hanya untuk file .bat
  • Pada colocated repo, masalahnya langsung terlihat
    • Git menyimpan gradlew.bat sebagai LF dan melakukan checkout sebagai CRLF
    • Karena jj tidak menghormati atribut tersebut, CRLF di disk dicatat sebagai perubahan dibanding blob LF di Git
    • Pada proyek Gradle yang terdampak, ini menimbulkan perubahan palsu yang terus-menerus pada gradlew.bat
  • Masalah ini bukan hanya terjadi pada tim Gradle
    • Seorang pengguna melaporkan phantom change pada ratusan ribu file dan akhirnya berhenti memakai jj

Jalan memutar yang diusulkan dan batasannya

  • Penulis jj mengusulkan non-colocated workspace sebagai salah satu pendekatan di isu tersebut
    • Contoh: memakai jj git init --git-repo=<path> dari luar working copy Git
  • Engineer Gradle menilai cara ini juga tidak menyelesaikan masalah
    • Saat jj mewujudkan gradlew.bat dari blob LF yang tersimpan, file itu akan turun ke disk sebagai LF
    • gradlew.bat dengan LF tidak bisa dijalankan di Windows
  • Konfigurasi global working-copy.eol-conversion = input-output memang bisa memaksa CRLF
    • Tetapi ini juga akan menulis ulang semua file teks menjadi CRLF saat checkout, sehingga memunculkan masalah lain

Solusi yang bekerja, tetapi rapuh

  • Cara yang benar-benar bekerja adalah mem-commit gradlew.bat ke repositori apa adanya dalam CRLF dan menghentikan normalisasi
  • Aturannya berubah seperti ini
    • Sebelumnya: *.bat text eol=crlf
    • Menjadi: *.bat -text
  • Dengan begitu, Git dan jj sama-sama sepakat memakai CRLF baik di stored tree maupun working copy
    • Tidak ada lagi konversi
    • Phantom diff pun hilang
    • Eksekusi di Windows tetap terjaga
  • Namun *.bat -text berarti melepaskan pemulihan otomatis yang sebelumnya diberikan oleh text eol=crlf
    • Sebelumnya, jika LF masuk karena kesalahan, Git akan diam-diam menormalkannya lagi saat commit
    • Sekarang, LF akan tetap ada dan gradlew.bat bisa rusak diam-diam di Windows
  • Konversi ini hanya perlu dilakukan sekali, dan edit yang keliru biasanya bisa tertangkap saat review
  • Meski begitu, tim Gradle menilai terlalu berisiko menggantungkan ekosistem pada asumsi bahwa semua proyek Gradle akan mem-commit CRLF secara langsung dan tidak ada editor yang diam-diam mengubahnya

Alternatif yang dipertahankan untuk sementara: git worktree

  • Workspace di jj menyediakan beberapa working directory yang berbagi satu repositori, sehingga proses CI yang panjang atau perubahan yang masih berjalan tidak menghalangi pekerjaan berikutnya
  • Tim Gradle sudah cukup memenuhi kebutuhan yang sama dengan git worktree
git worktree add ../gradle-feature-x feature-x
git worktree add ../gradle-hotfix    hotfix-7.6
  • Pendekatan ini memakai dua checkout dan satu object store
  • Dengan ini, pekerjaan paralel dan checkout main yang dipertahankan dalam jangka panjang bisa dijalankan tanpa stash atau clone kedua
  • Tim Gradle telah memakai pola ini selama bertahun-tahun

Kemungkinan meninjau ulang jj

  • Kasus ini bukan penilaian final terhadap jj untuk proyek Gradle
  • Operation log milik jj saja sudah cukup menarik untuk ditinjau lebih dalam
  • Dukungan eol diperlakukan sebagai masalah yang bisa diselesaikan, dan di isu tersebut juga ada pembahasan implementasi melalui gix-filter
  • Jika dukungan itu hadir, tim Gradle berencana mencoba lagi
  • Sampai saat itu, mereka tetap memakai Git karena gradlew.bat, dan git worktree mengisi peran yang mereka butuhkan

1 komentar

 
GN⁺ 9 jam lalu
Pendapat di Lobste.rs
  • Menurut saya, konfigurasi autocrlf di Git dan konfigurasi .gitattributes yang menyusulnya adalah kesalahan sejak awal, dan akan tetap begitu ke depannya
    Sistem version control tidak semestinya menyimpan file di dalam repository dalam bentuk yang berbeda dari file di disk
    Jika ingin memaksakan format file, itu tugas linter, commit hook, atau merge hook, bukan peran sistem version control

    • Saya cenderung setuju bahwa itu kesalahan sejak awal, tetapi sekarang menurut saya sebaiknya dinyatakan jelas sebagai kesalahan, dan khususnya core.{eol, safecrlf, autocrlf} harus dipindahkan ke status deprecated
      Konversi akhir baris ditambahkan semata-mata karena Windows; format khusus ␍ sudah mati bahkan sebelum Git, dan semua platform kecuali Windows sudah menetap pada format khusus ␊
      Sekarang, target utama yang benar-benar peduli pada ␍␊ tampaknya hanya file batch
      Semua bahasa berusaha mendukung ␍␊, tetapi sekarang hampir tidak ada yang mengharuskan atau menghasilkannya
      Jika Notepad masih memakai ␍␊ sebagai default, atau hanya mendukung itu, pengguna Notepad harus menanggung konsekuensinya
      Area yang lebih menarik dalam kompatibilitas Windows adalah file mode
      Git membawa mode Unix, dan jejaknya masih tersisa, sehingga saat bekerja di Windows kadang muncul kesalahan mode yang tidak disengaja
    • Justru sebaliknya, saya merasa version control seharusnya melakukan lebih banyak hal seperti ini, bukan lebih sedikit
      Jika tooling sudah cukup baik sehingga saat checkout otomatis memakai whitespace, atau menyesuaikannya ke jumlah whitespace yang sangat spesifik dan aneh yang dipaksakan seseorang, kita bisa menghentikan perdebatan tab versus spasi
      Lebih jauh lagi, bisa saja kita berpendapat bahwa sistem version control seharusnya menyimpan abstract syntax tree (AST), bukan teks mentah
      Saat ini mungkin sulit meyakinkan orang, tetapi mudah membayangkan lini masa lain atau masa depan di mana cara seperti ini terasa sangat natural
  • Saya tidak tahu file .bat itu akan dijalankan di mana kalau bukan di Windows
    Saya juga bertanya-tanya dalam kasus apa perilaku lain, sekecil apa pun, bisa dianggap diinginkan

  • Saya tidak yakin dengan argumen bahwa kita tidak boleh meng-commit file persis dengan format akhir baris yang dibutuhkan
    Intinya tampaknya adalah “seseorang bisa merusak akhir baris lalu meng-commit-nya, code review meloloskannya, dan skrip yang rusak masuk”
    Semua itu benar, tetapi bukankah karena itu ada pemeriksaan lint di CI?
    Pindai akhir baris yang bukan CRLF pada file tersebut, dan jika ditemukan, gagalkan CI; maka perubahan yang merusak akhir baris tidak akan bisa lolos tahap pull request

    • Sepertinya tujuan tulisan ini bukan hanya membahas jj di Gradle, melainkan menunjukkan bahwa masalah ini relevan bagi semua orang dan proyek di ekosistem JVM yang ingin memakai jj
      Jawaban “tinggal tambahkan CI saja” tidak cukup
      Proyek terkait bisa saja berupa mod Minecraft yang dibuat oleh pemula, dan siapa pun di antara mereka bisa merusak gradle.bat tanpa menyadarinya
      Saya sendiri juga punya tanggung jawab karena mempromosikan jj sebagai alternatif yang jauh lebih baik daripada CLI Git untuk pemula
  • Apakah opsi berpindah dari gradlew.bat ke gradlew.ps1, yaitu dari cmd.exe/file batch ke PowerShell, memungkinkan?

    • Saya tidak terlibat dengan Gradle, tetapi beberapa tahun lalu kami mencoba melakukan itu di Leiningen, dan saat itu kondisinya benar-benar kacau sehingga sama sekali tidak praktis
      Sekarang MUNGKIN bisa diasumsikan bahwa 90% basis instalasi Windows memiliki PowerShell yang cukup baru
      Namun, dalam beberapa kasus permission eksekusi default masih harus dinaikkan, dan di lingkungan perusahaan bisa saja dikunci
      Saya tidak tahu seberapa banyak Anda pernah memakai PowerShell, tetapi rasanya bukan seperti “karena ada bash, tinggal jalankan file .sh
      Kumpulan fiturnya berbeda-beda antarversi Windows, sehingga rasanya seperti membandingkan ksh dengan bash4