Apakah ada perbedaan antara penggabungan dalam svn dibandingkan dengan git atau lincah?

12

Dari pemahaman saya, SVN adalah 'Mudah untuk cabang. Sulit untuk digabung '. Mengapa demikian? Apakah ada perbedaan bagaimana mereka bergabung?


sumber

Jawaban:

21

Silakan lihat jawaban Stack Overflow saya untuk situasi yang sangat konkret di mana Mercurial (dan Git) bergabung tanpa masalah dan di mana Subversion menghadirkan konflik palsu kepada Anda. Situasinya adalah refactoring sederhana yang dilakukan pada cabang tempat Anda mengganti nama beberapa file.

Berkenaan dengan jawaban tammmer, maka ada sejumlah kesalahpahaman di sana:

  • Subversion, Mercurial, dan Git semua snapshot track-lebar proyek. Menyebutnya versi , revisi , atau perubahan tidak ada bedanya. Itu semua secara logis merupakan cuplikan atom dari sekumpulan file.

  • Ukuran komit Anda tidak membuat perbedaan dalam hal penggabungan. Ketiga sistem bergabung dengan algoritma gabungan tiga arah standar dan input untuk algoritma tersebut

    • versi leluhur bersama terbesar
    • versi di satu cabang
    • versi di cabang lain

    Tidak masalah bagaimana dua versi cabang dibuat. Anda dapat menggunakan 1000 komit kecil sejak versi leluhur, atau Anda dapat menggunakan 1 komit. Yang penting adalah versi final file. (Ya, ini mengejutkan! Ya, banyak panduan DVCS yang salah ini.)

Dia juga memunculkan beberapa poin bagus tentang perbedaan:

  • Subversion memiliki beberapa "voodoo" di mana Anda dapat bergabung dari /trunk, katakanlah /branches/foo,. Mercurial dan Git tidak menggunakan model ini - cabang malah dimodelkan secara langsung dalam sejarah. Karenanya sejarah menjadi grafik asiklik yang terarah bukannya linier. Ini model yang jauh lebih sederhana daripada yang digunakan oleh Subversion dan ini memotong sejumlah kasus sudut.

  • Anda dapat dengan mudah menunda penggabungan atau bahkan membiarkan orang lain menanganinya. Jika hg mergememberi Anda satu ton konflik, maka Anda dapat meminta rekan kerja hg pullAnda dari Anda dan kemudian ia memiliki kondisi yang sama persis. Jadi dia bisa hg mergedan mungkin dia lebih baik dalam menyelesaikan konflik daripada Anda.

    Ini sangat sulit dengan Subversion di mana Anda harus memperbarui sebelum dapat melakukan. Anda tidak bisa mengabaikan perubahan di server dan terus melakukan di cabang anonim Anda sendiri. Secara umum, Subversion memaksa Anda untuk bermain-main dengan copy pekerjaan yang kotor ketika Anda svn update. Ini agak berisiko karena Anda belum menyimpan perubahan Anda di tempat yang aman. Git dan Mercurial memungkinkan Anda melakukan komit terlebih dahulu, lalu memperbarui dan menggabungkan seperlunya.

Alasan sebenarnya Git dan Mercurial lebih baik dalam merger daripada Subversion adalah masalah implementasi. Ada perubahan nama konflik yang Subversion tidak bisa atasi bahkan berpikir sudah jelas apa jawaban yang benar. Mercurial dan Git menangani itu dengan mudah. Tetapi tidak ada alasan mengapa Subversion tidak dapat menangani hal itu juga - dipusatkan tentu bukan alasannya.

Martin Geisler
sumber
4
jawaban bagus! Saya akan memilih dua kali jika saya bisa. :) Saya juga menambahkan bahwa buku SVN yang Anda rujuk dalam SO jawaban dengan jelas mengakui bahwa "fitur gabungan pelacakan Subversion memiliki implementasi internal yang sangat kompleks ..." - ini saja merupakan indikasi yang cukup baik bahwa fitur tidak dapat diandalkan
agas
2
... dan bahkan dengan implementasi yang sangat kompleks tidak dapat menemukan leluhur bersama dengan benar dalam kasus apa pun kecuali sederhana.
Jan Hudec
Tentang gabungan yang tertunda - jangan pahami - dengan SVN, rekan kerja saya dapat memperbarui ke / checkout trunk, dan kemudian menggabungkan dari cabang saya ke dalamnya.
Gill Bates
@GillBates: Saya sedang berbicara tentang situasi di mana Anda belum memulai cabang untuk pekerjaan Anda - saat Anda bekerja trunkdi SVN. Dengan DVCS Anda dapat melakukan tanpa berbagi, tetapi dalam SVN Anda svn commitakan langsung mempengaruhi orang lain yang bekerja di cabang yang sama. Bahkan jika kami berdua bekerja di cabang di SVN, saya tidak bisa melakukan pekerjaan saya tanpa harus segera bergabung dengan pekerjaan Anda. Itu membuat komit agak menakutkan - yang merupakan properti menakutkan untuk sistem kontrol versi! :-)
Martin Geisler
6

Masalah inti terletak pada cara sistem ini mewakili struktur direktori berversi.

Konsep dasar Subversion di mana seluruh sistem berputar adalah versi (atau, dalam bahasa svn, "revisi"): snapshot file pada titik tertentu. Selama sejarahnya benar-benar linier, semuanya baik-baik saja, tetapi jika Anda perlu menggabungkan perubahan dari dua jalur independen pengembangan, svn harus membandingkan versi saat ini dari keduanya, dan kemudian melakukan perbandingan tiga arah antara versi terakhir yang dibagikan dan dua versi kepala. Garis yang muncul berubah di salah satu kepala, tetapi tidak yang lain, dapat dengan mudah diselesaikan; garis yang menyimpang dengan cara yang sama persis di kedua kepala lebih sulit, tetapi biasanya bisa dilakukan; garis yang menyimpang dengan cara yang berbeda adalah apa yang membuat svn mengatakan, "Aku tidak tahu ini, manusia, tolong selesaikan ini untukku."

Sebaliknya, git dan track perubahan berubah daripada versi. Seluruh repositori adalah pohon perubahan, masing-masing tergantung pada orang tua, di mana orang tua perubahan dapat memiliki jumlah anak berapa pun, dan akar pohon mewakili direktori kosong. Dengan kata lain, git / hg mengatakan "pertama saya tidak punya apa-apa, lalu tambalan ini diterapkan, lalu tambalan itu, dll.". Ketika Anda perlu menggabungkan dua baris pengembangan, git / hg tidak hanya tahu seperti apa masing-masing kepala saat ini, dan seperti apa versi umum terakhirnya, tetapi juga tahu bagaimana transisi terjadi, memungkinkan penggabungan yang jauh lebih cerdas.

Hal lain yang membuat penggabungan menjadi lebih mudah dalam DVCS adalah konsekuensi tidak langsung dari pemisahan konsep commit dan push, dan memungkinkan segala macam gabungan silang antara dua klon dari repositori yang sama setiap saat. Dengan svn, orang cenderung melakukan perubahan besar dengan perubahan yang sering tidak berhubungan, karena komitmen juga merupakan pembaruan pada repositori pusat yang mempengaruhi semua anggota tim lainnya; jika Anda melakukan versi yang rusak, semua orang akan marah kepada Anda. Karena sebagian besar pengaturan melibatkan server svn jaringan, melakukan juga melibatkan pemompaan data melalui jaringan, yang berarti melakukan menimbulkan penundaan yang cukup besar pada alur kerja (terutama ketika copy pekerjaan Anda sudah usang dan Anda harus menarik lebih dulu). Dengan git dan lincah, komit terjadi secara lokal, dan karena keduanya sangat efisien dalam menangani sistem file lokal, biasanya selesai secara instan. Akibatnya, orang-orang (begitu mereka terbiasa) melakukan perubahan bertahap kecil, dan ketika itu berhasil, dorong selusin atau lebih komit dalam sekali jalan. Kemudian ketika waktu penggabungan muncul, SCM memiliki banyak informasi yang lebih detail untuk dilalui, dan dapat melakukan pekerjaan yang lebih baik dalam menyelesaikan konflik dengan aman dan otomatis.

Dan kemudian ada detail bagus yang membuat segalanya lebih mudah:

  • Anda dapat memiliki beberapa kepala dan masih berkomitmen pada salah satu; tidak seperti subversi, Anda tidak perlu menggabungkan tarikan, perbarui, dan gabungkan sebelum melakukan lagi - beberapa kepala tetap seperti itu sampai Anda memilih untuk menggabungkan
  • Direktori tidak diperlakukan secara khusus; sebaliknya, path hanya dianggap sebagai nama file besar, dan semua direktori Anda harus pada revisi yang sama setiap saat. Ini berarti Anda tidak dapat melakukan subversi voodoo di mana subfolder proyek berada pada revisi yang berbeda, tetapi itu juga berarti copy pekerjaan lebih kecil kemungkinannya untuk menjadi kekacauan besar yang tidak dapat dikelola yang dikelola, dan yang lebih menarik, perpindahan tidak ditampilkan sebagai penghapusan -and-add (yang akan pecah seluruhnya dalam svn jika bukan karena metadata retrofit), tetapi hanya sebagai ganti nama; jika Anda memindahkan file, seluruh riwayatnya akan dipertahankan; penggabungan bahkan dapat menerapkan perubahan pada file yang dipindahkan yang dibuat ke versi yang tidak dipindahkan dari file yang sama setelah pindah, di cabang lain
  • Sebagian besar waktu, Anda sebenarnya tidak perlu melakukan percabangan: sebaliknya, Anda hanya mengkloning seluruh repositori. Kloning itu murah, terutama jika itu dilakukan pada sistem file yang sama, dan jika Anda memutuskan ingin menyingkirkan klon, Anda cukup menghapus direktori tempatnya tinggal dan itu saja. Anda bahkan tidak perlu menggunakan hg atau git untuk itu.
  • Ada beberapa (jika ada) pembatasan pada apa yang dapat Anda gabungkan. Anda dapat memiliki enam klon dari repositori yang sama, dan menggabungkan (atau lebih tepatnya, mendorong atau menarik; penggabungan eksplisit seringkali tidak diperlukan) dari A ke B, lalu C ke B, lalu B ke D, lalu C ke D, B kembali ke A, D ke E, kapan saja dan sesering yang Anda suka.
  • Anda bisa menguji gabungan dengan mengkloning salah satu repositori yang ingin Anda gabungkan, dan kemudian menariknya dari yang lain. Jika melakukan apa yang Anda inginkan, Anda dapat mendorong kembali ke target yang sebenarnya, jika tidak, Anda membuang klon dan mulai lagi.
tammmer
sumber
2
Saya harus menyebutkan beberapa koreksi dan menambahkan jawaban: 1. Revisi SVN bersifat global per-repositori , revisi mewakili semua file dalam repo dalam beberapa saat 2. Teknologi penggabungan pada dasarnya umum di SVN dan DVCS - jika file dalam file gabungan hanya mengubah cara yang sama , penggabungan akan menghasilkan jumlah konflik yang sama untuk SVN dan DVCS - semua SCM masih beroperasi pada level string, bukan blok logis 3. Komit besar di SVN bukan hasil dari kelemahan arsitektur, tetapi karena pengguna sering idiot malas - mereka mengabaikan pola dasar. Cabang | menggabungkan bekerja di SVN, jika / dev / otak dan / dev / tangan bekerja
Lazy Badger
2
Bagian 2: Penggabungan cerdas dalam DVCS sebagian besar terjadi karena, bertentangan dengan Subversion, mereka melacak dan menangani perpindahan | nama file dan SVN tidak melakukannya sama sekali, sehingga - operasi apa pun, yang memproses file, berubah di satu sisi dan diubah namanya menjadi kedua, akan gagal. Bercabang dengan cabang dan dengan kloning hanyalah strategi berbeda dari bercabang dengan hak yang sama untuk hidup, yang menggunakan "... tergantung dari ..."
Lazy Badger
@LazyBadger: Au contraire. Subversi tidak track bergerak / mengganti nama, yang menyebabkan konflik palsu sebagian karena itu penanganan mengganti nama di merge hanya kereta dan sebagian lagi karena ada kasus sudut yang sulit atau tidak mungkin untuk menangani dengan benar. Yang kemudian adalah mengapa git (dan disalin lincah) oleh desain tidak melacak nama dan menebak mereka saat penggabungan. Yang berfungsi dengan baik jika isinya masih cukup mirip untuk digabung (yaitu saat Anda membutuhkannya) dan tidak melakukan hal-hal konyol sebaliknya.
Jan Hudec
@JanHudec - maaf, pegangan SVN tidak bergerak | berganti nama menjadi atomic one action (cara DVCS - "rename"), tetapi sebagai "delete + ...", dengan demikian - menghasilkan konflik pohon, di mana hal itu tidak terjadi di DVCS ( true rename ). Track Mercurial mengubah nama secara eksplisit ( hg mvatau hg addremove --similarity...), sementara Git menggunakan heuristik, tetapi keduanya menangani penggantian nama . Saya bisa mendapatkan konflik pohon bahkan dengan perbedaan 1 string dalam file yang digabungkan! Anda harus mempelajari kembali beberapa aspek Subversi, maaf.
Malas Badger
5
Sekarang kita mendapatkan cukup teknis :-) Baik salinan lagu Subversion dan Mercurial , bukan nama. Kedua sistem melacak rename a bsebagai copy a b; remove adan keduanya melakukannya dalam satu atom komit. Perbedaan dalam perilaku penggabungan berasal dari penanganan kasus sudut yang berbeda dan dari Subversion yang memungkinkan penggabungan lebih banyak daripada Mercurial dan Git. Akhirnya, Git mendeteksi nama-nama pada saat penggabungan dan waktu log - kami juga berpikir untuk menambahkan ini dalam Mercurial.
Martin Geisler