Apakah squashing pull request mematahkan algoritma penggabungan git?

15

Saat ini saya bekerja untuk perusahaan yang menggunakan VSTS untuk mengelola kode git. Cara "direkomendasikan" Microsoft untuk menggabungkan cabang adalah dengan melakukan "penggabungan squash", yang berarti bahwa semua komit untuk cabang tersebut tergencet menjadi satu komit baru yang menggabungkan semua perubahan.

Masalahnya adalah, bagaimana jika saya melakukan beberapa perubahan di satu cabang untuk satu item jaminan simpanan, maka segera ingin mulai melakukan perubahan di cabang lain untuk jaminan simpanan lain, dan perubahan itu tergantung pada set perubahan cabang pertama?

Saya bisa membuat cabang untuk item backlog itu dan mendasarkannya pada cabang pertama. Sejauh ini baik. Namun, ketika tiba saatnya untuk membuat permintaan tarikan untuk saya cabang kedua, cabang pertama telah digabung menjadi master dan karena itu telah dilakukan sebagai penggabungan squash, git menggerakkan sekelompok konflik. Ini karena git tidak melihat commit asli yang menjadi dasar dari cabang kedua, ia hanya melihat satu squash besar bergabung dan jadi untuk menggabungkan cabang kedua menjadi master, ia mencoba untuk memutar ulang semua komitmen cabang pertama di atas penggabungan squash, menyebabkan banyak konflik.

Jadi pertanyaan saya adalah, apakah ada cara untuk mengatasi ini (selain tidak pernah mendasarkan satu cabang fitur dari yang lain, yang membatasi alur kerja saya) atau apakah penggabungan squash hanya mematahkan algoritma git?

Jez
sumber

Jawaban:

15

Dengan Git, lakukan

  • tidak kekal,
  • dan membentuk grafik asiklik terarah.

Squashing tidak menggabungkan komitmen. Alih-alih, ini mencatat komit baru dengan perubahan dari beberapa komit lainnya. Rebasing serupa, tetapi tidak menggabungkan komitmen. Merekam komit baru dengan perubahan yang sama seperti komit yang ada disebut penulisan ulang riwayat . Tetapi karena komitmen yang ada tidak dapat diubah, ini harus dipahami sebagai "menulis sejarah alternatif."

Penggabungan mencoba untuk menggabungkan perubahan dari dua sejarah komit (cabang) mulai dari komit leluhur yang sama.

Jadi mari kita lihat sejarah Anda:

                                 F  feature2
                                /
               1---2---3---4---5    feature1 (old)
              /
-o---o---o---A---o---o---S          master

A adalah leluhur yang umum, 1–5 cabang fitur asli, F cabang fitur baru, dan S commit yang tergencet yang berisi perubahan yang sama dengan 1–5. Seperti yang Anda lihat, leluhur umum dari F dan S adalah A. Sejauh menyangkut git, tidak ada hubungan antara S dan 1-5. Jadi menggabungkan master dengan S di satu sisi dan fitur2 dengan 1-5 di sisi lain akan bertentangan. Menyelesaikan konflik-konflik ini tidak sulit, tetapi itu tidak perlu, pekerjaan yang membosankan.

Karena kendala-kendala ini, ada dua pendekatan untuk menangani penggabungan / penindasan:

  • Entah Anda menggunakan penulisan ulang riwayat, dalam hal ini Anda akan mendapatkan beberapa komit yang mewakili perubahan yang sama. Anda kemudian akan rebase cabang fitur kedua ke komit terjepit:

                                     F  feature2 (old)
                                    /
                   1---2---3---4---5    feature1 (old)
                  /
    -o---o---o---A---o---o---S          master
                              \
                               F'       feature2
    
  • Atau Anda tidak menggunakan penulisan ulang riwayat, dalam hal ini Anda mungkin mendapatkan komitmen gabungan tambahan:

                                     F  feature2
                                    /
                   1---2---3---4---5    feature1 (old)
                  /                 \
    -o---o---o---A---o---o-----------M  master
    

    Ketika fitur2 dan master digabung, leluhur bersama akan melakukan 5.

Dalam kedua kasus Anda akan memiliki beberapa upaya penggabungan. Upaya ini tidak terlalu bergantung pada mana dari dua strategi di atas yang Anda pilih. Tapi pastikan itu

  • cabang berumur pendek, untuk membatasi seberapa jauh mereka bisa melayang dari cabang utama, dan itu
  • Anda secara teratur menggabungkan master ke cabang fitur Anda, atau rebase cabang fitur pada master untuk menjaga agar cabang-cabang tetap sinkron.

Ketika bekerja dalam tim, akan sangat membantu untuk mengoordinasikan siapa yang sedang mengerjakan apa. Ini membantu menjaga jumlah fitur dalam pengembangan kecil, dan dapat mengurangi jumlah konflik penggabungan.

amon
sumber
2
Jawaban Anda sepertinya tidak membahas apa yang terjadi jika Anda pertama-tama menggabungkan squash feature1ke master, lalu ingin bergabung feature2nanti. Dalam hal itu, bukankah pendekatan pertama akan menghasilkan konflik ketika git mencoba untuk menerapkan kembali feature1komit di atas komit terjepit, sedangkan yang kedua akan memungkinkan git untuk menentukan bahwa komit tersebut tidak perlu digabung?
Jez
@ Jean Itulah yang terjadi ketika Anda menekan PR. Saya baru-baru ini harus secara manual menulis ulang sebuah PR pada proyek OSS (dengan git clonemengambil repo dan menyalin file saya yang sudah berubah!) Karena saya bercabang dari cabang dan kemudian pengelola menghancurkan cabang pertama. Di pekerjaan saya, mereka juga melakukan penggabungan squash. Ini berarti saya tidak dapat bekerja pada fitur byang bergantung pada fitur asampai fitur adigabungkan.
Membuang Akun
1
Dan apakah itu bukan kerusakan yang sangat mengganggu dari sesuatu yang seharusnya bekerja, seperti yang dirancang git? Lihat, saya melihat berbagai organisasi seperti Microsoft dan Github sebenarnya merekomendasikan penggabungan squash ini dan mereka tampak bodoh bagi saya.
Jez
1
@Jez Dalam skenario asli, ya Anda akan mendapatkan konflik saat menggabungkan feature2 ke master karena menggabungkan komit 1–5 akan bertentangan dengan perubahan yang sama di S. Solusinya adalah dengan rebase feature2 (solusi 1) atau tidak menggunakan squashing / rebasing di semua (solusi 2).
amon
Apakah penggabungan squash cocok untuk Anda tergantung pada apa yang ingin Anda rekam dalam riwayat kontrol versi. Jika cabang fitur memiliki banyak komit WIP, maka squashing menempatkan satu komit besar dengan fitur lengkap pada cabang master. Jika Anda lebih memilih untuk mempertahankan semua komit perantara dari cabang fitur, maka gunakan rebasing atau penggabungan.
amon
11

Penggabungan squash memecah algoritma penggabungan untuk setiap cabang yang berisi komit apa pun yang dihapus oleh squash. Dengan kata lain, rebases adalah viral. Jika Anda rebase satu cabang, Anda harus rebase cabang lain yang bergantung pada cabang itu. Jika Anda menggunakan rerere , konflik gabungan apa pun yang Anda selesaikan secara manual di repo lokal Anda tidak perlu dipecahkan secara manual lagi, tetapi itu tidak membantu menyelesaikan konflik yang diselesaikan oleh orang lain.

Itu sebabnya aturan tidak tertulis kami di sini boleh-boleh saja tergencet selama tidak ada orang lain yang bergantung pada cabang fitur Anda, yang mungkin terjadi 90% dari waktu. Jika tidak, penggabungan lurus membantu semua orang menghindari masalah.

Karl Bielefeldt
sumber
Salah satu cara untuk memiliki komit terjepit dalam sejarah master dan cabang fitur yang utuh untuk membuat cabang squash-only terpisah. Misalkan Anda memiliki feature-xyzcabang. Anda dapat membuat feature-xyz-squashedcabang mulai sama komit sebagai feature-xyzcabang, git cherry-pickyang komit dari feature-xyzke feature-xyz-squashed, labu mereka di sana, dan merge feature-xyz-squasheduntuk master. Anda seharusnya tidak bergabung feature-xyzsaat itu. Terkadang hal di atas masuk akal (misalnya Anda tidak ingin memasukkan komit dengan kata sandi dimasukkan), tetapi ini merupakan solusi, bukan praktik terbaik.
9000