1 poin oleh GN⁺ 2 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • Git berhasil sebagai repositori terdistribusi untuk source code, tetapi penanganan workflow terdistribusi lebih mirip solusi yang ditempel belakangan sehingga batasannya mulai terlihat
  • Commit dan branch di Git tidak bisa dengan sendirinya merepresentasikan commit penerus, riwayat amend, riwayat rebase, atau status yang sudah dibuang
  • Dalam Stacked PR, kita perlu menemukan PR lanjutan dan melakukan rebase sambil mempertahankan stack, tetapi Git sulit memahami relasi ini secara andal
  • Git menempatkan status yang dapat berubah seperti staging, unstaged, file system, dan HEAD di luar commit dan branch, sehingga pembelajaran dan penggunaannya menjadi lebih rumit
  • Dalam alur pengembangan asinkron yang mengharuskan beberapa PR ditulis bersama sebelum digabung, model riwayat immutable Git yang menghadap ke belakang menimbulkan masalah berulang

Dua peran Git

  • Git digunakan sekaligus sebagai repositori terdistribusi untuk source code dan alat workflow terdistribusi
  • Sebagai repositori source code, Git sangat sukses, tetapi cara Git menangani workflow terdistribusi pada dasarnya lebih mirip solusi tambahan yang ditempel belakangan
  • Pengembangan asinkron, seperti ungkapan dari East River Source Control, nyaris merupakan kondisi dasar; ini terjadi bukan hanya saat berkolaborasi lintas zona waktu, tetapi juga saat bekerja dengan diri sendiri pada waktu yang berbeda
  • jj adalah alat yang membuat keterbatasan Git terlihat lebih jelas, dan orang yang merasa Git sudah cukup besar kemungkinan tidak akan mencoba jj dengan serius

Relasi yang terlewat oleh model dasar Git

  • Inti cara berpikir Git adalah commit dan branch
    • Commit adalah objek immutable yang memuat source code dan riwayatnya
    • Branch adalah pointer yang bisa berubah dengan log yang melekat padanya
  • Diagram Git yang umum biasanya menggambar commit sebagai C1, C2, C3 sehingga urutan dan relasinya tampak jelas, tetapi di repositori nyata nama commit lebih mendekati hash atau pesan, sehingga relasi urutan seperti itu tidak benar-benar ada di dalam sistem
  • Notasi seperti C2 dan C2’ setelah rebase hanyalah penjelasan yang mudah dipahami manusia; Git sendiri tidak tahu bahwa kedua commit itu saling berkorespondensi
  • Untuk menemukan commit penerus dari commit tertentu, kita harus menelusuri semua branch dan mencari commit pada jalur yang terhubung ke commit tersebut, jadi ini bukan hal yang sederhana

Git tidak punya “C”

  • Commit Git tidak bisa mengetahui sendiri informasi berikut
    • Commit penerus

      • Riwayat perubahan yang menghubungkan commit lama ke commit baru setelah amend
    • Riwayat rebase

      • Apakah commit tersebut sudah dibuang atau belum
      • Branch juga punya keterbatasan
      • Branch memang punya konsep riwayat, tetapi sulit dipercaya sebagai padanan 1:1 dengan perubahan kode
      • Branch tidak memiliki relasi antarsesamanya; misalnya, dari trunk kita tidak bisa menemukan wp/bugfix secara andal
      • Karena tidak ada referensi maju dari trunk ke wp/bugfix, relasi itu juga bukan relasi yang dapat dijangkau
      • Diagram Git bagi manusia tampak memiliki urutan dan relasi korespondensi, tetapi bisa melebih-lebihkan kemampuan yang benar-benar disediakan alatnya

Mengapa Stacked PR sulit

  • Jika ingin berkolaborasi dengan orang di zona waktu berbeda tanpa melakukan merge sebelum review selesai, pekerjaan harus di-pipeline seperti CPU
  • Alih-alih membuat satu PR lalu menunggu review selesai, Stacked PR adalah pendekatan membuat PR kedua di atas PR pertama, lalu PR berikutnya di atas itu, sehingga beberapa PR berurutan bisa direview secara bersamaan
  • Git membuat struktur Stacked PR sulit ditangani secara andal
    • Kita bisa membuat PR lanjutan seperti Refactor key entry code di atas Fix key entry race, lalu setelah mengambil pembaruan trunk, kita harus melakukan rebase sambil mempertahankan stack
    • Karena Git tidak mengetahui commit penerus, dari Fix key entry race kita tidak bisa dengan mudah melihat Refactor key entry code
    • Commit itu juga mungkin sudah dibuang, sehingga meskipun commit lanjutan bisa ditemukan, sulit mengetahui apakah itu masih versi terbaru
    • Branch dipakai seperti PR itu sendiri, tetapi dalam alur ini sangat mudah tertimpa secara tidak sengaja
  • Alat stacking seperti Graphite bisa melakukan pekerjaan ini di atas Git, tetapi tidak dapat memperkuat commit atau branch Git itu sendiri
    • Ia harus membuat repositori metadata branch terpisah dan menyinkronkannya dengan Git
    • Jika pengguna memanipulasi Git secara langsung, repositori itu bisa menjadi tidak sinkron dengan status Git

Status yang dapat berubah berada di luar commit

  • Banyak masalah Git berawal dari cara Git tidak memodelkan mutability secara langsung
  • Dalam workflow pengeditan Git, ada status terpisah di luar commit dan branch
    • Staging atau index adalah snapshot source code yang dibentuk dari working copy, dan commit baru dibuat dari sini
    • Unstaged adalah diff kedua yang merepresentasikan perbedaan antara index dan file system
    • File system menyimpan isi yang sedang di-checkout, dan perubahan staged maupun unstaged ditambahkan di atasnya
    • HEAD adalah posisi tempat commit baru akan dibuat
  • stash bekerja seperti repositori terpisah untuk menyimpan dan memulihkan perubahan staged dan unstaged
  • Saat checkout dipindah ke commit atau branch lain, Git mencoba menyesuaikan file system ke lokasi baru sambil tetap mempertahankan diff staging atau unstaged
  • Proses ini memang memakai perintah berbeda, tetapi jika hanya melihat relasi panahnya, bentuknya mirip rebase yang memindahkan staging ke atas basis baru

Mengapa sulit memodelkan semuanya sebagai commit

  • Staging dan working copy juga punya leluhur yang jelas dan berisi source code, jadi bila hanya dilihat sebagai status statis, keduanya tampak bisa direpresentasikan sebagai commit
  • Namun ID commit adalah hash dari isinya, jadi jika commit bisa berubah, ID-nya akan terus berubah
  • Agar staging dan working copy bisa secara konsisten menunjuk pada “apa” mereka, keduanya harus diperlakukan seperti branch, bukan commit, tetapi branch memiliki keterbatasan yang sudah dibahas sebelumnya
  • Kompleksitas ini menimbulkan masalah nyata
    • Git menjadi lebih sulit dipelajari dan digunakan, karena konsep yang sama hadir terpisah di dua sisi
    • Status keseluruhan repositori sangat berbeda dari status yang dibawa lewat clone, sehingga ekspor terasa canggung
    • Alur asinkron, di mana change set berubah seiring waktu, tidak berjalan dengan baik
    • Sistem di sisi yang mutable tidak bisa merepresentasikan merge, sehingga kadang tidak mampu menggambarkan workflow nyata

Saat Git tidak bisa merepresentasikan workflow yang sebenarnya

  • Saat sedang mengembangkan di feature branch baru tanpa commit, kita bisa menemukan bug pada perangkat yang mengganggu pengembangan
  • Jika bug itu tidak menghalangi fitur baru, tetapi membuat pengembangan merepotkan, kita bisa melakukan stash, pindah ke branch baru, membuat tes reproduksi dan perbaikannya, lalu mengajukan PR
  • Setelah itu, ketika kembali ke feature branch baru, pilihan kita menjadi terbatas
    • Melakukan rebase new-feature ke atas bugfix, meskipun sebenarnya tidak ada dependensi nyata, lalu melanjutkan review
    • Selama pengembangan, memakai new-feature di atas bugfix melalui rebase, lalu membatalkan rebase itu sebelum branch diajukan
  • Dengan Git, kita tidak bisa merepresentasikan keadaan bahwa “di ruang kerja pengeditan harus ada seluruh kode dari bugfix dan kode new feature yang sudah di-commit secara bersamaan”
  • Kebutuhan seperti ini muncul dengan struktur yang sama pada masalah yang lebih sulit, misalnya pengujian kompatibilitas dengan PR yang belum di-merge
  • Dengan alat yang tepat seperti Jujutsu megamerges, beberapa PR bisa dipertahankan secara paralel sambil tetap digunakan bersama di ruang pengeditan

Git tidak lagi cukup

  • Alat version control pada awal 2000-an sulit digunakan dan dikelola, kualitasnya tidak konsisten, dan ada persepsi luas bahwa Subversion pun menyakitkan untuk dipakai
  • Pada masa itu, kebutuhan untuk memiliki salinan penuh repositori secara lokal belum umum, dan keinginan untuk membuat local branch juga belum menjadi hal yang lazim
  • Banyak orang merasa tidak nyaman dengan file locking, tetapi sebagian lain menganggapnya perlu, dan bahkan bertanya apakah Git bisa mengunci file atau direktori individual
  • Bagi orang-orang yang mengalami workflow terdistribusi secara langsung seperti di open source, DVCS diterima seperti perban yang menutup luka lama
  • Saat ini, bagi orang yang benar-benar menggunakan workflow terdistribusi secara bermakna, model riwayat immutable Git yang menghadap ke belakang menjadi sumber masalah yang berulang
  • Perusahaan seperti Meta telah menggunakan sistem internal yang jauh melampaui Git selama hampir 10 tahun
  • Arus pemikiran bahwa “sekarang Git disentuh oleh Claude sebagai gantinya” tidak membuat alternatif seperti ini menjadi tidak relevan
  • Dengan penggunaan LLM, tampaknya para engineer bahkan dalam satu mesin tunggal pun melakukan jauh lebih banyak pengembangan asinkron dibanding sebelumnya

1 komentar

 
GN⁺ 2 jam lalu
Opini di Lobste.rs
  • Akan lebih bagus kalau tulisan ini menunjukkan bagaimana jj menyelesaikan masalah yang diangkat
    Bagi pengguna jj mungkin ini sudah jelas, tetapi kemungkinan besar mereka bukan target utama tulisan ini

  • Secara pribadi, saya belum pernah benar-benar membutuhkan fitur-fitur yang disebut di tulisan itu sebagai bukti bahwa Git tidak baik-baik saja
    Jadi saya bertanya-tanya apakah cuma saya yang seperti itu

    • Sama sekali bukan sendirian
      Salah satu hal penting tentang alat adalah bahwa alat merupakan bagian dari sistem yang dinamis. Hal yang dimungkinkan oleh suatu alat memengaruhi “hal yang saya yakini bisa saya lakukan”, dan keyakinan itu pada gilirannya mengubah persepsi terhadap alat tersebut serta arah evolusinya
      Ketika suatu alat mengguncang keadaan yang sudah ada, keyakinan dan ekspektasi tentang apa yang bisa dilakukan ikut berubah
  • Terlihat menarik, tetapi melihat diagramnya bikin pusing

  • Menanggapi pernyataan bahwa situasinya tidak separah awal 2000-an sekarang, dan bahwa keterbatasan sistem kontrol versi sebelum Git cukup jelas, Darcs hadir lebih dulu daripada Git dan dalam beberapa hal secara mendasar memperbaiki sebagian masalah version control berbasis snapshot
    Di awal ia kalah karena performanya buruk, tetapi performanya kemudian membaik dan orang-orang tidak kembali untuk memeriksanya lagi. Ada sistem kontrol versi lain yang juga mengerjakan hal-hal menarik, jadi saya harap ini tidak dibingkai seolah satu-satunya pilihan selain “Git adalah Jujutsu”. Saya terlalu sering melihat logika seperti itu

    • Agak lucu bahwa penulis mengatakan model data Git sangat bagus, lalu sambil lalu mengatakan bahwa branch di Git hanyalah pointer ke ujung branch sehingga alur kerjanya kurang baik
      Itu juga masalah model data
  • Bagaimana jj menangani ini? https://www.billjings.com/posts/title/git-is-not-fine/RealityEx23.png

    • Jika memakai jj new A B, commit working copy bisa memiliki beberapa parent, sehingga bertindak seperti merge commit
      Jadi working copy akan berisi perubahan dari kedua parent itu, lalu Anda bisa melanjutkan pekerjaan di atas hasil merge tersebut atau melakukan amend ke salah satu commit
  • Saya masih lebih menyukai Git, dan penulis tampaknya punya bias

    • Saya penasaran apakah alasan lebih menyukai Git adalah karena tidak mengalami situasi yang oleh penulis disebut sulit di Git dan sudah telanjur terbiasa dengan Git, atau karena meskipun mengalami situasi seperti itu tetap merasa Git memberi alur kerja yang lebih baik daripada Jujutsu
    • Selama ingat bahwa Anda harus menjalankan jj new, Anda bisa mencampur penggunaan git dan jj
      Git selalu menunjuk ke parent commit, dan jj commit saat ini menjadi seperti perubahan yang belum di-commit di working tree
      Saya belajar jj dengan cara itu. Saya memakai jj untuk hal-hal yang memang dikerjakannya dengan baik, seperti menangani rebase atau memindahkan tree, dan tetap memakai perintah git untuk pekerjaan sehari-hari ketika saya belum tahu padanannya di jj atau ketika perintah Git seperti git blame lebih dulu terlintas di kepala
      Saya benar-benar tidak terlalu merasakan kenapa jj lebih baik sampai memakainya setiap hari; saat hanya membacanya saya berpikir, “apa fitur ini benar-benar perlu?” atau “bukankah ini sudah bisa dilakukan di Git?”
      Tentu saja jj juga punya kekurangan. Jika tidak ada .gitignore terbaru, file biner bisa ikut masuk ke commit tanpa sengaja. Untungnya jj memberi peringatan saat Anda menambahkan file yang sangat besar, tetapi file kecil bisa lolos
      Kalau saat debugging ada file pelacakan atau file log di direktori saat ini, itu juga bisa ikut masuk, jadi setelah banyak memanipulasi tree sebaiknya meninjau seluruh diffstat
      Ini terutama bisa jadi masalah jika Anda melakukan bisect dengan jj lalu menguji commit yang lebih lama daripada commit yang memperbarui .gitignore. Mungkin mode read-only diperlukan untuk bisect