Mengapa git pull melakukan penggabungan bukannya rebase secara default?

71

Pertimbangkan situasi berikut:

  • Anda memiliki klon dari repositori git
  • Anda memiliki beberapa komit lokal (komit yang belum didorong ke mana pun)
  • Repositori jarak jauh memiliki komit baru yang belum Anda rekonsiliasi

Jadi sesuatu seperti ini:

Komitmen tanpa ikatan

Jika Anda menjalankan git pulldengan pengaturan default, Anda akan mendapatkan sesuatu seperti ini:

gabungkan komit

Ini karena git melakukan penggabungan.

Ada alternatifnya. Anda dapat meminta pull untuk melakukan rebase sebagai gantinya:

git pull --rebase

dan Anda akan mendapatkan ini:

rebased

Menurut pendapat saya, versi rebased memiliki banyak keuntungan yang sebagian besar terpusat pada menjaga kode Anda dan sejarah bersih, jadi saya sedikit dikejutkan oleh fakta bahwa git melakukan penggabungan secara default. Ya, hash dari komit lokal Anda akan diubah, tetapi ini sepertinya harga kecil untuk membayar untuk sejarah yang lebih sederhana yang Anda dapatkan sebagai gantinya.

Tidak berarti saya menyarankan bahwa ini entah bagaimana default yang buruk atau salah. Saya hanya mengalami kesulitan memikirkan alasan mengapa penggabungan mungkin lebih disukai untuk default. Apakah kita punya wawasan mengapa itu dipilih? Apakah ada manfaat yang membuatnya lebih cocok sebagai default?

Motivasi utama untuk pertanyaan ini adalah bahwa perusahaan saya mencoba untuk menetapkan beberapa standar garis dasar (mudah-mudahan, lebih seperti pedoman) untuk bagaimana kita mengatur dan mengelola repositori kami untuk memudahkan pengembang untuk mendekati repositori yang belum pernah mereka kerjakan sebelumnya. Saya tertarik membuat kasus bahwa kita biasanya harus rebase dalam situasi seperti ini (dan mungkin untuk merekomendasikan pengembang mengatur konfigurasi global mereka untuk rebase secara default), tetapi jika saya menentangnya, saya pasti akan bertanya mengapa rebase bukan t default jika ini sangat bagus. Jadi saya bertanya-tanya apakah ada sesuatu yang saya lewatkan.

Telah disarankan bahwa pertanyaan ini adalah duplikat dari Mengapa begitu banyak situs web lebih memilih "git rebase" daripada "git merge"? ; Namun, pertanyaan itu agak kebalikan dari yang ini. Ini membahas manfaat rebase atas penggabungan, sementara pertanyaan ini menanyakan tentang manfaat penggabungan atas rebase. Jawaban di sana mencerminkan hal ini, dengan fokus pada masalah dengan penggabungan dan manfaat rebase.

jpmc26
sumber
Masalah lainnya adalah jika Anda secara tidak sengaja berkomitmen untuk menguasai, maka lakukan tarikan yang digabungkan, kedua master dapat tidak sinkron meskipun penggabungan tersebut terlihat normal. Inilah sebabnya mengapa alias tarik saya hanya menyertakan --ff.
Ixrec
jika sourcetree pernah mengubah tampilan grafiknya sehingga menampilkan rebases / penggabungan berbeda, akankah Anda beralih ke penggabungan?
Ewan
1
@Ewan SourceTree seharusnya tidak mengubah tampilan grafiknya. Secara akurat mewakili grafik.
jpmc26
4
Untuk pemilih duplikat, harap perhatikan bahwa konten dalam jawaban yang saya terima jelas tidak ada dalam pertanyaan yang Anda klaim adalah duplikat.
jpmc26

Jawaban:

56

Sulit untuk mengetahui dengan pasti mengapa penggabungan adalah default tanpa mendengar dari orang yang membuat keputusan itu.

Ini sebuah teori ...

Git tidak dapat menganggap itu tidak masalah untuk --menurunkan setiap tarikan. Dengarkan bagaimana itu terdengar. "Rebase setiap tarikan." hanya terdengar salah jika Anda menggunakan permintaan tarik atau serupa. Apakah Anda akan rebase atas permintaan tarik?

Dalam sebuah tim yang tidak hanya menggunakan Git untuk kontrol sumber terpusat ...

  • Anda dapat menarik dari hulu dan dari hilir. Beberapa orang melakukan banyak hal menarik dari hilir, dari kontributor, dll.

  • Anda dapat mengerjakan fitur dalam kolaborasi erat dengan pengembang lain, menarik dari mereka atau dari cabang topik bersama dan kadang-kadang masih diperbarui dari hulu. Jika Anda selalu rebase maka Anda akhirnya mengubah riwayat bersama, belum lagi siklus konflik yang menyenangkan.

Git dirancang untuk tim berdistribusi besar di mana setiap orang tidak menarik dan mendorong ke satu repo pusat. Jadi standarnya masuk akal.

  • Pengembang yang tidak tahu kapan melakukan rebase akan bergabung secara default.
  • Pengembang dapat rebase saat mereka mau.
  • Komiter yang melakukan banyak tarikan dan memiliki banyak tarikan mendapatkan default yang paling cocok untuk mereka.

Untuk bukti niat, berikut ini tautan ke email terkenal dari Linus Torvalds dengan pandangannya tentang kapan mereka seharusnya tidak melakukan rebase. Dri-devel git pull email

Jika Anda mengikuti keseluruhan utas, Anda dapat melihat bahwa satu pengembang menarik dari pengembang lain dan Linus menarik dari keduanya. Dia membuat pendapatnya cukup jelas. Karena dia mungkin memutuskan default Git, ini mungkin menjelaskan alasannya.

Banyak orang sekarang menggunakan Git secara terpusat, di mana setiap orang dalam tim kecil hanya menarik dari repo pusat hulu dan mendorong ke remote yang sama. Skenario ini menghindari beberapa situasi di mana rebase tidak baik, tetapi biasanya tidak menghilangkannya.

Saran: Jangan membuat kebijakan untuk mengubah default. Setiap kali Anda menyatukan Git dengan sekelompok besar pengembang, beberapa pengembang tidak akan memahami Git secara mendalam (termasuk saya sendiri). Mereka akan pergi ke Google, JADI, mendapatkan saran buku masak dan kemudian bertanya-tanya mengapa beberapa hal tidak berfungsi, misalnya mengapa git checkout --ours <path>mendapatkan versi file yang salah? Anda selalu dapat merevisi lingkungan lokal Anda, membuat alias, dll. Sesuai selera Anda.

joshp
sumber
5
+1 untuk tidak mengubah default - daripada memutar alur kerja git Anda sendiri, mungkin lebih baik untuk mengambil yang ada (misalnya yang didokumentasikan oleh Atlassian atlassian.com/git/tutorials/comparing-workflows/… )
Rob Church
1
Terima kasih atas jawabannya. Info tentang menarik dari hilir adalah apa yang saya lewatkan. Juga, cukup menarik, tautan yang Anda berikan memberi semangat apa yang ingin saya capai: "Orang-orang dapat (dan mungkin harus) rebase pohon pribadi mereka (pekerjaan mereka sendiri)."
jpmc26
2
@ jpmc Hebat. Memang. Memulihkan pohon-pohon pribadi dapat menjaga banyak pengaburan dari sejarah bersama. Saya lakukan itu. Ini adalah kejelasan kapan tidak melakukannya yang penting.
joshp
"beberapa pengembang tidak akan mengerti Git terlalu dalam". Rebase BUKAN fitur Git yang sangat mewah ("dalam", dll.) Apakah Anda benar-benar menganggap hal ini sulit dipahami? Saya pikir ini harus menjadi pemicu untuk memanggil dev tidak kompeten.
Victor Yarema
15

Jika Anda membaca halaman manual git untuk rebase, dikatakan :

Memotong kembali (atau bentuk penulisan ulang lainnya) cabang yang menjadi dasar pekerjaan orang lain adalah ide yang buruk: siapa pun di hilirnya dipaksa untuk secara manual memperbaiki sejarah mereka. Bagian ini menjelaskan cara melakukan perbaikan dari sudut pandang hilir. Perbaikan sebenarnya, bagaimanapun, adalah untuk menghindari rebasing hulu di tempat pertama.

Saya pikir itu mengatakan itu cukup baik sebagai alasan untuk tidak menggunakan rebase sama sekali, apalagi secara otomatis melakukannya untuk setiap tarikan. Beberapa orang menganggap rebase berbahaya . Mungkin seharusnya tidak pernah dimasukkan ke dalam git sama sekali, karena semua yang tampaknya dilakukan adalah merapikan sejarah, sesuatu yang seharusnya tidak diperlukan dalam SCM mana pun yang tugas utamanya adalah untuk melestarikan sejarah.

Ketika Anda mengatakan 'menjaga ... sejarah bersih', anggap Anda salah. Mungkin terlihat lebih bagus, tetapi untuk alat yang dirancang untuk menjaga riwayat revisi, jauh lebih bersih untuk menjaga setiap komit sehingga Anda dapat melihat apa yang terjadi. Membasmi sejarah sesudahnya adalah seperti memoles patina pergi, membuat tampilan antik yang kaya seperti repro mengkilap :-)

gbjbaanb
sumber
3
@Wan IMHO "tidak bekerja tetapi terlihat cantik" adalah sesuatu yang seharusnya hanya diperuntukkan bagi industri fashion, bukan IT. Git IMHO harus menghapusnya karena jelas mendorong terlalu banyak orang untuk berpikir gaya lebih penting daripada substansi.
gbjbaanb
12
Saya akan membantah saran Anda bahwa menjaga sejarah tetap bersih tidak berguna. Ini bukan. Riwayat repositori dimaksudkan untuk konsumsi manusia, dan karenanya, ada banyak nilai dalam membuatnya dapat dibaca. Dalam kasus penggunaan khusus saya, kami bahkan bermaksud agar Manajer Proyek non-pengembang harus dapat membaca sejarah. Riwayat bersih hanya dapat membantu dengan itu, dan itu dapat membantu pengembang baru yang belum pernah melihat basis kode dan harus menyelam dan memperbaiki bug memahami apa yang terjadi di area kode tertentu.
jpmc26
3
Kode ada terlebih dahulu dan terutama untuk dieksekusi oleh mesin (mungkin setelah dikompilasi). Menerapkan filosofi Anda di atas, kami akan menyimpulkan bahwa keterbacaan kode tidak masalah karena tidak ada jumlah keterbacaan yang akan menyelesaikan kesulitan memahami kode. Saya tidak pernah menyarankan bahwa apa pun harus dihancurkan. Saya hanya mengatakan bahwa grafik kompleks yang menyimpang ke banyak persimpangan jalan sulit untuk diikuti, jadi ada baiknya berinvestasi sedikit untuk menjaga sejarah Anda cukup bersih. Perhatikan juga bahwa sejarah linear lebih kondusif untuk meningkatkan alat git seperti menyalahkan dan membagi dua.
jpmc26
6
Dokumen tidak mengatakan "jangan rebase." Dikatakan, "jangan rebase perubahan yang hulu dari orang lain ." Ada dunia perbedaan antara keduanya. Linus sendiri menyarankan beberapa rebasing untuk mengatur sejarah, seperti dapat dilihat pada tautan dalam jawaban yang diterima. Dan bagaimana alat apa pun tahu komit mana yang tidak relevan (terutama jika alat mengalami kesulitan menganalisis sejarah non-linear!), Dan bagaimana Anda tahu komitmen mana yang ingin Anda bedakan (terutama tanpa bisa menggali sejarah!)? Anda mengambil kata hati-hati tentang situasi tertentu ke ekstrem dogmatis.
jpmc26
4
Anda pasti tidak ingin "menyimpan riwayat revisi" jika itu termasuk setiap komit yang pernah dibuat pengembang. Dengan mengikuti logika itu, kita juga harus merekam versi kode asli setiap kali tombol backspace dipukul. Setiap komitmen harus merupakan perubahan minimal dan lengkap yang masih membuat seluruh proyek dalam keadaan stabil. Jika komit asli Anda kemudian ditemukan bermasalah, jauh lebih baik untuk mengubah / mengedit / mengubah komit daripada membuat yang lain. Namun, lihat juga mail-archive.com/[email protected]/msg39091.html
Mikko Rantalainen
12

Anda benar, dengan anggapan Anda hanya memiliki satu repositori lokal / yang diubah. Namun, pertimbangkan untuk ada PC lokal kedua, misalnya.

Setelah salinan lokal / modifikasi Anda didorong ke tempat lain rebasing akan mengacaukan salinan itu. Tentu saja, Anda bisa memaksa mendorong, tetapi itu dengan cepat menjadi rumit. Apa yang terjadi jika satu atau lebih dari ini memiliki komitmen yang sama sekali baru?

Seperti yang Anda lihat, ini sangat situasional, tetapi strategi dasarnya (bagi saya) jauh lebih praktis dalam kasus-kasus non-khusus / kolaborasi.


Perbedaan kedua: Strategi penggabungan akan menjaga struktur yang jelas dan konsisten waktu. Setelah rebases, sangat mungkin bahwa komitmen yang lebih lama mungkin mengikuti perubahan yang lebih baru, membuat seluruh sejarah dan alurnya lebih sulit untuk dipahami.

Mario
sumber
1
"Setelah rebases, sangat mungkin komit yang lebih lama mungkin mengikuti perubahan yang lebih baru" - itu juga terjadi dengan penggabungan, itulah sebabnya Anda (mungkin) membutuhkan grafik yang cantik untuk memahami hal itu. Waktu di mana komit dibuat mungkin jauh sebelum penggabungan yang membawanya ke cabang ini.
Steve Jessop
6

Alasan besar mungkin adalah bahwa perilaku default harus "hanya bekerja" di repo publik. Memulihkan sejarah yang telah digabungkan orang lain akan menyebabkan masalah. Saya tahu Anda berbicara tentang repo pribadi Anda, tetapi secara umum git tidak tahu atau peduli apa yang pribadi atau publik, jadi default yang dipilih akan menjadi default untuk keduanya.

Saya menggunakan git pull --rebasecukup banyak dalam repo pribadi saya, tetapi bahkan di sana pun memiliki potensi kerugian, yaitu bahwa sejarah saya HEADtidak lagi mencerminkan pohon ketika saya benar-benar mengerjakannya.

Jadi untuk contoh besar, anggaplah bahwa saya selalu menjalankan tes dan memastikan mereka lulus sebelum melakukan komit. Ini kurang relevan setelah saya melakukan git pull --rebase, karena tidak lagi benar bahwa pohon di setiap komit saya telah lulus ujian. Selama perubahan tidak mengganggu dengan cara apa pun, dan kode yang saya tarik telah diuji, maka mungkin itu akan lulus tes, tetapi kami tidak tahu karena saya tidak pernah mencobanya. Jika integrasi berkelanjutan adalah bagian penting dari alur kerja Anda, maka segala macam rebase dalam repo yang sedang CIed bermasalah.

Saya tidak terlalu mempermasalahkan hal ini, tetapi itu memang mengganggu sebagian orang: mereka lebih suka bahwa sejarah mereka di git mencerminkan kode yang sebenarnya mereka kerjakan (atau mungkin pada saat mereka mendorongnya, versi kebenaran yang disederhanakan setelah digunakan) dari "perbaikan").

Saya tidak tahu apakah masalah ini secara khusus adalah alasan mengapa Linus memilih untuk menggabungkan daripada rebasing secara default. Mungkin ada kelemahan lain yang belum saya temui. Tetapi karena dia tidak malu untuk mengungkapkan pendapatnya dalam kode, saya cukup yakin itu mengarah pada apa yang menurutnya merupakan alur kerja yang cocok untuk orang-orang yang tidak ingin terlalu memikirkannya (dan terutama mereka yang bekerja di depan umum bukan daripada repo pribadi). Menghindari garis paralel dalam grafik cantik, lebih memilih garis lurus bersih yang tidak mewakili pengembangan paralel seperti yang terjadi, mungkin bukan prioritas utamanya meskipun itu milik Anda :-)

Steve Jessop
sumber