Bagaimana cara git bergabung setelah ceri-pick bekerja?

190

Mari kita bayangkan bahwa kita memiliki mastercabang.

Lalu kita buat a newbranch

git checkout -b newbranch

dan buat dua commit baru ke newbranch: commit1 dan commit2

Lalu kami beralih ke master dan membuat cherry-pick

git checkout master
git cherry-pick hash_of_commit1

Melihat ke dalam gitkkita melihat bahwa commit1 dan versi yang dipilih ceri memiliki hash yang berbeda, jadi secara teknis mereka adalah dua komitmen yang berbeda.

Akhirnya kami bergabung newbranchmenjadi master:

git merge newbranch

dan melihat bahwa dua komitmen ini dengan hash yang berbeda digabungkan tanpa masalah meskipun mereka menyiratkan bahwa perubahan yang sama harus diterapkan dua kali, jadi salah satu dari mereka harus gagal.

Apakah git benar-benar melakukan analisis cerdas terhadap konten komit sambil menggabungkan dan memutuskan bahwa perubahan tidak boleh diterapkan dua kali atau komit ini ditandai secara internal sebagai terhubung bersama?

Paul
sumber

Jawaban:

131

Jawaban singkat

Jangan khawatir, Git akan menanganinya.

Jawaban panjang

Tidak seperti misalnya SVN 1 , Git tidak menyimpan commit dalam format delta, tetapi berbasis snapshot 2,3 . Sementara SVN akan secara naif mencoba menerapkan setiap komit yang digabung sebagai tambalan (dan gagal, untuk alasan yang tepat seperti yang Anda jelaskan), Git umumnya dapat menangani skenario ini.

Saat menggabungkan, Git akan mencoba menggabungkan snapshot dari kedua commit HEAD menjadi snapshot baru. Jika sebagian kode atau file identik di kedua snapshot (yaitu karena komit sudah dipilih secara ceri), Git tidak akan menyentuhnya.

Sumber

1 Lewati-Delta di Subversi
2 Dasar-Dasar Git
3 Model objek Git

helmbert
sumber
40
Sebenarnya, saya katakan Anda harus khawatir tentang penggabungan dan "git akan menanganinya" bukan aturan praktis yang baik.
cregox
4
Bahkan penggabungan BISA menghasilkan konten duplikat dalam beberapa kasus. Git kadang-kadang menanganinya, tetapi terkadang tidak.
donquixote
Ini sangat salah. Cukup banyak menyimpan file file dalam semua bentuk yang bisa diterima. Dan jika saya ingat dengan benar SVN digunakan untuk menyimpan foto.
he_the_great
2
@he_the_great, tidak. Format penyimpanan lewati-delta SVN (! = Snapshots) didokumentasikan dengan baik dalam manual . Dan saya benar-benar tidak mengerti apa yang Anda maksudkan dengan kondensasi . Saya bukan penutur asli, tapi saya cukup yakin itu bukan kata yang nyata.
helmbert
2
@he_the_great Tetapi bahkan sebagai packfiles setiap hash yang diberikan untuk file menghasilkan file lengkap. Ya itu mengkompres menggunakan delta, tetapi itu bukan delta untuk perubahan dalam komit, tetapi sebaliknya delta antara hash untuk file. Sejauh menyangkut objek komit itu merujuk pohon yang merujuk hash untuk file lengkap. Bahwa di bawah tenda data dikompresi tidak mempengaruhi cara git bekerja. Git menyimpan file lengkap sejauh menyangkut komit, SVN menyimpan delta untuk komitmen seperti yang saya mengerti.
Peter Olson
44

Setelah penggabungan seperti itu, Anda mungkin memiliki komitmen ceri-pick dalam sejarah dua kali.

Solusi untuk mencegah hal ini saya kutip dari artikel yang merekomendasikan untuk cabang dengan duplikat (cherry-pick) berkomitmen menggunakan rebase sebelum bergabung:

git merge setelah git cherry-pick: menghindari duplikat komit

Bayangkan kita memiliki cabang utama dan cabang b:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

Sekarang kita sangat membutuhkan komit b1 dan b3 di master, tetapi bukan komit yang tersisa di b. Jadi apa yang kita lakukan adalah checkout cabang master dan komit cherry-pick b1 dan b3:

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

Hasilnya adalah:

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

Katakanlah kita melakukan commit lain pada master dan kita dapatkan:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

Jika sekarang kita akan menggabungkan cabang b menjadi master:

$ git merge b

Kami akan mendapatkan yang berikut:

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

Itu berarti perubahan yang diperkenalkan oleh b1 dan b3 akan muncul dua kali dalam sejarah. Untuk menghindari itu, kita bisa rebase bukan menggabungkan:

$ git rebase master b

Yang akan menghasilkan:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

Akhirnya:

$ git checkout master
$ git merge b

memberi kita:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

Koreksi EDIT seharusnya oleh komentar David Lemon

efhemerr
sumber
1
petunjuk bagus tentang rebase! itu akan 'melewati' semua ceri-memilih melakukan secara otomatis.
Itake
2
Jujur, kedengarannya terlalu bagus untuk menjadi kenyataan, saya harus melihatnya dengan mata saya. Juga rebase memodifikasi commit, timeline terakhir Anda seharusnya---Y---b2'---b4'
David Lemon
Bekerja dengan sempurna. Sangat membantu jika Anda tidak ingin memetik buah cherry dua kali dalam sejarah.
user2350644
1
Tidakkah harus dicatat bahwa sementara rebase itu indah, bahayanya menggunakannya adalah setiap garpu atau cabang yang dibuat dari b lama akan tidak sinkron, dan pengguna mungkin perlu menggunakan hal-hal seperti git reset --hard dan git tekan -f?
JHH
1
@JHH itu sebabnya kami rebase cabang lokal di sini
ephemerr