Mengapa banyak proyek lebih suka "git rebase" daripada "git merge"?

69

Salah satu keuntungan menggunakan DVCS adalah alur kerja edit-commit-gabungan (lebih dari edit-gabungan-komit sering dipaksakan oleh CVCS). Mengizinkan setiap perubahan unik untuk dicatat dalam repositori independen dari penggabungan memastikan DAG secara akurat mencerminkan silsilah sebenarnya dari proyek.

Mengapa begitu banyak situs web berbicara tentang keinginan untuk "menghindari penggabungan komitmen"? Tidakkah menggabungkan pra-komitmen atau rebound pasca-penggabungan membuat lebih sulit untuk mengisolasi regresi, mengembalikan perubahan di masa lalu, dll?

Titik klarifikasi: Perilaku default untuk DVCS adalah membuat komit gabungan. Mengapa begitu banyak tempat berbicara tentang keinginan untuk melihat sejarah pengembangan linear yang menyembunyikan komitmen gabungan ini?

Jace Browning
sumber
18
Alat tidak selalu benar. Dan ketika mereka salah, oh nak, apakah mereka salah.
Oded
2
@Oded apakah Anda merujuk ke komit gabungan otomatis (seperti yang dibuat oleh git pull)? Saya bisa melihat mengapa itu bisa bermasalah, tetapi pertanyaan saya adalah tentang semua komitmen gabungan.
Jace Browning
duplikat yang mungkin dari Apakah Konflik Penggabungan yang Sering Dilakukan Tanda Masalah? "Penggabungan dan rebase harus menyebabkan konflik yang sama persis, untuk konflik inheren yang harus diselesaikan manusia (yaitu dua pengembang mengubah baris kode yang sama) ..."
Agas
Sebuah pemikiran yang saya miliki setelah memposting jawaban saya, bahwa IMO tidak persis cocok sebagai jawaban: git pull --rebase == svn up(longgar-sama dengan, tidak ketat-sama)
Izkata
di toko terpusat seperti SourceSafe, perubahan akan terus diperiksa dalam upaya yang berkelanjutan, tetapi begitu dataran tinggi yang stabil tercapai, kami akan memberi label semua file pada tanggal tertentu. Maka setidaknya Anda dapat menghubungkan bug ke sebelum atau sesudah versi ini dan itu, atau rebase- line.
Andyz Smith

Jawaban:

65

Orang ingin menghindari gabungan komitmen karena membuat log lebih cantik. Serius. Sepertinya log terpusat mereka tumbuh dengan, dan secara lokal mereka dapat melakukan semua perkembangan mereka dalam satu cabang. Tidak ada manfaat selain dari estetika itu, dan beberapa kelemahan selain yang Anda sebutkan, seperti membuatnya rawan konflik untuk menarik langsung dari seorang kolega tanpa melalui server "pusat".

Karl Bielefeldt
sumber
5
Anda adalah satu-satunya yang telah memahami pertanyaan saya dengan benar. Bagaimana saya bisa membuatnya lebih jelas?
Jace Browning
12
Mungkin ulangi menjadi "Apa manfaat dari sejarah pengembangan linear?"
Karl Bielefeldt
11
"Seringkali, Anda akan melakukan ini untuk memastikan komitmen Anda berlaku bersih pada cabang terpencil - mungkin dalam proyek yang Anda coba berkontribusi tetapi Anda tidak mempertahankannya. Dalam hal ini, Anda akan melakukan pekerjaan Anda di cabang dan kemudian rebase pekerjaan Anda ke asal / master ketika Anda siap untuk mengirimkan tambalan Anda ke proyek utama. Dengan begitu, pengelola tidak harus melakukan pekerjaan integrasi apa pun - hanya fast-forward atau clean apply. " git-scm.com/book/en/Git-Branching-Rebasing
Andyz Smith
12
Anda membuatnya terdengar seperti itu hanya kosmetik, tetapi sebenarnya praktis: jauh lebih mudah untuk memahami apa yang terjadi dalam sejarah linier daripada dari DAG yang rumit dengan garis-garis yang saling bersilangan dan bergabung.
Daniel Hershcovich
20
"Tidak ada manfaat selain dari estetika itu" - Saya tidak tahu tentang itu. Sangat sulit untuk memahami apa yang terjadi dalam sejarah Anda ketika sejarah Anda terlihat seperti papan sirkuit. (Dengan asumsi beberapa anggota tim, masing-masing memiliki cabang dan alur kerja masing-masing.)
Archagon
46

Dalam dua kata: git bisect

Sejarah linier memungkinkan Anda menentukan sumber bug yang sebenarnya.


Sebuah contoh. Ini adalah kode awal kami:

def bar(arg=None):
    pass

def foo():
    bar()

Cabang 1 melakukan beberapa refactoring sehingga argtidak berlaku lagi:

def bar():
    pass

def foo():
    bar()

Cabang 2 memiliki fitur baru yang perlu digunakan arg:

def bar(arg=None):
    pass

def foo():
    bar(arg=1)

Tidak akan ada konflik penggabungan, namun bug telah diperkenalkan. Untungnya, yang satu ini akan terjebak pada langkah kompilasi, tapi kami tidak selalu beruntung. Jika bug bermanifestasi sebagai perilaku tak terduga, dan bukan kesalahan kompilasi, kami mungkin tidak menemukannya selama satu atau dua minggu. Pada titik itu, git bisectuntuk menyelamatkan!

Oh sial. Inilah yang dilihatnya:

(master: green)
|             \_________________________
|                \                      \
(master: green)  (branch 1: green)     (branch 2: green)
|                 |                     |
|                 |                     |
(master/merge commit: green)            |
|                         ______________/
|                        /
(master/merge commit: red)
|
...days pass...
|
(master: red)

Jadi ketika kami mengirim git bisectuntuk menemukan komit yang merusak build, itu akan menunjukkan komit gabungan. Yah, itu sedikit membantu, tetapi pada dasarnya menunjuk pada paket komitmen, bukan satu pun. Semua leluhur berwarna hijau. Di sisi lain, dengan rebasing, Anda mendapatkan sejarah linier:

(master: green)
|
(master: green)
|
(all branch 1 commits: green)
|
(some branch 2 commits: green)
|
(branch 2 commit: red)
|
(remaining branch 2 commits: red)
|
...days pass...
|
(master: still red)

Sekarang, git bisectakan menunjukkan komit fitur yang tepat yang merusak build. Idealnya, pesan komit akan menjelaskan apa yang dimaksudkan dengan cukup baik untuk melakukan refactor lain dan segera memperbaiki bug.

Efeknya hanya diperparah dalam proyek-proyek besar ketika pengelola tidak menulis semua kode, sehingga mereka tidak selalu ingat mengapa komit yang diberikan dilakukan / untuk apa masing-masing cabang. Jadi menunjukkan dengan tepat komit (dan kemudian bisa memeriksa komit di sekitarnya) adalah bantuan besar.


Yang mengatakan, saya (saat ini) masih lebih suka bergabung. Memulihkan kembali ke cabang rilis akan memberi Anda riwayat linier untuk digunakan bersama git bisect, sambil mempertahankan riwayat sebenarnya untuk pekerjaan sehari-hari.

Izkata
sumber
2
Terima kasih atas penjelasannya. Bisakah Anda memperluas alasan Anda masih lebih suka bergabung? Saya tahu banyak orang lebih suka bergabung daripada rebasing dalam banyak situasi, tapi saya tidak pernah bisa mengerti mengapa.
Philip
@ Pilip Saya agak ragu untuk melakukannya, karena saya hanya menggunakan git selama beberapa bulan pada proyek pribadi kecil, tidak pernah dalam tim. Tetapi ketika melacak apa yang telah saya lakukan baru-baru ini, bisa melihat aliran komit di seluruh cabang gitk --allsangat berguna (terutama karena saya biasanya memiliki cabang 3-ish pada waktu tertentu, dan beralih di antara mereka setiap hari tergantung pada suasana hati saya di waktu).
Izkata
16
Tapi gabungannya adalah masalahnya, jadi Anda menginginkan gabungan komit sebagai bisecthasilnya. Cukup mudah untuk menemukan individu yang berkomitmen dengan blameatau berbeda bisectjika Anda ingin menggali lebih dalam. Dengan riwayat linier, penggabungan dilakukan dari buku, jadi Anda tidak bisa lagi mengatakan penggabungan yang buruk adalah masalahnya. Itu hanya terlihat seperti orang idiot yang menggunakan argumen yang tidak ada, terutama jika argumen itu dihapus beberapa komit sebelumnya. Mencoba mencari tahu mengapa dia melakukan itu jauh lebih sulit ketika Anda menghancurkan sejarah.
Karl Bielefeldt
1
Sangat tidak setuju dengan jawaban ini. Rebasing kadang-kadang merusak utilitas bisect. Kecuali untuk komit kepala rebase, komit dari rebase mungkin tidak bisa dijalankan. Contoh: Anda bercabang di A dan membuat B, C, D, seseorang mendorong E. Anda B dan C dan bekerja tetapi diubah pada E, Anda B dan C tidak dapat dielakkan atau dapat dijalankan dan tidak berfungsi. Kasus terbaik adalah Anda menyerah, kasus terburuk yang menurut Anda B atau C berisi masalah padahal kenyataannya adalah D.
Lan
4
@Izkata Mengapa Anda menggunakan dua bagian? Karena bug / kesalahan terjadi. Itu adalah kenyataan yang merendahkan. Mungkin "menyeret mouse ke kiri" bukan bagian dari daftar pengujian otomatis / manual sebelumnya dan sekarang kita perhatikan bahwa fitur itu rusak tetapi kita tahu itu berfungsi.
Lan
17

Singkatnya, karena penggabungan seringkali merupakan tempat lain untuk sesuatu yang salah, dan itu hanya perlu salah sekali untuk membuat orang sangat takut menghadapinya lagi (sekali digigit dua kali malu, jika Anda mau).

Jadi, katakanlah kita sedang mengerjakan Layar Manajemen Akun baru, dan ternyata ada bug yang ditemukan dalam alur kerja Akun Baru. OK, kami mengambil dua jalur terpisah - Anda menyelesaikan Manajemen Akun, dan saya memperbaiki bug dengan Akun Baru. Karena kami berdua berurusan dengan akun, kami telah bekerja dengan kode yang sangat mirip - mungkin kami bahkan harus menyesuaikan potongan kode yang sama.

Sekarang, pada saat ini kami memiliki dua versi perangkat lunak yang berbeda tetapi berfungsi penuh. Kami berdua menjalankan komit pada perubahan kami, kami berdua dengan patuh menguji kode kami, dan secara independen kami sangat yakin kami telah melakukan pekerjaan yang luar biasa. Sekarang apa?

Nah, ini waktunya untuk bergabung, tapi ... sial, apa yang terjadi sekarang? Kita bisa beralih dari dua set perangkat lunak yang berfungsi menjadi satu, perangkat lunak yang baru rusak dan menyatu, di mana Manajemen Akun Anda tidak berfungsi dan Akun Baru rusak dan saya bahkan tidak tahu apakah bug lama masih ada .

Mungkin perangkat lunak itu pintar dan dikatakan ada konflik dan bersikeras kami memberikannya panduan. Nah, sial - Saya duduk untuk melakukannya dan melihat Anda telah menambahkan beberapa kode kompleks yang saya tidak segera mengerti. Saya pikir itu bertentangan dengan perubahan yang saya buat ... Saya bertanya kepada Anda, dan ketika Anda sebentar Anda memeriksa dan Anda melihat kode saya bahwa Anda tidak mengerti. Salah satu atau kami berdua harus meluangkan waktu untuk duduk, melakukan penggabungan yang tepat, dan mungkin menguji ulang seluruh masalah dang untuk memastikan kami tidak mematahkannya.

Sementara itu 8 orang lainnya semua melakukan kode seperti para sadis, saya membuat beberapa perbaikan bug kecil dan mengirimkannya sebelum saya tahu kami memiliki konflik penggabungan, dan pria itu sepertinya waktu yang tepat untuk beristirahat, dan mungkin Anda libur untuk sore atau terjebak dalam rapat atau apa pun. Mungkin sebaiknya aku berlibur saja. Atau berganti karier.

Maka, untuk melepaskan diri dari mimpi buruk ini, beberapa orang menjadi sangat takut pada komitmen (apa lagi yang baru, oke?). Kita tentu saja menolak risiko dalam skenario seperti ini - kecuali kita pikir kita payah dan akan mengacaukannya, dalam hal ini orang mulai bertindak dengan pengabaian yang ceroboh. mendesah

Jadi begitulah. Ya, sistem modern dirancang untuk meringankan rasa sakit ini, dan itu seharusnya dapat dengan mudah mundur dan merendahkan dan merendahkan dan freebase dan hanglide dan semua itu.

Tapi itu semua lebih banyak pekerjaan, dan kami hanya ingin menekan tombol di microwave dan memiliki 4 hidangan sebelum kita punya waktu untuk menemukan garpu, dan semuanya terasa sangat tidak memuaskan - kode berfungsi, produktif, dan bermakna, tetapi anggun menangani penggabungan tidak masuk hitungan.

Programmer, sebagai suatu peraturan, harus mengembangkan memori kerja yang hebat, dan kemudian memiliki kecenderungan untuk segera melupakan semua sampah dan nama variabel dan pelingkupan segera setelah mereka menyelesaikan masalah, dan menangani konflik gabungan (atau lebih buruk, suatu salah menangani penggabungan) adalah undangan untuk diingatkan akan kefanaan Anda.

BrianH
sumber
5
Kata yang luar biasa, Pak!
Kelinci Southpaw
10
Ini menjawab mengapa orang takut bergabung, bukan mengapa menggabungkan komitmen dianggap buruk oleh begitu banyak orang.
Jay
23
Masalah dengan jawaban ini adalah bahwa ini masih berlaku untuk rebase . Lagi pula, rebase masih melakukan penggabungan di mana Anda telah mengubah sebaris kode yang sudah diubah. Saya pikir ini adalah masalah dengan cara pertanyaan itu dinyatakan.
deworde
2
Saya menurunkan jawaban ini karena masih fasih dan tidak masuk akal, imho.
Eugene
6
Ini sepertinya tidak mengenai rebase vs merge-merge sama sekali.
Andyz Smith
5

Rebasing menyediakan titik cabang bergerak yang menyederhanakan proses mendorong perubahan kembali ke garis dasar. Ini memungkinkan Anda untuk memperlakukan cabang yang sudah berjalan lama seolah-olah itu adalah perubahan lokal. Tanpa rebasing, cabang mengakumulasikan perubahan dari baseline yang akan dimasukkan dalam perubahan yang digabung kembali ke baseline.

Penggabungan meninggalkan garis dasar Anda di titik cabang asli. Jika Anda menggabungkan perubahan beberapa minggu dari garis tempat Anda bercabang, sekarang Anda memiliki banyak perubahan dari titik cabang Anda, banyak di antaranya akan berada di baseline Anda. Ini membuatnya sulit untuk mengidentifikasi perubahan Anda di cabang Anda. Mendorong perubahan kembali ke garis dasar dapat menghasilkan konflik yang tidak terkait dengan perubahan Anda. Dalam kasus konflik, dimungkinkan untuk mendorong perubahan yang tidak konsisten. Penggabungan yang sedang berlangsung membutuhkan upaya untuk mengelola, dan relatif mudah untuk kehilangan perubahan.

Rebase memindahkan titik cabang Anda ke revisi terbaru pada baseline Anda. Setiap konflik yang Anda temui hanya untuk perubahan Anda saja. Mendorong perubahan jauh lebih sederhana. Konflik ditangani di cabang lokal dengan melakukan rebase tambahan. Dalam hal dorongan yang saling bertentangan, yang terakhir untuk mendorong perubahan mereka perlu menyelesaikan masalah dengan perubahan mereka.

BillThor
sumber
1
jadi yang dilakukannya hanyalah menurunkan perubahan baru ke tingkat yang dianggap 'hal yang salah' karena hanya itu perubahan . Jika semua perubahan lama dimasukkan dalam penggabungan, semua perubahan berada pada pijakan level, tentang apakah mereka adalah 'hal yang benar' hari ini.
Andyz Smith
@AndyzSmith Saya tidak akan menganggap perubahan baru itu salah . Ketika mencoba menentukan apa yang sedang diubah dan harus didorong, itu adalah hal yang benar . Setelah direstrukturisasi, Anda dapat mengabaikan perubahan lama karena merupakan bagian dari baseline Anda.
BillThor
benar, jadi Jika Anda tidak yakin apa baseline Anda, yaitu, apakah apa yang telah Anda ubah sudah siap untuk digabungkan adalah 'hal yang benar' maka jangan rebase.
Andyz Smith
Dan, jika Anda mendapat dorongan perubahan dari seseorang, dan itu merusak build karena prototipe fungsi mereka tidak cocok dengan prototipe yang ada, Anda langsung tahu, karena rebase, bahwa pria baru itu salah. Anda tidak perlu menebak bahwa mungkin orang baru memiliki prototipe yang tepat dan perubahan changset yang sebelumnya tidak dilepaskan, yang belum diterapkan adalah perubahan dengan prototipe yang salah.
Andyz Smith
4

Alat otomatis menjadi lebih baik dalam memastikan bahwa kode penggabungan akan dikompilasi dan dijalankan, sehingga menghindari konflik sintaksis , tetapi mereka tidak dapat menjamin tidak adanya konflik logis yang dapat diperkenalkan oleh penggabungan. Jadi gabungan yang 'berhasil' memberi Anda rasa percaya diri yang salah, padahal kenyataannya itu tidak menjamin apa pun, dan Anda harus mengulang semua pengujian Anda.

Masalah sebenarnya dengan percabangan dan penggabungan, seperti yang saya lihat, adalah menendang pepatah di jalan. Ini memungkinkan Anda mengatakan "Saya hanya akan bekerja di dunia kecil saya sendiri" selama seminggu, dan menangani masalah apa pun yang muncul kemudian. Tetapi memperbaiki bug selalu lebih cepat / lebih murah saat masih segar. Pada saat semua cabang kode mulai digabung, Anda mungkin sudah lupa beberapa nuansa dari hal-hal yang dilakukan.

Ambil kedua masalah tersebut bersama-sama, dan Anda mungkin menemukan diri Anda dalam situasi di mana lebih mudah dan lebih mudah untuk membuat semua orang bekerja di bagasi yang sama dan terus menyelesaikan konflik saat mereka muncul, bahkan jika mereka membuat pengembangan aktif sedikit lebih lambat.

MrFox
sumber
4
Ini menjawab mengapa orang takut bergabung, bukan mengapa menggabungkan komitmen dianggap buruk oleh begitu banyak orang.
Jay
Jadi, trunk ini yang Anda maksud, apakah itu melibatkan rebase? Tolong jelaskan.
Andyz Smith
@AndyzSmith "trunk" adalah istilah svn untuk setara dengan cabang "master" git
Izkata
@Izkata jadi jawaban ini menganjurkan tidak menggunakan gabungan atau rebase?
Andyz Smith
@AndyzSmith Ya, begitulah cara saya membacanya juga. Dan saya tidak setuju dengan itu; setelah bekerja di tim dengan 7 pengembang lain dengan cara yang disarankan, saya tidak menyarankan itu. Kita seharusnya menggunakan cabang fitur lebih dari yang kita lakukan, tetapi kebanyakan dari mereka takut untuk bergabung (seperti yang BrianDHall bahas dalam jawabannya).
Izkata
0

Poin tambahan yang relevan adalah ini: Dengan rebasing saya dapat dengan mudah memilih atau mengembalikan fitur di cabang rilis saya.

Bruno Schäpper
sumber
1
Ini menguraikan ini?
Akavall
Tentu :-) Dalam aliran git, kami secara teratur membuat cabang rilis baru. Jika setelah pembuatan, bug diperbaiki di cabang pengembangan, kami gunakan git cherry-pick -x <commit>untuk menerapkannya ke cabang rilis. Atau, kami mungkin ingin membatalkan sesuatu untuk rilis, dengan git revert <commit>. Jika <commit>gabungan, itu menjadi berbulu. Hal ini mungkin sejauh yang saya tahu, tapi tidak mudah dilakukan. Saat menggunakan rebase, setiap 'penggabungan' adalah satu raksasa tapi komit reguler, mudah dipilih dan dikembalikan.
Bruno Schäpper
0

Tiga hal belum dikatakan dalam salah satu jawaban:

  • Diffing di dalam cabang:

    • Membedakan antara pasangan komit yang sewenang-wenang di cabang menjadi sangat sulit ketika ada komit gabungan.
  • Menggabungkan satu item sekaligus:

    • Saat Anda menyelesaikan perbedaan antara dua cabang, gabungan biasanya terjadi sekaligus, dan konflik gabungan apa pun yang tersisa harus Anda lakukan tanpa konteks di mana komit spesifik bertanggung jawab atas konflik tersebut. Jika Anda rebase, rebase akan berhenti pada titik konflik terjadi dan memungkinkan Anda untuk menyelesaikannya dalam konteks itu.
  • Pembersihan sebelum mendorong:

    • Jika Anda melakukan kesalahan komit yang kemudian perlu Anda perbaiki, jika Anda tidak mendorong rebase interaktif akan memungkinkan Anda untuk menggabungkan / membagi / mengubah / memindahkan komit. Meskipun Anda masih bisa melakukan itu jika Anda telah bergabung, menjadi sangat sulit jika Anda ingin menggabungkan / membagi / mengubah / pindah melintasi batas gabungan.
Catskul
sumber