Saya telah mendengar di beberapa tempat bahwa salah satu alasan utama mengapa sistem kontrol versi terdistribusi bersinar, adalah penggabungan yang jauh lebih baik daripada pada alat tradisional seperti SVN. Apakah ini sebenarnya karena perbedaan yang melekat pada bagaimana kedua sistem bekerja, atau melakukan implementasi DVCS spesifik seperti Git / Mercurial hanya memiliki algoritma penggabungan yang lebih pintar daripada SVN?
400
Jawaban:
Klaim mengapa penggabungan lebih baik dalam DVCS daripada di Subversion sebagian besar didasarkan pada bagaimana percabangan dan penggabungan bekerja di Subversion beberapa waktu lalu. Subversi sebelum 1.5.0 tidak menyimpan informasi tentang kapan cabang digabung, jadi ketika Anda ingin menggabungkan Anda harus menentukan rentang revisi mana yang harus digabung.
Jadi mengapa penggabungan Subversion menghisap ?
Renungkan contoh ini:
Ketika kami ingin menggabungkan perubahan b1 ke dalam trunk, kami akan mengeluarkan perintah berikut, sambil berdiri di folder yang memiliki trunk check out:
... yang akan mencoba untuk menggabungkan perubahan dari
b1
ke direktori kerja lokal Anda. Dan kemudian Anda melakukan perubahan setelah Anda menyelesaikan konflik dan menguji hasilnya. Saat Anda komit, pohon revisi akan terlihat seperti ini:Namun cara menentukan rentang revisi ini cepat hilang ketika pohon versi tumbuh karena subversi tidak memiliki data meta kapan dan apa revisi yang digabungkan. Renungkan apa yang terjadi kemudian:
Ini sebagian besar merupakan masalah oleh desain repositori yang dimiliki Subversion, untuk membuat cabang Anda perlu membuat direktori virtual baru di repositori yang akan menampung salinan trunk tetapi tidak menyimpan informasi mengenai kapan dan apa hal-hal yang digabungkan kembali. Itu akan menyebabkan konflik gabungan yang buruk di kali. Yang lebih buruk lagi adalah bahwa Subversion menggunakan penggabungan dua arah secara default, yang memiliki beberapa batasan yang melumpuhkan dalam penggabungan otomatis ketika dua kepala cabang tidak dibandingkan dengan leluhur mereka yang sama.
Untuk mengurangi Subversi ini sekarang menyimpan data meta untuk cabang dan bergabung. Itu akan menyelesaikan semua masalah bukan?
Dan oh, omong-omong, Subversi masih menyebalkan ...
Pada sistem terpusat, seperti subversi, direktori virtual menyedot. Mengapa? Karena setiap orang memiliki akses untuk melihatnya ... bahkan yang eksperimental sampah. Percabangan baik jika Anda ingin bereksperimen tetapi Anda tidak ingin melihat eksperimen orang lain dan bibinya . Ini adalah kebisingan kognitif yang serius. Semakin banyak cabang yang Anda tambahkan, semakin banyak omong kosong yang akan Anda lihat.
Semakin banyak cabang publik yang Anda miliki di repositori, semakin sulit melacak semua cabang yang berbeda. Jadi pertanyaan yang akan Anda miliki adalah apakah cabang masih dalam pengembangan atau jika benar-benar mati yang sulit dikatakan dalam sistem kontrol versi terpusat.
Sebagian besar waktu, dari apa yang saya lihat, organisasi akan default untuk menggunakan satu cabang besar. Yang memalukan karena pada gilirannya akan sulit untuk melacak versi pengujian dan rilis, dan apa pun yang baik berasal dari percabangan.
Jadi mengapa DVCS, seperti Git, Mercurial dan Bazaar, lebih baik daripada Subversion di percabangan dan penggabungan?
Ada alasan yang sangat sederhana mengapa: percabangan adalah konsep kelas satu . Tidak ada direktori virtual oleh desain dan cabang adalah objek keras dalam DVCS yang perlu sedemikian rupa agar dapat bekerja hanya dengan sinkronisasi repositori (yaitu push dan pull ).
Hal pertama yang Anda lakukan ketika Anda bekerja dengan DVCS adalah mengkloning repositori (git's
clone
, hg'sclone
dan bzr'sbranch
). Kloning secara konseptual sama dengan membuat cabang dalam kontrol versi. Beberapa menyebutnya forking atau branching (meskipun yang terakhir sering juga digunakan untuk merujuk ke cabang co-located), tetapi itu adalah hal yang sama. Setiap pengguna menjalankan repositori mereka sendiri yang artinya Anda memiliki percabangan per-pengguna .Struktur versi bukan pohon , melainkan grafik . Lebih khusus grafik asiklik terarah (DAG, artinya grafik yang tidak memiliki siklus). Anda benar-benar tidak perlu memikirkan spesifik DAG selain setiap komit memiliki satu atau lebih referensi induk (yang berdasarkan komit itu). Jadi grafik berikut ini akan menunjukkan panah antara revisi secara terbalik karena ini.
Contoh penggabungan yang sangat sederhana adalah ini; bayangkan repositori sentral dipanggil
origin
dan seorang pengguna, Alice, mengkloning repositori ke mesinnya.Apa yang terjadi selama klon adalah bahwa setiap revisi disalin ke Alice persis seperti mereka (yang divalidasi oleh hash-id yang dapat diidentifikasi secara unik), dan menandai di mana cabang asal berada.
Alice kemudian mengerjakan repo-nya, melakukan dalam repositori miliknya sendiri dan memutuskan untuk mendorong perubahannya:
Solusinya agak sederhana, satu-satunya hal yang
origin
perlu dilakukan repositori adalah mengambil semua revisi baru dan memindahkan cabangnya ke revisi terbaru (yang git memanggil "fast-forward"):Kasus penggunaan, yang saya ilustrasikan di atas, bahkan tidak perlu menggabungkan apa pun . Jadi masalahnya sebenarnya bukan dengan algoritma penggabungan karena algoritma penggabungan tiga arah hampir sama antara semua sistem kontrol versi. Masalahnya lebih tentang struktur daripada apa pun .
Jadi, bagaimana kalau Anda menunjukkan contoh yang memiliki penggabungan nyata ?
Memang contoh di atas adalah kasus penggunaan yang sangat sederhana, jadi mari kita lakukan yang lebih memutar meskipun yang lebih umum. Ingat itu
origin
dimulai dengan tiga revisi? Nah, orang yang melakukannya, sebut saja dia Bob , telah mengerjakan sendiri dan membuat komit di repositori sendiri:Sekarang Bob tidak bisa mendorong perubahannya langsung ke
origin
repositori. Bagaimana sistem mendeteksi ini adalah dengan memeriksa apakah revisi Bob langsung diturunkan dariorigin
, yang dalam kasus ini tidak. Setiap upaya untuk mendorong akan menghasilkan sistem mengatakan sesuatu yang mirip dengan " Eh ... aku takut tidak bisa membiarkanmu melakukan itu Bob ."Jadi Bob harus menarik dan menggabungkan perubahan (dengan git
pull
; atau hgpull
danmerge
; atau bzrmerge
). Ini adalah proses dua langkah. Bob pertama harus mengambil revisi baru, yang akan menyalinnya dariorigin
repositori. Kita sekarang dapat melihat bahwa grafik berbeda:Langkah kedua dari proses tarik adalah menggabungkan tip yang berbeda dan membuat komitmen terhadap hasilnya:
Mudah-mudahan penggabungan tidak akan mengalami konflik (jika Anda mengantisipasi mereka, Anda dapat melakukan dua langkah secara manual di git dengan
fetch
danmerge
). Yang nanti perlu dilakukan adalah mendorong perubahan itu lagiorigin
, yang akan menghasilkan penggabungan cepat karena komit gabungan adalah keturunan langsung dari yang terbaru dalamorigin
repositori:Ada opsi lain untuk menggabungkan git dan hg, yang disebut rebase , yang akan memindahkan perubahan Bob setelah perubahan terbaru. Karena saya tidak ingin jawaban ini menjadi lebih bertele-tele saya akan membiarkan Anda membaca dokumen git , lincah atau bazaar tentang itu.
Sebagai latihan untuk pembaca, coba gambarkan cara kerjanya dengan pengguna lain yang terlibat. Demikian pula halnya dengan contoh di atas dengan Bob. Penggabungan antar repositori lebih mudah daripada yang Anda pikirkan karena semua revisi / komit dapat diidentifikasi secara unik.
Ada juga masalah pengiriman tambalan antara masing-masing pengembang, yang merupakan masalah besar dalam Subversion yang dimitigasi dalam git, hg dan bzr oleh revisi yang dapat diidentifikasi secara unik. Setelah seseorang menggabungkan perubahannya (yaitu membuat komit gabungan) dan mengirimkannya kepada semua orang di tim untuk dikonsumsi dengan mendorong ke repositori pusat atau mengirim tambalan maka mereka tidak perlu khawatir tentang gabungan tersebut, karena itu sudah terjadi . Martin Fowler menyebut cara ini untuk melakukan integrasi bebas pilih - pilih .
Karena strukturnya berbeda dari Subversion, dengan alih-alih menggunakan DAG, itu memungkinkan percabangan dan penggabungan dilakukan dengan cara yang lebih mudah tidak hanya untuk sistem tetapi juga bagi pengguna.
sumber
Secara historis, Subversion hanya mampu melakukan penggabungan dua arah yang lurus karena tidak menyimpan informasi penggabungan. Ini melibatkan mengambil satu set perubahan dan menerapkannya pada pohon. Bahkan dengan informasi penggabungan, ini masih merupakan strategi penggabungan yang paling umum digunakan.
Git menggunakan algoritma penggabungan 3-arah secara default, yang melibatkan menemukan leluhur yang sama dengan kepala yang digabungkan dan memanfaatkan pengetahuan yang ada di kedua sisi penggabungan. Ini memungkinkan Git menjadi lebih cerdas dalam menghindari konflik.
Git juga memiliki beberapa kode pencarian ganti nama yang canggih, yang juga membantu. Itu tidak menyimpan perubahan atau menyimpan informasi pelacakan - itu hanya menyimpan keadaan file di setiap komit dan menggunakan heuristik untuk mencari nama dan gerakan kode yang diperlukan (penyimpanan pada disk lebih rumit dari ini, tetapi antarmuka itu hadir ke lapisan logika memperlihatkan tidak ada pelacakan).
sumber
Sederhananya, implementasi gabungan dilakukan lebih baik di Git daripada di SVN . Sebelum 1.5 SVN tidak merekam tindakan penggabungan, jadi tidak mungkin melakukan penggabungan di masa mendatang tanpa bantuan pengguna yang perlu memberikan informasi yang tidak dicatat oleh SVN. Dengan 1,5 semakin baik, dan memang model penyimpanan SVN sedikit lebih mampu daripada Dag Git. Tetapi SVN menyimpan informasi penggabungan dalam bentuk yang agak berbelit-belit yang memungkinkan penggabungan mengambil waktu lebih banyak daripada di Git - Saya telah mengamati faktor 300 dalam waktu eksekusi.
Juga, SVN mengklaim untuk melacak nama untuk membantu penggabungan file yang dipindahkan. Tapi sebenarnya itu masih menyimpannya sebagai salinan dan tindakan penghapusan terpisah, dan algoritma penggabungan masih tersandung di atasnya dalam memodifikasi / mengubah nama situasi, yaitu, di mana file diubah pada satu cabang dan mengubah nama pada yang lain, dan cabang-cabang itu adalah untuk digabung. Situasi seperti itu masih akan menghasilkan konflik penggabungan palsu, dan dalam kasus direktori berganti nama itu bahkan menyebabkan hilangnya modifikasi diam-diam. (Orang-orang SVN kemudian cenderung menunjukkan bahwa modifikasi masih dalam sejarah, tetapi itu tidak banyak membantu ketika mereka tidak dalam hasil penggabungan di mana mereka akan muncul.
Git, di sisi lain, bahkan tidak melacak nama tetapi mencari mereka setelah fakta (pada saat penggabungan), dan melakukannya dengan cukup ajaib.
Representasi gabungan SVN juga memiliki masalah; di 1.5 / 1.6 Anda bisa menggabungkan dari trunk ke branch sesering yang baru saja disukai, secara otomatis, tetapi penggabungan ke arah lain perlu diumumkan (
--reintegrate
), dan meninggalkan cabang dalam keadaan tidak dapat digunakan. Jauh kemudian mereka menemukan bahwa ini sebenarnya bukan masalahnya, dan bahwa a)--reintegrate
dapat dipecahkan secara otomatis, dan b) penggabungan berulang di kedua arah dimungkinkan.Tetapi setelah semua ini (yang IMHO menunjukkan kurangnya pemahaman tentang apa yang mereka lakukan), saya akan (OK, saya) sangat berhati-hati untuk menggunakan SVN dalam skenario percabangan nontrivial, dan idealnya akan mencoba melihat apa yang Git pikirkan tentang hasil penggabungan.
Poin-poin lain yang dibuat dalam jawaban, karena visibilitas global yang dipaksakan dari cabang-cabang di SVN, tidak relevan untuk menggabungkan kemampuan (tetapi untuk kegunaan). Juga, 'Git store berubah sementara SVN store (sesuatu yang berbeda)' sebagian besar tidak tepat sasaran. Git secara konseptual menyimpan setiap komit sebagai pohon terpisah (seperti file tar ), dan kemudian menggunakan beberapa heuristik untuk menyimpannya secara efisien. Menghitung perubahan antara dua komit terpisah dari implementasi penyimpanan. Yang benar adalah bahwa Git menyimpan DAG sejarah dalam bentuk yang jauh lebih mudah bahwa SVN melakukan mergeinfo. Siapa pun yang mencoba memahami yang terakhir akan tahu apa yang saya maksud.
Singkatnya: Git menggunakan model data yang jauh lebih sederhana untuk menyimpan revisi daripada SVN, dan dengan demikian itu dapat menempatkan banyak energi ke dalam algoritma penggabungan yang sebenarnya daripada mencoba untuk mengatasi representasi => penggabungan yang praktis lebih baik.
sumber
Satu hal yang belum disebutkan dalam jawaban lain, dan itu benar-benar adalah keuntungan besar dari DVCS, adalah bahwa Anda dapat melakukan secara lokal sebelum Anda mendorong perubahan Anda. Di SVN, ketika saya memiliki beberapa perubahan, saya ingin check-in, dan seseorang telah melakukan komitmen pada cabang yang sama sementara itu, ini berarti bahwa saya harus melakukan
svn update
sebelum saya dapat melakukan. Ini berarti bahwa perubahan saya, dan perubahan dari orang lain sekarang digabung menjadi satu, dan tidak ada cara untuk membatalkan penggabungan (seperti dengangit reset
atauhg update -C
), karena tidak ada komitmen untuk kembali. Jika penggabungan bersifat non-sepele, ini berarti Anda tidak dapat terus bekerja pada fitur Anda sebelum Anda membersihkan hasil penggabungan.Tapi kemudian, mungkin itu hanya keuntungan bagi orang-orang yang terlalu bodoh untuk menggunakan cabang terpisah (jika saya ingat dengan benar, kami hanya memiliki satu cabang yang digunakan untuk pengembangan kembali di perusahaan tempat saya menggunakan SVN).
sumber
EDIT: Ini terutama membahas bagian dari pertanyaan ini:
Apakah ini sebenarnya karena perbedaan yang melekat dalam bagaimana kedua sistem bekerja, atau melakukan implementasi DVCS spesifik seperti Git / Mercurial hanya memiliki algoritma penggabungan yang lebih pintar daripada SVN?
TL; DR - Alat khusus itu memiliki algoritma yang lebih baik. Didistribusikan memiliki beberapa manfaat alur kerja, tetapi ortogonal dengan keuntungan penggabungan.
AKHIR EDIT
Saya membaca jawaban yang diterima. Itu salah sekali.
Penggabungan SVN bisa jadi menyebalkan, dan juga bisa merepotkan. Tapi, abaikan cara kerjanya sebenarnya sebentar. Tidak ada informasi yang disimpan atau diperoleh Git bahwa SVN juga tidak disimpan atau dapat diturunkan. Lebih penting lagi, tidak ada alasan mengapa menyimpan salinan terpisah dari sistem kontrol versi akan memberikan Anda informasi yang lebih aktual. Kedua struktur ini sepenuhnya setara.
Asumsikan Anda ingin melakukan "sesuatu yang pintar" Git "lebih baik". Dan Anda diperiksa ke SVN.
Konversikan SVN Anda menjadi bentuk Git yang setara, lakukan di Git, dan kemudian periksa hasilnya, mungkin menggunakan beberapa komit, beberapa cabang tambahan. Jika Anda bisa membayangkan cara otomatis untuk mengubah masalah SVN menjadi masalah Git, maka Git tidak memiliki keunggulan mendasar.
Pada akhirnya, sistem kontrol versi apa pun akan mengizinkan saya
Selain itu, untuk menggabungkan itu juga berguna (atau penting) untuk diketahui
Mercurial , Git dan Subversion (sekarang secara native, sebelumnya menggunakan svnmerge.py) semua dapat memberikan ketiga informasi. Untuk menunjukkan sesuatu yang secara fundamental lebih baik dengan DVC, tunjukkan beberapa informasi keempat yang tersedia di Git / Mercurial / DVC tidak tersedia dalam SVN / VC terpusat.
Itu bukan berarti mereka bukan alat yang lebih baik!
sumber
git merge-base
. Dengan git, Anda dapat mengatakan "cabang a dan b dibagi pada revisi x". Tapi svn menyimpan "file disalin dari foo ke bar", jadi Anda perlu menggunakan heuristik untuk mengetahui bahwa copy ke bar membuat cabang baru alih-alih menyalin file dalam suatu proyek. Kuncinya adalah bahwa revisi di svn didefinisikan oleh angka revisi dan jalur dasar. Meskipun mungkin untuk menganggap "trunk" sebagian besar waktu, itu menggigit jika sebenarnya ada cabang.SVN melacak file sementara Git melacak perubahan
konten. Cukup pintar untuk melacak blok kode yang dire-refored dari satu kelas / file ke yang lain. Mereka menggunakan dua pendekatan berbeda lengkap untuk melacak sumber Anda.Saya masih menggunakan banyak SVN, tetapi saya sangat senang dengan beberapa kali saya menggunakan Git.
Bacaan yang bagus jika Anda punya waktu: Mengapa saya memilih Git
sumber
Baca saja sebuah artikel di blog Joel (sayangnya yang terakhir). Yang ini tentang Mercurial, tetapi sebenarnya berbicara tentang keuntungan dari sistem VC Terdistribusi seperti Git.
Baca artikel di sini .
sumber