Git dan Mercurial - Bandingkan dan Kontras

520

Untuk sementara sekarang saya telah menggunakan subversi untuk proyek pribadi saya.

Semakin banyak saya terus mendengar hal-hal hebat tentang Git dan Mercurial, dan DVCS secara umum.

Saya ingin memberikan seluruh pusaran hal-hal DVCS, tapi saya tidak terlalu akrab dengan pilihan baik.

Apa perbedaan antara Mercurial dan Git?

Catatan: Saya tidak berusaha mencari tahu mana yang "terbaik" atau bahkan mana yang harus saya mulai. Saya terutama mencari bidang-bidang utama di mana mereka serupa, dan di mana mereka berbeda, karena saya tertarik untuk mengetahui perbedaannya dalam hal implementasi dan filosofi.

TM.
sumber

Jawaban:

451

Penafian: Saya menggunakan Git, ikuti pengembangan Git di milis git, dan bahkan berkontribusi sedikit pada Git (terutama gitweb). Saya tahu Mercurial dari dokumentasi dan beberapa dari diskusi di kanal IRC #revctrl di FreeNode.

Terima kasih kepada semua orang di saluran IRC #mercurial yang memberikan bantuan tentang Mercurial untuk penulisan ini



Ringkasan

Di sini akan menyenangkan untuk memiliki beberapa sintaks untuk tabel, sesuatu seperti di PHPMarkdown / MultiMarkdown / Maruku ekstensi Markdown

  • Struktur repositori: Mercurial tidak mengizinkan penggabungan gurita (dengan lebih dari dua orang tua), atau menandai objek yang tidak berkomitmen.
  • Tag: Mercurial menggunakan .hgtagsfile berversi dengan aturan khusus untuk tag per-repositori, dan juga mendukung tag lokal di .hg/localtags; di Git tag adalah referensi yang berada di refs/tags/namespace, dan secara default diikutkan secara otomatis pada pengambilan dan memerlukan dorongan eksplisit.
  • Cabang: Dalam alur kerja dasar Mercurial didasarkan pada kepala anonim ; Git menggunakan cabang bernama ringan, dan memiliki jenis cabang khusus ( cabang pelacakan jarak jauh ) yang mengikuti cabang di repositori jarak jauh.
  • Penamaan dan rentang revisi : Mercurial memberikan angka revisi , lokal ke repositori, dan mendasarkan revisi relatif (dihitung dari ujung, yaitu cabang saat ini) dan rentang revisi pada penomoran lokal ini ; Git menyediakan cara untuk merujuk pada revisi relatif terhadap ujung cabang, dan rentang revisi bersifat topologis (berdasarkan grafik revisi)
  • Mercurial menggunakan pelacakan nama , sedangkan Git menggunakan deteksi nama untuk berurusan dengan nama file
  • Jaringan: Mercurial mendukung protokol SSH dan HTTP "pintar", dan protokol HTTP statis; Git modern mendukung protokol SSH, HTTP, dan GIT "pintar", dan protokol HTTP (S) "bodoh". Keduanya memiliki dukungan untuk file bundel untuk transportasi off-line.
  • Mercurial menggunakan ekstensi (plugin) dan API yang mapan; Git memiliki skripabilitas dan format yang ditetapkan.

Ada beberapa hal yang berbeda Mercurial dari Git, tetapi ada hal-hal lain yang membuatnya serupa. Kedua proyek saling meminjam ide. Misalnya hg bisectperintah dalam Mercurial (sebelumnya ekstensi dua bagian ) diilhami oleh git bisectperintah di Git, sementara ide git bundlediilhami oleh hg bundle.

Struktur repositori, menyimpan revisi

Di Git ada empat jenis objek dalam database objeknya: objek gumpalan yang berisi konten file, objek hierarki pohon yang menyimpan struktur direktori, termasuk nama file dan bagian yang relevan dari izin file (izin yang dapat dieksekusi untuk file, menjadi tautan simbolik) , komit objek yang berisi informasi kepengarangan, penunjuk ke snapshot keadaan repositori pada revisi yang diwakili oleh komit (melalui objek pohon direktori proyek teratas) dan referensi ke nol atau lebih komit induk, dan menandai objek yang mereferensikan objek lain dan dapat ditandatangani menggunakan PGP / GPG.

Git menggunakan dua cara menyimpan objek: format longgar , di mana setiap objek disimpan dalam file terpisah (file-file itu ditulis sekali, dan tidak pernah dimodifikasi), dan dikemas format yang mana banyak objek disimpan delta-dikompresi dalam satu file. Atomicity operasi disediakan oleh fakta, bahwa referensi ke objek baru ditulis (secara atomis, menggunakan trik buat + ganti nama) setelah menulis objek.

Repositori Git memerlukan pemeliharaan berkala menggunakan git gc(untuk mengurangi ruang disk dan meningkatkan kinerja), meskipun saat ini Git melakukannya secara otomatis. (Metode ini memberikan kompresi repositori yang lebih baik.)

Mercurial (sejauh yang saya mengerti) menyimpan sejarah file dalam filelog (bersama-sama, saya pikir, dengan metadata tambahan seperti pelacakan nama, dan beberapa informasi pembantu); menggunakan struktur datar yang disebut manifes untuk menyimpan struktur direktori, dan struktur yang disebut changelog yang menyimpan informasi tentang perubahan (revisi), termasuk pesan komit dan nol, satu atau dua orang tua.

Mercurial menggunakan jurnal transaksi untuk memberikan atomicity operasi, dan bergantung pada pemotongan file untuk pembersihan setelah operasi gagal atau terputus. Revlog hanya untuk penambahan.

Melihat struktur repositori di Git versus di Mercurial, orang dapat melihat bahwa Git lebih mirip database objek (atau sistem file yang ditujukan pada konten), dan Mercurial lebih seperti database relasional bidang tetap tradisional.

Perbedaan:
Dalam Git objek pohon membentuk struktur hierarkis ; dalam file manifes Mercurial adalah struktur datar . Dalam objek Git blob, simpan satu versi isi file; di Mercurial filelog menyimpan seluruh riwayat satu file (jika kita tidak memperhitungkan segala komplikasi dengan penggantian nama di sini). Ini berarti bahwa ada area operasi yang berbeda di mana Git akan lebih cepat daripada Mercurial, semua hal lain dianggap sama (seperti penggabungan, atau menunjukkan sejarah proyek), dan area di mana Mercurial akan lebih cepat daripada Git (seperti menerapkan tambalan, atau menunjukkan riwayat satu file).Masalah ini mungkin tidak penting bagi pengguna akhir.

Karena struktur catatan tetap dari struktur changelog Mercurial , komit di Mercurial hanya dapat memiliki hingga dua orang tua ; komit di Git dapat memiliki lebih dari dua orang tua (disebut "gurita bergabung"). Meskipun Anda (secara teori) dapat mengganti penggabungan gurita dengan serangkaian penggabungan dua induk, ini dapat menyebabkan komplikasi saat mengkonversi antara repositori Mercurial dan Git.

Sejauh yang saya tahu Mercurial tidak memiliki setara dengan tag beranotasi (objek tag) dari Git. Kasus khusus dari tag beranotasi adalah tag yang ditandatangani (dengan tanda tangan PGP / GPG); setara dalam Mercurial dapat dilakukan menggunakan GpgExtension , yang ekstensi sedang didistribusikan bersama dengan Mercurial. Anda tidak dapat menandai objek non-komit di Mercurial seperti yang Anda bisa di Git, tapi itu tidak terlalu penting, saya pikir (beberapa repositori git menggunakan gumpalan yang ditandai untuk mendistribusikan kunci PGP publik yang digunakan untuk memverifikasi tag yang ditandatangani).

Referensi: cabang dan tag

Dalam referensi Git (cabang, cabang dan tag pelacak jarak jauh) berada di luar DAG dari commit (sebagaimana mestinya). Referensi dalam refs/heads/namespace ( cabang lokal ) menunjuk ke commit, dan biasanya diperbarui oleh "git commit"; mereka menunjuk ke ujung (kepala) cabang, itu sebabnya nama seperti itu. Referensi dalam refs/remotes/<remotename>/namespace ( cabang pelacakan jarak jauh ) menunjuk untuk melakukan, mengikuti cabang di repositori jarak jauh <remotename>, dan diperbarui dengan "git fetch" atau yang setara. Referensi dalam refs/tags/namespace ( tag ) menunjuk biasanya untuk melakukan (tag ringan) atau objek tag (tag beranotasi dan bertanda tangan), dan tidak dimaksudkan untuk berubah.

Tag

Di Mercurial, Anda dapat memberikan nama tetap untuk direvisi menggunakan tag ; tag disimpan mirip dengan pola abaikan. Ini berarti bahwa tag yang terlihat secara global disimpan dalam .hgtagsfile yang dikendalikan revisi dalam repositori Anda. Itu memiliki dua konsekuensi: pertama, Mercurial harus menggunakan aturan khusus untuk file ini untuk mendapatkan daftar semua tag saat ini dan untuk memperbarui file tersebut (misalnya, ia membaca revisi terbaru dari file tersebut, saat ini tidak memeriksa versi); kedua, Anda harus melakukan perubahan pada file ini agar tag baru terlihat oleh pengguna lain / repositori lainnya (sejauh yang saya mengerti).

Mercurial juga mendukung tag lokal , disimpan di hg/localtags, yang tidak terlihat oleh orang lain (dan tentu saja tidak dapat ditransfer)

Dalam Git tag diperbaiki (konstan) bernama referensi ke objek lain (biasanya tag objek, yang pada gilirannya mengarah ke komit) disimpan dalam refs/tags/namespace. Secara default ketika mengambil atau mendorong satu set revisi, git secara otomatis mengambil atau mendorong tag yang mengarah ke revisi yang diambil atau didorong. Namun demikian, Anda dapat mengontrol sampai batas mana tag diambil atau didorong.

Git memperlakukan tag ringan (menunjuk langsung ke komit) dan tag beranotasi (menunjuk ke objek tag, yang berisi pesan tag yang secara opsional menyertakan tanda tangan PGP, yang pada gilirannya mengarah ke komit) sedikit berbeda, misalnya secara default hanya menganggap tag beranotasi ketika menggambarkan berkomitmen menggunakan "git mendeskripsikan".

Git tidak memiliki tag lokal yang setara dengan Mercurial. Namun demikian git best practices merekomendasikan untuk menyiapkan repositori telanjang publik yang terpisah, tempat Anda mendorong perubahan siap, dan dari mana orang lain mengkloning dan mengambil. Ini berarti bahwa tag (dan cabang) yang tidak Anda push, bersifat pribadi untuk repositori Anda. Di sisi lain Anda juga dapat menggunakan namespace selain heads, remotesatau tags, misalnya local-tagsuntuk tag lokal.

Pendapat pribadi: Menurut saya, tag harus berada di luar grafik revisi, karena merupakan eksternal dari itu (mereka adalah penunjuk ke grafik revisi). Tag harus bukan versi, tetapi dapat ditransfer. Pilihan Mercurial untuk menggunakan mekanisme yang mirip dengan yang digunakan untuk mengabaikan file, berarti bahwa ia harus memperlakukan .hgtagssecara khusus (file in-tree dapat ditransfer, tetapi biasanya ini berversi), atau memiliki tag yang hanya bersifat lokal ( .hg/localtagsbukan versi, tetapi tidak bisa dipindahtangankan).

Ranting

Di Git, cabang lokal (ujung cabang, atau kepala cabang) adalah referensi yang dinamai komit, tempat seseorang dapat menumbuhkan komit baru. Cabang juga dapat berarti garis pengembangan aktif, yaitu semua komit dapat dicapai dari ujung cabang. Cabang lokal berada di refs/heads/namespace, jadi mis. Nama cabang 'master' yang sepenuhnya memenuhi syarat adalah 'ref / head / master'.

Cabang saat ini di Git (artinya cabang yang dicek, dan cabang tempat komit baru akan dituju) adalah cabang yang direferensikan oleh referensi HEAD. Seseorang dapat memiliki KEPALA menunjuk langsung ke sebuah komit, daripada menjadi referensi simbolis; situasi berada di cabang tanpa nama anonim disebut HEAD terlepas ("cabang git" menunjukkan bahwa Anda menggunakan '(tanpa cabang)').

Di Mercurial ada cabang anonim (kepala cabang), dan orang dapat menggunakan bookmark (melalui ekstensi bookmark ). Cabang - cabang bookmark semacam itu murni lokal, dan nama-nama itu (hingga versi 1.6) tidak dapat ditransfer menggunakan Mercurial. Anda dapat menggunakan rsync atau scp untuk menyalin .hg/bookmarksfile ke repositori jarak jauh. Anda juga dapat menggunakan hg id -r <bookmark> <url>untuk mendapatkan id revisi dari ujung bookmark saat ini.

Karena 1.6 bookmark dapat didorong / ditarik. The BookmarksExtension halaman memiliki bagian tentang Kerja Dengan Remote Repositori . Ada perbedaan bahwa dalam nama bookmark Mercurial bersifat global , sedangkan definisi 'jarak jauh' di Git menjelaskan juga pemetaan nama cabang dari nama-nama dalam repositori jarak jauh ke nama cabang pelacakan jarak jauh lokal; misalnya refs/heads/*:refs/remotes/origin/*pemetaan berarti bahwa seseorang dapat menemukan keadaan cabang 'master' ('ref / head / master') di repositori jauh di cabang pelacakan jarak jauh 'asal / master' ('ref / remote / asal / master /').

Mercurial juga disebut cabang bernama , di mana nama cabang tertanam dalam komit (dalam changeset). Nama tersebut bersifat global (ditransfer saat mengambil). Nama-nama cabang dicatat secara permanen sebagai bagian dari metadata changeset. Dengan Mercurial modern Anda dapat menutup "cabang bernama" dan berhenti merekam nama cabang. Dalam mekanisme ini, tip cabang dihitung dengan cepat.

"Cabang bernama" Mercurial harusnya menurut saya disebut label komit saja, karena memang itulah namanya. Ada situasi di mana "cabang bernama" dapat memiliki banyak kiat (banyak komitmen tanpa anak), dan juga dapat terdiri dari beberapa bagian grafik revisi yang terpisah.

Tidak ada yang setara dengan "cabang tertanam" Mercurial di Git; selain itu filosofi Git adalah bahwa sementara seseorang dapat mengatakan bahwa cabang mencakup beberapa komit, itu tidak berarti bahwa komit adalah milik beberapa cabang.

Perhatikan bahwa dokumentasi Mercurial masih mengusulkan untuk menggunakan klon terpisah (repositori terpisah) setidaknya untuk cabang yang berumur panjang (cabang tunggal per alur kerja repositori), alias bercabang dengan kloning .

Cabang dalam mendorong

Mercurial secara default mendorong semua kepala . Jika Anda ingin mendorong satu cabang ( kepala tunggal ), Anda harus menentukan tip revisi cabang yang ingin Anda dorong. Anda dapat menentukan tip cabang dengan nomor revisi (lokal ke repositori), dengan pengidentifikasi revisi, dengan nama bookmark (lokal ke repositori, tidak dapat ditransfer), atau dengan nama cabang tertanam (bernama cabang).

Sejauh yang saya pahami, jika Anda mendorong serangkaian revisi yang berisi komit yang ditandai berada di beberapa "cabang bernama" dalam bahasa Mercurial, Anda akan memiliki "cabang bernama" ini di repositori yang Anda dorong. Ini berarti bahwa nama-nama cabang tertanam tersebut ("cabang bernama") bersifat global (sehubungan dengan klon repositori / proyek yang diberikan).

Secara default (tergantung pada push.defaultvariabel konfigurasi) "git push" atau "git push < remote >" Git akan mendorong cabang-cabang yang cocok , yaitu hanya cabang-cabang lokal yang memiliki padanannya yang sudah ada dalam repositori jarak jauh yang Anda dorong. Anda dapat menggunakan --allopsi untuk git-push ("git push --all") untuk mendorong semua cabang , Anda dapat menggunakan "git push < remote > < branch >" untuk mendorong cabang tunggal yang diberikan , dan Anda dapat menggunakan "git push < remote > KEPALA "untuk mendorong cabang saat ini .

Semua hal di atas mengasumsikan bahwa Git tidak mengkonfigurasi cabang mana yang harus didorong melalui remote.<remotename>.push variabel konfigurasi.

Cabang dalam mengambil

Catatan: di sini saya menggunakan terminologi Git di mana "fetch" berarti mengunduh perubahan dari repositori jarak jauh tanpa mengintegrasikan perubahan itu dengan pekerjaan lokal. Inilah yang dilakukan " git fetch" dan " hg pull".

Jika saya memahaminya dengan benar, secara default Mercurial mengambil semua kepala dari repositori jarak jauh, tetapi Anda dapat menentukan cabang yang akan diambil melalui " hg pull --rev <rev> <url>" atau " hg pull <url>#<rev>" untuk mendapatkan cabang tunggal . Anda dapat menentukan <rev> menggunakan pengidentifikasi revisi, nama "bernama cabang" (cabang tertanam di changelog), atau nama bookmark. Namun nama bookmark (setidaknya saat ini) tidak dapat ditransfer. Semua revisi "cabang bernama" yang Anda miliki menjadi bagian untuk ditransfer. "hg pull" menyimpan ujung cabang yang diambilnya sebagai kepala tanpa nama, tanpa nama.

Di Git secara default (untuk remote 'origin' dibuat oleh "git clone", dan untuk remote yang dibuat menggunakan "git remote add") " git fetch" (atau " git fetch <remote>") mendapatkan semua cabang dari repositori jarak jauh (dari refs/heads/namespace), dan menyimpannya di refs/remotes/namespace. Ini berarti misalnya cabang yang bernama 'master' (nama lengkap: 'ref / head / master') di 'asal' jauh akan disimpan (disimpan) sebagai cabang pelacakan jarak jauh 'asal / master' (nama lengkap: 'ref / remote / asal / master ').

Anda dapat mengambil cabang tunggal di Git dengan menggunakan git fetch <remote> <branch>- Git akan menyimpan cabang yang diminta di FETCH_HEAD, yang mirip dengan kepala Mercurial tanpa nama.

Itu hanyalah contoh kasus default sintaks Git refspec yang kuat : dengan refspec Anda dapat menentukan dan / atau mengkonfigurasi cabang mana yang ingin diambil, dan tempat menyimpannya. Misalnya kasus "ambil semua cabang" default diwakili oleh '+ ref / kepala / *: refs / remote / asal / *' wildcard refspec, dan "ambil cabang tunggal" adalah singkatan untuk 'ref / kepala / <branch>:' . Refspec digunakan untuk memetakan nama cabang (ref) dalam repositori jarak jauh ke nama referensi lokal. Tetapi Anda tidak perlu tahu (banyak) tentang refspec untuk dapat bekerja secara efektif dengan Git (terutama berkat perintah "git remote").

Pendapat pribadi: Saya pribadi berpikir bahwa "cabang bernama" (dengan nama cabang tertanam dalam metadata changeset) di Mercurial adalah desain yang salah arah dengan namespace globalnya, terutama untuk sistem kontrol versi terdistribusi . Sebagai contoh, mari kita ambil contoh di mana Alice dan Bob memiliki "nama cabang" bernama 'for-joe' di repositori mereka, cabang-cabang yang tidak memiliki kesamaan. Namun dalam repositori Joe, kedua cabang itu akan diperlakukan secara salah sebagai satu cabang. Jadi, entah bagaimana, Anda membuat konvensi yang melindungi terhadap bentrokan nama cabang. Ini bukan masalah dengan Git, di mana dalam repositori Joe 'untuk-joe' cabang dari Alice akan menjadi 'alice / untuk-joe', dan dari Bob itu akan menjadi 'bob / untuk-joe'.

"Cabang penunjuk" Mercurial saat ini kekurangan mekanisme distribusi inti.

Perbedaan:
Area ini adalah salah satu perbedaan utama antara Mercurial dan Git, seperti yang dikatakan james woodyatt dan Steve Losh dalam jawaban mereka. Mercurial, secara default, menggunakan codelines ringan anonim, yang dalam terminologinya disebut "kepala". Git menggunakan cabang bernama ringan, dengan pemetaan injeksi untuk memetakan nama-nama cabang dalam repositori jarak jauh ke nama-nama cabang pelacakan jarak jauh. Git "memaksa" Anda untuk memberi nama cabang (well, dengan pengecualian cabang tunggal yang tidak disebutkan namanya, situasi yang disebut HEAD terpisah), tapi saya pikir ini bekerja lebih baik dengan alur kerja cabang-berat seperti alur kerja cabang topik, yang berarti banyak cabang dalam paradigma repositori tunggal.

Penamaan revisi

Di Git ada banyak cara penamaan revisi (dijelaskan misalnya dalam manual git rev-parse ):

  • Nama objek SHA1 lengkap (string heksadesimal 40-byte), atau substring sedemikian rupa sehingga unik dalam repositori
  • Nama referensi simbolis, misalnya 'master' (merujuk ke cabang 'master'), atau 'v1.5.0' (merujuk ke tag), atau 'asal / depan' (merujuk ke cabang pelacakan jarak jauh)
  • ^Parameter suffix to revisi berarti induk pertama dari objek komit, ^nberarti induk ke-n dari komit gabungan. ~nParameter suffix to revisi berarti leluhur ke-11 dari komit dalam garis induk pertama lurus. Sufiks-sufiks itu dapat digabungkan, untuk membentuk specifier revisi mengikuti jalur dari referensi simbolis, misalnya 'pu ~ 3 ^ 2 ~ 3'
  • Output dari "git menggambarkan", yaitu tag terdekat, opsional diikuti oleh tanda hubung dan sejumlah komit, diikuti oleh tanda hubung, a 'g', dan nama objek disingkat, misalnya 'v1.6.5.1-75- g5bf8097 '.

Ada juga penentu revisi yang melibatkan reflog, tidak disebutkan di sini. Di Git setiap objek, baik itu komit, tag, pohon atau gumpalan memiliki pengidentifikasi SHA-1-nya; ada sintaks khusus seperti misalnya 'selanjutnya: Dokumentasi' atau 'berikutnya: README' untuk merujuk ke pohon (direktori) atau gumpalan (isi file) pada revisi yang ditentukan.

Mercurial juga memiliki banyak cara penamaan perubahan (dijelaskan misalnya dalam halaman hg ):

  • Bilangan bulat biasa diperlakukan sebagai angka revisi. Kita harus ingat bahwa angka revisi adalah lokal untuk repositori yang diberikan ; di repositori lain mereka bisa berbeda.
  • Bilangan bulat negatif diperlakukan sebagai offset berurutan dari ujung, dengan -1 menunjukkan ujung, -2 menunjukkan revisi sebelum ujung, dan sebagainya. Mereka juga lokal untuk repositori.
  • Pengidentifikasi revisi unik (string heksadesimal 40 digit) atau awalan uniknya.
  • Nama tag (nama simbolis yang terkait dengan revisi yang diberikan), atau nama bookmark (dengan ekstensi: nama simbolis terkait dengan kepala yang diberikan, lokal ke repositori), atau "cabang bernama" (label komit; revisi diberikan oleh "cabang bernama" adalah tip (komitmen tanpa anak) dari semua komitmen dengan label komit yang diberikan, dengan nomor revisi terbesar jika ada lebih dari satu tip seperti itu)
  • "Tip" nama yang dicadangkan adalah tag khusus yang selalu mengidentifikasi revisi terbaru.
  • Nama yang dicadangkan "null" menunjukkan revisi nol.
  • Nama yang dicadangkan "." menunjukkan induk direktori kerja.

Perbedaan
Seperti yang Anda lihat membandingkan daftar di atas Mercurial menawarkan angka revisi, lokal ke repositori, sedangkan Git tidak. Di sisi lain Mercurial menawarkan offset relatif hanya dari 'tip' (cabang saat ini), yang bersifat lokal untuk repositori (setidaknya tanpa ParentrevspecExtension ), sementara Git memungkinkan untuk menentukan komit berikut dari tip apa pun.

Revisi terbaru bernama HEAD in Git, dan "tip" dalam Mercurial; tidak ada revisi nol di Git. Baik Mercurial dan Git dapat memiliki banyak root (dapat memiliki lebih dari satu komitmen tanpa orangtua; ini biasanya merupakan hasil dari bergabungnya proyek yang sebelumnya terpisah).

Lihat juga: Berbagai jenis artikel penentu revisi di Blog Elia (berita baru).

Pendapat pribadi: Saya pikir angka revisi terlalu dibesar-besarkan (setidaknya untuk pengembangan terdistribusi dan / atau sejarah nonlinear / bercabang). Pertama, untuk sistem kontrol versi terdistribusi, mereka harus bersifat lokal untuk repositori, atau mengharuskan memperlakukan beberapa repositori dengan cara khusus sebagai otoritas penomoran pusat. Kedua, proyek-proyek yang lebih besar, dengan sejarah yang lebih panjang, dapat memiliki sejumlah revisi dalam rentang 5 digit sehingga mereka hanya menawarkan sedikit keuntungan dibandingkan dengan disingkat menjadi 6-7 pengenal revisi karakter, dan menyiratkan pemesanan ketat sementara revisi hanya dipesan sebagian (maksud saya di sini adalah bahwa revisi n dan n +1 tidak perlu menjadi orang tua dan anak).

Rentang revisi

Dalam rentang revisi Git bersifat topologis . A..BSintaks yang umum dilihat , yang untuk sejarah linier berarti rentang revisi mulai dari A (tetapi tidak termasuk A), dan berakhir di B (yaitu rentang terbuka dari bawah ), adalah singkatan ("gula sintaksis") untuk ^A B, yang untuk perintah traverse sejarah berarti semua berkomitmen dapat dijangkau dari B, tidak termasuk yang dapat dicapai dari A. Ini berarti bahwa perilaku A..Brentang sepenuhnya dapat diprediksi (dan cukup berguna) bahkan jika A bukan merupakan leluhur B: A..Bberarti kemudian rentang revisi dari leluhur bersama A dan B (basis gabungan ) untuk revisi B.

Dalam rentang revisi Mercurial didasarkan pada kisaran angka revisi . Rentang ditentukan menggunakan A:Bsintaks, dan bertentangan dengan rentang Git bertindak sebagai interval tertutup . Juga rentang B: A adalah kisaran A: B dalam urutan terbalik, yang tidak terjadi pada Git (tetapi lihat catatan di bawah ini tentang A...Bsintaks). Tetapi kesederhanaan seperti itu datang dengan harga: rentang revisi A: B masuk akal hanya jika A adalah leluhur B atau sebaliknya, yaitu dengan sejarah linier; jika tidak (saya rasa itu) kisaran tidak dapat diprediksi, dan hasilnya adalah lokal untuk repositori (karena angka revisi adalah lokal ke repositori).

Ini diperbaiki dengan Mercurial 1.6, yang memiliki rentang revisi topologi baru , di mana 'A..B' (atau 'A :: B') dipahami sebagai sekumpulan perubahan yang keduanya merupakan keturunan X dan leluhur Y. Ini adalah , Saya kira, setara dengan '--ancestry-path A..B' di Git.

Git juga memiliki notasi A...Buntuk perbedaan revisi simetris; itu berarti A B --not $(git merge-base A B), yang berarti semua komit dapat dicapai baik dari A atau B, tetapi tidak termasuk semua komit yang dapat dicapai dari keduanya (dapat dicapai dari leluhur bersama).

Ganti nama

Mercurial menggunakan pelacakan nama untuk berurusan dengan nama file. Ini berarti bahwa informasi tentang fakta bahwa suatu file diganti namanya disimpan pada waktu yang ditentukan; di Mercurial, informasi ini disimpan dalam bentuk "enhanced diff" dalam metadata filelog (file revlog). Konsekuensi dari ini adalah bahwa Anda harus menggunakan hg rename/ hg mv... atau Anda harus ingat untuk menjalankan hg addremoveuntuk melakukan deteksi nama berdasarkan kesamaan.

Git unik di antara sistem kontrol versi karena menggunakan deteksi nama untuk menangani nama file. Ini berarti fakta bahwa file diubah namanya terdeteksi pada saat diperlukan: ketika melakukan penggabungan, atau ketika menampilkan diff (jika diminta / dikonfigurasi). Ini memiliki keuntungan bahwa mengubah nama algoritma deteksi dapat ditingkatkan, dan tidak dibekukan pada saat melakukan.

Baik Git dan Mercurial memerlukan --followopsi menggunakan untuk mengikuti penggantian nama saat menampilkan riwayat satu file. Keduanya dapat mengikuti penggantian nama saat menampilkan riwayat baris-bijaksana dari file di git blame/ hg annotate.

Di Git, git blameperintah ini dapat mengikuti pergerakan kode, juga memindahkan (atau menyalin) kode dari satu file ke yang lain, bahkan jika perpindahan kode bukan bagian dari penggantian nama file yang sehat. Sejauh yang saya tahu fitur ini unik untuk Git (pada saat penulisan, Oktober 2009).

Protokol jaringan

Baik Mercurial dan Git memiliki dukungan untuk mengambil dari dan mendorong ke repositori pada sistem file yang sama, di mana URL repositori hanyalah jalur sistem file ke repositori. Keduanya juga memiliki dukungan untuk mengambil dari file bundel .

Dukungan Mercurial mengambil dan mendorong melalui SSH dan melalui protokol HTTP. Untuk SSH kita membutuhkan akun shell yang dapat diakses di mesin tujuan dan salinan hg diinstal / tersedia. Untuk akses HTTP, hg-serveatau menjalankan skrip Mercurial CGI diperlukan, dan Mercurial perlu diinstal pada mesin server.

Git mendukung dua jenis protokol yang digunakan untuk mengakses repositori jarak jauh:

  • Protokol "pintar" , yang mencakup akses melalui SSH dan melalui custom git: // protocol (by git-daemon), mengharuskan git diinstal pada server. Pertukaran dalam protokol-protokol tersebut terdiri dari klien dan server yang bernegosiasi tentang objek apa yang mereka miliki bersama, dan kemudian menghasilkan dan mengirim paketfile. Modern Git termasuk dukungan untuk protokol HTTP "pintar".
  • Protokol "bodoh" , yang meliputi HTTP dan FTP (hanya untuk mengambil), dan HTTPS (untuk mendorong melalui WebDAV), tidak memerlukan git yang diinstal pada server, tetapi protokol tersebut mengharuskan repositori berisi informasi tambahan yang dihasilkan oleh git update-server-info(biasanya dijalankan dari hook ). Pertukaran terdiri dari klien yang menjalankan rantai komit dan mengunduh objek dan paket yang longgar sesuai kebutuhan. Kelemahannya adalah ia mengunduh lebih dari yang dibutuhkan secara ketat (mis. Dalam kasus sudut ketika hanya ada satu paket file yang akan diunduh secara keseluruhan bahkan ketika mengambil hanya beberapa revisi), dan itu dapat membutuhkan banyak koneksi untuk menyelesaikannya.

Extending: scriptability vs extensions (plugins)

Mercurial diimplementasikan dalam Python , dengan beberapa kode inti ditulis dalam C untuk kinerja. Ini menyediakan API untuk menulis ekstensi (plugin) sebagai cara menambahkan fitur tambahan. Beberapa fungsi, seperti "cabang bookmark" atau menandatangani revisi, disediakan dalam ekstensi yang didistribusikan bersama Mercurial dan mengharuskan untuk mengaktifkannya.

Git diimplementasikan dalam skrip C , Perl dan shell . Git menyediakan banyak perintah level rendah ( pipa ledeng ) yang cocok untuk digunakan dalam skrip. Cara biasa untuk memperkenalkan fitur baru adalah dengan menuliskannya sebagai Perl atau skrip shell, dan ketika antarmuka pengguna menstabilkan penulisan ulang dalam C untuk kinerja, portabilitas, dan dalam kasus skrip shell menghindari kasus sudut (prosedur ini disebut builtinification ).

Git mengandalkan dan dibangun di sekitar format [repositori] dan protokol [jaringan]. Alih-alih binding bahasa ada (sebagian atau lengkap) implementasi ulang Git dalam bahasa lain (beberapa di antaranya adalah implementasi ulang sebagian, dan sebagian pembungkus di sekitar perintah git): JGit (Jawa, digunakan oleh EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).


TL; DR

Jakub Narębski
sumber
32
Apa yang dapat ditambahkan adalah bahwa hg berusaha sangat keras untuk mencegah penulisan ulang riwayat (hanya dapat dilakukan dengan ekstensi: mq, histedit, rebase), sementara git melakukannya di luar kotak (dan sepertinya bagian dari komunitas bahkan mendorongnya).
tonfa
80
Saya pikir "riwayat penulisan ulang" tidak perlu terdengar negatif. Yang saya dorong di git adalah orang-orang mempertimbangkan sejarah yang mereka terbitkan. Orang lain perlu mengkonsumsi sejarah itu. Tidak seorang pun (bahkan Anda) yang tertarik dengan semua komitmen "oops, forget a file" Anda. Juga tidak ada yang peduli tentang rangkaian penggabungan masuk yang Anda lalui saat Anda melacak cabang hulu saat mengerjakan fitur baru. Hal-hal semacam itu membuat sejarah (dan alat-alat terkait) jauh lebih sulit untuk dipahami dan tidak memberikan nilai.
Dustin
5
@ Yakub: cabang bernama adalah sesuatu yang tidak ada di git. Ini hanya sebuah bidang dalam deskripsi cset (dan itu adalah bagian dari sejarah, jadi itu tidak berubah kecuali Anda mengubah hash, dll.). Sesuatu seperti cabang git adalah bookmark ("kepala bernama") tetapi mereka saat ini tidak dapat ditransfer dari jauh (Anda tidak mengimpor bookmark jarak jauh saat menarik). stevelosh.com/blog/entry/2009/8/30/… menjelaskannya dengan sangat baik.
tonfa
28
"Mercurial awalnya didukung hanya satu cabang per alur kerja repositori, dan itu menunjukkan." Eh, tidak. Mercurial awalnya tidak mendukung cabang bernama , tetapi Anda selalu dapat memiliki cabang anonim sebanyak yang diinginkan hati Anda dalam satu repo. Bandingkan dengan git, yang membuat percabangan anonim menjadi sangat menyakitkan. Anda harus memikirkan nama untuk setiap cabang kecil jika Anda ingin menyelesaikan sesuatu (dan menghindari pengumpulan sampah kerja Anda).
Steve Losh
17
@SteveLosh: Anda tampaknya berpikir memiliki banyak cabang anonim di Mercurial adalah hal yang baik, tetapi bagi saya itu tampak mengerikan. Bagaimana Anda membedakan mereka semua? Dan Anda tampaknya berpikir menamai cabang di Git adalah beberapa kesulitan besar, tetapi jika Anda memiliki tujuan untuk membuat cabang maka Anda memiliki nama yang sudah jadi. Jika Anda tidak memiliki tujuan, maka jangan bercabang. Saya gagal melihat bagaimana Mercurial menawarkan keuntungan apa pun di sini. Saya hanya melihat rasa sakit dan kebingungan.
iconoclast
57

Saya pikir Anda bisa merasakan apa sistem yang serupa atau berbeda dengan menangkap kedua video:

Linus Torvalds di Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan di Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )

Keduanya sangat mirip dalam desain tetapi sangat berbeda dalam implementasinya.

Saya menggunakan Mercurial. Sejauh yang saya mengerti Git, satu hal utama git berbeda adalah bahwa ia melacak isi file, bukan file itu sendiri. Linus mengatakan bahwa jika Anda memindahkan suatu fungsi dari satu file ke file lainnya, Git akan memberi tahu Anda sejarah fungsi tunggal tersebut di seluruh langkah.

Mereka juga mengatakan bahwa git lebih lambat daripada HTTP tetapi memiliki protokol jaringan dan server sendiri.

Git bekerja lebih baik sebagai klien tebal SVN daripada Mercurial. Anda dapat menarik dan mendorong server SVN. Fungsi ini masih dalam pengembangan di Mercurial

Baik Mercurial dan Git memiliki solusi hosting web yang sangat bagus (BitBucket dan GitHub), tetapi Google Code hanya mendukung Mercurial. Ngomong-ngomong, mereka memiliki perbandingan Mercurial dan Git yang sangat rinci yang mereka lakukan untuk memutuskan mana yang akan didukung ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Ini memiliki banyak info bagus.

Artemb
sumber
8
Saya sarankan membaca semua komentar di halaman kode google itu. Informasi itu terasa agak bias dan tidak cocok dengan pengalaman saya dengan baik. Saya suka hg, dan menggunakannya secara luas selama kurang lebih satu tahun. Saya menggunakan git hampir secara eksklusif sekarang. Ada hal-hal yang perlu saya selesaikan bahwa git menjadi mudah dan hg membuat hampir tidak mungkin (meskipun beberapa orang suka menyebutnya dengan "komplikasi.") Basic git semudah dasar hg.
Dustin
11
Dustin, mungkin daftar beberapa kasus "mudah git, hg tidak begitu banyak"?
Gregg Lind
1
@ Knitt tidak, tidak. Terutama karena akan merepotkan bagi mereka untuk menerapkannya karena git tidak memiliki protokol http pintar (sebagian besar front-end Google berbasis http).
tonfa
2
@tonfa: Protokol HTTP pintar untuk Git saat ini sedang dikembangkan (seperti pada: ada tambalan di milis git, dan mereka ada di 'pu' = cabang pembaruan yang diusulkan dalam repositori git.git).
Jakub Narębski
4
Sampai sekarang Google Code mendukung Git juga.
Andrej Kirejeŭ
30

Saya menulis entri blog tentang model percabangan Mercurial beberapa waktu lalu, dan menyertakan perbandingan dengan model percabangan git. Mungkin Anda akan menganggapnya menarik: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/

Steve Losh
sumber
@Steve Losh: Saya ingin mengomentari entri blog ini (tentang cabang yang tidak disebutkan namanya alias terpisah KEPALA, dan tentang git-fetch mengambil semua cabang, bukan satu), tapi saya mendapat 500 server error.
Jakub Narębski
1
@Jakub Narębski Saya yakin masalahnya adalah karakter non-ASCII dalam nama Anda. Saya cukup yakin saya mengalami masalah yang sama di situs lain dan ternyata Python Askimet mengikat pada Unicode. Aku akan melihatnya.
Steve Losh
@Steve Losh: Terima kasih atas informasinya, setelah "unidecoding" nama saya, saya dapat memposting komentar. Deskripsi yang sangat baik bercabang di Mercurial (tapi saya masih berpikir itu lebih rendah ;-))
Jakub Narębski
@SteveLosh Saya mendorong Anda untuk memperluas jawaban ini ke ulasan yang lebih lengkap tentang mercurial. Saat ini, jawaban teratas sayangnya sebagian besar adalah iklan untuk git karena penulisnya belum menggunakan mercurial secara luas dan tidak mengerti cara menggunakannya secara efektif. Akan lebih baik untuk jawaban lain untuk memberikan sudut pandang lincah, sehingga untuk berbicara.
Warren Dew
25

Saya menggunakan keduanya secara teratur. Perbedaan fungsional utama adalah dalam cara Git dan Mercurial menamai cabang dalam repositori. Dengan Mercurial, nama cabang diklon dan ditarik bersama dengan perubahannya. Saat Anda menambahkan perubahan ke cabang baru di Mercurial dan mendorong ke repositori lain, nama cabang didorong secara bersamaan. Jadi, nama-nama cabang lebih atau kurang global di Mercurial, dan Anda harus menggunakan ekstensi Bookmark untuk memiliki nama ringan khusus lokal (jika Anda menginginkannya; Mercurial, secara default, menggunakan codeline ringan anonim, yang dalam terminologinya adalah disebut "kepala"). Di Git, nama-nama cabang dan pemetaan injeksi mereka ke cabang-cabang terpencil disimpan secara lokal dan Anda harus mengelolanya secara eksplisit, yang berarti mengetahui cara melakukannya.

Seperti yang akan dicatat orang lain di sini, ada banyak perbedaan kecil. Masalahnya dengan cabang adalah pembeda besar.

james woodyatt
sumber
2
Lihat juga posting ini untuk penjelasan yang baik tentang empat jenis cabang di Mercurial: stevelosh.com/blog/entry/2009/8/30/…
Martin Geisler
19

Lihatlah Git vs Mercurial: Silakan Bersantai posting blog oleh Patrick Thomson, di mana ia menulis:
Git adalah MacGyver , Mercurial adalah James Bond

Perhatikan bahwa posting blog ini adalah dari 7 Agustus 2008, dan kedua SCM meningkat banyak sejak itu.

Jakub Narębski
sumber
11

Mercurial hampir sepenuhnya ditulis dalam python. Inti Git ditulis dalam C (dan harus lebih cepat, daripada Mercurial) dan alat yang ditulis dalam sh, perl, tcl dan menggunakan utilitas GNU standar. Oleh karena itu perlu membawa semua utils dan interpreter ini ke sistem yang tidak mengandungnya (misalnya Windows).

Keduanya mendukung bekerja dengan SVN, meskipun dukungan AFAIK svn rusak untuk git di Windows (mungkin saya hanya sial / lumpuh, siapa tahu). Ada juga ekstensi yang memungkinkan untuk beroperasi antara git dan Mercurial.

Mercurial memiliki integrasi Visual Studio yang bagus . Terakhir kali saya memeriksa, plugin untuk Git berfungsi tetapi sangat lambat.

Mereka set perintah dasar sangat mirip (init, clone, tambah, status, komit, dorong, tarik dll). Jadi, alur kerja dasarnya akan sama. Juga, ada klien seperti TortoiseSVN untuk keduanya.

Ekstensi untuk Mercurial dapat ditulis dengan python (tidak mengherankan!) Dan untuk git mereka dapat ditulis dalam bentuk yang dapat dieksekusi (biner yang dapat dieksekusi, skrip shell, dll.). Beberapa ekstensi sangat kuat, seperti git bisect.

elder_george
sumber
9
Inti merkuri ditulis dalam C juga FYI (tapi mungkin inti lebih kecil dari git).
tonfa
1
Saya menggunakan git-svn di Windows tanpa masalah. Itu menggunakan Cygwin (satu-satunya cara yang tepat untuk menggunakan git di Windows jika Anda bertanya kepada saya). Tidak dapat berbicara untuk msysgit.
Dan Moulding
@Dan Moulding: Ya, saya pernah mengalami masalah dengan msysgit. Mungkin perlu mencoba port cygwin (saya punya pengalaman buruk menggunakan cygwin sebelumnya, jadi saya menghindarinya). Terima kasih atas sarannya!
elder_george
Saya pribadi tidak suka intrusi cygwin ke dalam registri untuk menyimpan data pengguna. Ini adalah PITA untuk menjalankannya dari kunci USB dan menyimpan salinan lokal c: \ drive disinkronkan ketika saya ingin menjalankan lebih cepat daripada kunci USB saya bisa pergi. : - /
Chris K
1
Saya menggunakan plugin Git untuk Visual Studio yang disebutkan di atas, dan kinerja versi saat ini baik. Itu keluar ke alat baris perintah untuk melakukan pekerjaan, jadi saya tidak berpikir bahwa itu akan secara signifikan kehilangan kinerja pada proyek-proyek besar.
Stuart Ellis
11

Jika Anda membutuhkan dukungan Windows yang baik, Anda mungkin lebih suka Mercurial. TortoiseHg (plugin Windows explorer) mengelola untuk menawarkan antarmuka grafis yang mudah digunakan ke alat yang agak rumit. Sebagai status di sini, Anda juga akan memiliki plugin Visual Studio . Namun, terakhir kali saya mencoba, antarmuka SVN tidak berfungsi dengan baik di Windows.

Jika Anda tidak keberatan dengan antarmuka baris perintah, saya akan merekomendasikan Git. Bukan karena alasan teknis tetapi karena alasan strategis. Tingkat adopsi git jauh lebih tinggi. Lihat saja berapa banyak proyek open source terkenal yang beralih dari cvs / svn ke Mercurial dan berapa banyak yang beralih ke Git. Lihat berapa banyak penyedia hosting kode / proyek yang dapat Anda temukan dengan dukungan git dibandingkan dengan hosting Mercurial.

Eric Darchis
sumber
Ada juga TortoiseGit, jika Anda tidak suka menggunakan baris perintah. (Tapi itu membutuhkan msysgit untuk diinstal.)
Ben James
2
Perusahaan kami akhirnya memilih git karena dukungannya yang luar biasa pada Windows - lihat Git Extensions . Saya bias karena saya sekarang menjadi kontributor, tetapi saya tidak ketika kami mulai menggunakannya.
Jacob Stanley
11

Setelah membaca semua yang Mercurial lebih mudah (yang saya masih percaya, setelah semua komunitas internet berpendapat), ketika saya mulai bekerja dengan Git dan Mercurial saya merasa Git relatif lebih mudah bagi saya untuk beradaptasi (saya mulai dengan Mercurial dengan TortoiseHg) ketika bekerja dari baris perintah, terutama karena perintah git dinamai sesuai dengan saya dan jumlahnya lebih sedikit. Mercurial memiliki penamaan yang berbeda untuk setiap perintah yang melakukan pekerjaan yang berbeda, sedangkan perintah Git dapat multiguna sesuai dengan situasi (misalnya,checkout). Sementara Git lebih sulit saat itu, sekarang perbedaannya hampir tidak substansial. YMMV .. Dengan klien GUI yang baik seperti TortoiseHg, benar itu jauh lebih mudah untuk bekerja dengan Mercurial dan saya tidak harus mengingat perintah yang sedikit membingungkan. Saya tidak akan menjelaskan secara terperinci bagaimana setiap perintah untuk tindakan yang sama bervariasi, tetapi di sini ada dua daftar lengkap: 1 dari situs Mercurial sendiri danke-2 dari wikiv .

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Git menyimpan catatan setiap versi file yang dilakukan secara internal, sementara Hg menyimpan hanya perubahan yang dapat memiliki jejak yang lebih kecil. Git membuatnya lebih mudah untuk mengubah sejarah dibandingkan dengan Hg, tetapi sekali lagi itu fitur benci-itu-atau-cinta-itu. Saya suka Hg untuk mantan dan Git untuk yang terakhir.

Apa yang saya lewatkan di Hg adalah fitur submodule dari Git. Hg memiliki subrepo tapi itu bukan submitule Git.

Ekosistem di sekitar keduanya juga dapat memengaruhi pilihan seseorang: Git harus lebih populer (tapi itu sepele), Git memiliki GitHub sementara Mercurial memiliki BitBucket , Mercurial memiliki TortoiseHg yang belum pernah saya lihat sama baiknya dengan Git.

Masing-masing memiliki kelebihan dan kekurangan, dengan salah satu dari mereka Anda tidak akan kehilangan.

nawfal
sumber
8

Lihat pos Scott Chacon dari waktu yang lalu.

Saya pikir git memiliki reputasi sebagai "lebih rumit", meskipun dalam pengalaman saya itu tidak lebih rumit dari yang seharusnya. IMO, model git adalah cara lebih mudah untuk dipahami (tag berisi komit (dan pointer ke nol atau lebih komit induk) mengandung pohon berisi gumpalan dan pohon lainnya ... selesai).

Bukan hanya pengalaman saya bahwa git tidak lebih membingungkan daripada lincah. Saya akan merekomendasikan lagi membaca posting blog ini dari Scott Chacon tentang masalah ini.

Dustin
sumber
1
Model Mercurial sebenarnya hampir identik: poin changelog ke manifes poin ke file revisi / gumpalan ... dilakukan Jika Anda membandingkan format pada disk Anda mungkin tidak memperhitungkan file paket yang lebih sulit dijelaskan daripada format revlog sederhana dari hg.
tonfa
Nah, model yang disederhanakan itu mengabaikan penandaan yang secara umum dianggap clunkier dalam hg (walaupun saya berpendapat bahwa tag git agak membingungkan karena tidak membuat objek tag secara default). Format on-disk sangat mahal untuk kedua proyek yang memiliki sejarah banyak nama file.
Dustin
1
Saya tidak berpikir model mengabaikan penandaan: penandaan adalah sepele di Mercurial - seperti yang Anda tahu, itu hanya sebuah file yang memberi nama pada hash SHA-1. Tidak ada dugaan bagaimana tag mengalir di dalam sistem: mereka bergerak seiring dengan dorongan dan tarikan. Dan jika ada konflik tag, maka itu juga sepele untuk menyelesaikannya: Anda menyelesaikannya seperti konflik lainnya. Bagaimanapun, itu hanya satu baris dalam file teks. Saya pikir kesederhanaan model ini adalah fitur yang sangat bagus.
Martin Geisler
Dustin: Ya, pengguna sering bingung dengan kenyataan bahwa Anda tidak dapat melihat tag 1.0 .hgtagsketika Anda telah memeriksa revisi 1.0. Namun, Anda tidak perlu mencari ke dalam .hgtagsdan Anda akan menemukan bahwa hg tagsmasih mencantumkan semua tag. Lebih jauh lagi, perilaku ini merupakan konsekuensi sederhana dari penyimpanan tag dalam file yang dikendalikan versi - lagi-lagi model ini mudah dipahami dan sangat dapat diprediksi .
Martin Geisler
1
Martin Geisler Saya berpendapat bahwa aturan untuk tag di Mercurial, diperlukan karena menggunakan file versi-terkontrol untuk transportasi, dengan lapisan pada aturan khusus untuk membuat tag tidak berversi, sama sekali tidak mudah dipahami.
Jakub Narębski
5

Saya telah menggunakan Git selama sedikit lebih dari setahun di pekerjaan saya saat ini, dan sebelumnya, menggunakan Mercurial selama lebih dari setahun di pekerjaan saya sebelumnya. Saya akan memberikan evaluasi dari sudut pandang pengguna.

Pertama, keduanya adalah sistem kontrol versi terdistribusi. Sistem kontrol versi terdistribusi membutuhkan perubahan pola pikir dari sistem kontrol versi tradisional, tetapi sebenarnya bekerja jauh lebih baik dalam banyak hal begitu orang memahaminya. Untuk alasan ini, saya menganggap Git dan Mercurial jauh lebih unggul daripada Subversion, Perforce, dll. Perbedaan antara sistem kontrol versi terdistribusi dan sistem kontrol versi tradisional jauh lebih besar daripada perbedaan antara Git dan Mercurial.

Namun, ada juga perbedaan signifikan antara Git dan Mercurial yang membuat masing-masing lebih cocok untuk subset kasus penggunaannya sendiri.

Mercurial lebih mudah dipelajari. Saya sampai pada titik di mana saya jarang harus merujuk pada dokumentasi atau catatan setelah beberapa minggu menggunakan Mercurial; Saya masih harus merujuk catatan saya secara teratur dengan Git, bahkan setelah menggunakannya selama satu tahun. Git jauh lebih rumit.

Ini sebagian karena Mercurial hanyalah pembersih biasa. Anda jarang harus bercabang secara manual di Mercurial; Mercurial akan membuat cabang anonim secara otomatis untuk Anda jika dan ketika Anda membutuhkannya. Nomenklatur mercurial lebih intuitif; Anda tidak perlu khawatir tentang perbedaan antara "ambil" dan "tarik" seperti yang Anda lakukan dengan Git. Mercurial sedikit kurang buggy. Ada masalah sensitivitas case name file yang digunakan untuk menyebabkan masalah saat mendorong proyek lintas platform dengan Git dan Mercurial; ini diperbaiki di Mercurial beberapa waktu lalu sementara mereka belum diperbaiki di Git terakhir saya periksa. Anda dapat memberi tahu Mercurial tentang penggantian nama file; dengan Git, jika ia tidak mendeteksi penggantian nama secara otomatis - proposisi yang sangat hit atau miss dalam pengalaman saya - ganti nama tidak dapat dilacak sama sekali.

Alasan lain untuk komplikasi tambahan Git, bagaimanapun, adalah bahwa sebagian besar dibutuhkan untuk mendukung fitur dan kekuatan tambahan. Ya, itu lebih rumit untuk menangani percabangan di Git - tetapi di sisi lain, begitu Anda memiliki cabang, tidak terlalu sulit untuk melakukan hal-hal dengan cabang-cabang yang hampir mustahil di Mercurial. Cabang rebasing adalah salah satu dari hal-hal ini: Anda dapat memindahkan cabang Anda sehingga basisnya, alih-alih menjadi keadaan batang saat Anda bercabang, adalah keadaan batang sekarang; ini sangat menyederhanakan riwayat versi ketika ada banyak orang yang bekerja pada basis kode yang sama, karena masing-masing dorongan untuk trunk dapat dibuat tampak berurutan, daripada saling terkait. Demikian pula, jauh lebih mudah untuk menciutkan banyak komit di cabang Anda menjadi satu komit,

Pada akhirnya saya pikir pilihan antara Mercurial dan Git harus bergantung pada seberapa besar proyek kontrol versi Anda, diukur berdasarkan jumlah orang yang mengerjakannya secara bersamaan. Jika Anda memiliki sekelompok selusin atau lebih yang bekerja pada aplikasi web monolitik tunggal, misalnya, alat manajemen cabang Git yang lebih kuat akan membuatnya lebih cocok untuk proyek Anda. Di sisi lain, jika tim Anda mengembangkan sistem terdistribusi heterogen, dengan hanya satu atau dua pengembang yang mengerjakan satu komponen pada satu waktu, menggunakan repositori Mercurial untuk setiap proyek komponen akan memungkinkan pengembangan berjalan lebih lancar dengan lebih sedikit overhead manajemen repositori.

Intinya: jika Anda memiliki tim besar yang mengembangkan satu aplikasi besar, gunakan Git; jika aplikasi individual Anda kecil, dengan skala apa pun yang berasal dari jumlah tersebut dan bukan dari ukuran aplikasi semacam itu, gunakan Mercurial.

Warren Dew
sumber
4

Satu perbedaan yang sama sekali tidak terkait dengan DVCS sendiri:

Git tampaknya sangat populer di kalangan pengembang C. Git adalah repositori de-facto untuk Kernel Linux dan ini mungkin menjadi alasan mengapa ia sangat populer di kalangan pengembang C. Ini terutama berlaku bagi mereka yang memiliki kemewahan hanya bekerja di dunia Linux / Unix.

Pengembang Java tampaknya lebih menyukai Mercurial daripada Git. Mungkin ada dua alasan untuk itu: Pertama adalah bahwa sejumlah proyek Jawa yang sangat besar di-host di Mercurial, termasuk JDK itu sendiri. Lain adalah bahwa struktur dan dokumentasi yang bersih dari Mercurial menarik bagi orang-orang yang datang dari kamp Jawa sedangkan orang-orang seperti itu menemukan penamaan perintah git yang tidak konsisten dan kurang dalam dokumentasi Git. Saya tidak mengatakan itu sebenarnya benar, saya mengatakan orang sudah terbiasa dengan sesuatu dari habitat biasanya dan kemudian mereka cenderung memilih DVCS dari situ.

Pengembang python hampir secara eksklusif mendukung Mercurial, saya akan berasumsi. Sebenarnya tidak ada alasan rasional untuk itu selain fakta bahwa Mercurial didasarkan pada Python. (Saya menggunakan Mercurial juga dan saya benar-benar tidak mengerti mengapa orang-orang membuat keributan tentang bahasa implementasi DVCS. Saya tidak mengerti sepatah kata pun dari Python dan jika bukan karena fakta bahwa itu terdaftar di suatu tempat yang itu didasarkan pada Python maka saya tidak akan tahu).

Saya tidak berpikir Anda bisa mengatakan bahwa satu DVCS cocok dengan bahasa yang lebih baik daripada yang lain, jadi Anda tidak harus memilih itu. Tetapi pada kenyataannya orang memilih (sebagian) berdasarkan pada DVCS mana mereka paling terkena sebagai bagian dari komunitas mereka.

(tidak, saya tidak memiliki statistik penggunaan untuk mendukung klaim saya di atas .. itu semua berdasarkan pada subjektivitas saya sendiri)

peterh
sumber