Sejak saat git cherry-pick
belajar untuk dapat menerapkan banyak komit, perbedaannya memang menjadi agak diperdebatkan, tetapi ini adalah sesuatu yang disebut evolusi konvergen ;-)
Perbedaan sebenarnya terletak pada niat asli untuk membuat kedua alat tersebut:
git rebase
Tugasnya adalah meneruskan serangkaian perubahan yang dimiliki pengembang dalam repositori pribadinya, yang dibuat terhadap versi X dari beberapa cabang hulu, ke versi Y dari cabang yang sama (Y> X). Ini secara efektif mengubah dasar rangkaian komit tersebut, karenanya "rebasing".
(Ini juga memungkinkan pengembang untuk mentransplantasikan serangkaian komit ke komit sewenang-wenang, tetapi penggunaan ini kurang jelas.)
git cherry-pick
adalah untuk membawa komitmen menarik dari satu lini pengembangan ke lini lain. Contoh klasik adalah mem-backport perbaikan keamanan yang dibuat pada cabang pengembangan yang tidak stabil ke cabang yang stabil (pemeliharaan), yang merge
tidak masuk akal, karena akan membawa banyak perubahan yang tidak diinginkan.
Sejak kemunculannya yang pertama, git cherry-pick
telah dapat memilih beberapa komit sekaligus, satu per satu.
Oleh karena itu, mungkin perbedaan paling mencolok antara kedua perintah ini adalah bagaimana mereka memperlakukan cabang tempat mereka bekerja: git cherry-pick
biasanya membawa komit dari tempat lain dan menerapkannya di atas cabang Anda saat ini, merekam komit baru , sambil git rebase
mengambil cabang Anda saat ini dan menulis ulang serangkaian tipnya sendiri berlaku dalam satu atau lain cara. Ya, ini adalah deskripsi yang sangat bodoh tentang apa yang git rebase
bisa dilakukan, tetapi disengaja, untuk mencoba membuat gagasan umum meresap.
Perbarui untuk lebih menjelaskan contoh penggunaan yang git rebase
sedang dibahas.
Mengingat situasi ini,
Buku menyatakan:
Namun, ada cara lain: Anda dapat mengambil patch dari perubahan yang diperkenalkan di C3 dan menerapkannya kembali di atas C4. Di Git, ini disebut rebasing. Dengan perintah rebase, Anda dapat mengambil semua perubahan yang dilakukan pada satu cabang dan menerapkannya ke cabang lain.
Dalam contoh ini, Anda akan menjalankan yang berikut ini:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
"Tangkapan" di sini adalah bahwa dalam contoh ini, cabang "eksperimen" (subjek untuk rebasing) pada awalnya bercabang dari cabang "master", dan karenanya berbagi commit C0 hingga C2 dengannya - secara efektif, "eksperimen" adalah " master "hingga, dan termasuk, C2 plus commit C3 di atasnya. (Ini adalah kasus yang paling sederhana; tentu saja, "eksperimen" dapat berisi beberapa lusinan commit di atas basis aslinya.)
Sekarang git rebase
diperintahkan untuk rebase "percobaan" ke saat ujung "master", dan git rebase
berjalan seperti ini:
- Berjalan
git merge-base
untuk melihat komit terakhir yang dibagi oleh "eksperimen" dan "master" (apa tujuan pengalihan, dengan kata lain). Ini C2.
- Menghemat semua komitmen yang dibuat sejak titik pengalihan; dalam contoh mainan kami, hanya C3.
- Mundurkan HEAD (yang menunjuk ke ujung komit dari "eksperimen" sebelum operasi mulai dijalankan) untuk menunjuk ke ujung "master" - kami melakukan rebasing ke atasnya.
- Mencoba untuk menerapkan setiap komit yang disimpan (seolah-olah dengan
git apply
) secara berurutan. Dalam contoh mainan kami itu hanya satu komit, C3. Katakanlah aplikasinya akan menghasilkan komit C3 '.
- Jika semua berjalan dengan baik, referensi "percobaan" diperbarui untuk menunjuk ke komit yang dihasilkan dari penerapan komit tersimpan terakhir (C3 'dalam kasus kami).
Sekarang kembali ke pertanyaan Anda. Seperti yang Anda lihat, di sini secara teknis git rebase
memang mentransplantasikan serangkaian komit dari "eksperimen" ke ujung "master", sehingga Anda berhak mengetahui bahwa memang ada "cabang lain" dalam proses tersebut. Tapi intinya adalah bahwa tip komit dari "eksperimen" akhirnya menjadi komit tip baru dalam "eksperimen", itu baru saja mengubah dasarnya:
Sekali lagi, secara teknis Anda dapat mengatakan bahwa di git rebase
sini menggabungkan komit tertentu dari "master", dan ini sepenuhnya benar.
Dengan cherry-pick, komit / cabang asli tetap ada dan komit baru dibuat. Dengan rebase, seluruh cabang dipindahkan dengan cabang menunjuk ke komit yang diputar ulang.
Katakanlah Anda memulai dengan:
Rebase:
Anda mendapatkan:
Pilih ceri:
Anda mendapatkan:
untuk info lebih lanjut tentang git buku ini memiliki sebagian besar (http://git-scm.com/book)
sumber
topic
rebased di atasmaster
, itu tidak berisi komit yang ditinggalkan jadi di cabang apa mereka akan menjadi bagian?git checkout topic
dan kemudiangit reset --hard C'
setelah pemetikan ceri, maka Anda memiliki hasil yang sama seperti setelah rebasing. Saya menyelamatkan diri dari banyak konflik penggabungan menggunakan cherry picking over rebasing, karena nenek moyang yang sama sudah jauh.git
-guru tapi inirebase
/cherry-pick
pada semua detail dengangit
yang saya punya masalah pemahaman.git checkout -b
, yang tidak ada hubungannya dengangit cherry-pick
. Cara yang lebih baik untuk menjelaskan apa yang ingin Anda katakan adalah "Anda larigit rebase
ditopic
cabang dan menyebarkannyamaster
; Anda menjalankangit cherry-pick
dimaster
cabang dan meneruskannya (komit dari)topic
. "Memetik ceri bekerja untuk komitmen individu .
Saat Anda melakukan rebasing, ini berlaku semua komit dalam riwayat ke HEAD cabang yang hilang di sana.
sumber
git cherry-pick foo~3..foo
dan mendapatkan komitmen puncak pohon dari "foo" yang dipilih satu per satu.git am
. Sedangkan cherry pick menerapkan commit by commit (mungkin dengan membuat kotak pesan pesan tunggal untuk setiap patch). Rebase saya gagal karena file kotak surat yang dibuatnya kehabisan ruang di drive, tetapi cherry-pick dengan rentang revisi yang sama berhasil (dan tampaknya berjalan lebih cepat).Jawaban singkatnya:
Jawaban yang diberikan di atas bagus, saya hanya ingin memberi contoh dalam upaya menunjukkan keterkaitannya.
Tidak disarankan untuk mengganti "git rebase" dengan urutan tindakan ini, ini hanya "bukti konsep" yang, saya harap, membantu untuk memahami cara kerja sesuatu.
Diberikan repositori mainan berikut:
Katakanlah, kami memiliki beberapa perubahan yang sangat penting (komit # 2 hingga # 5) di master yang ingin kami sertakan ke dalam test_branch_1 kami. Biasanya kita hanya berpindah ke cabang dan melakukan "git rebase master". Tapi karena kami berpura-pura kami hanya dilengkapi dengan "git cherry-pick", kami melakukan:
Setelah semua operasi ini, grafik komit kami akan terlihat seperti ini:
Seperti yang bisa kita lihat, komit # 6 dan # 7 diterapkan terhadap 7254931 (komit tip dari master). HEAD dipindahkan dan menunjukkan komit yang, pada dasarnya, ujung dari cabang rebased. Sekarang yang perlu kita lakukan adalah menghapus pointer cabang lama dan membuat yang baru:
test_branch_1 sekarang di-root dari posisi master terbaru. Selesai!
sumber
cherry-pick
dapat menerapkan berbagai komitmen, saya rasa, ya. Meskipun ini adalah cara yang agak aneh dalam melakukan sesuatu, tidak ada yang menghalangi Anda untuk memilih semua komitmen di cabang fitur Anda di atasnyamaster
, kemudian hapus cabang fitur dan buat kembali sedemikian rupa sehingga mengarah ke ujungmaster
. Anda dapat menganggapnyagit rebase
sebagai urutangit cherry-pick feature_branch
,git branch -d feature_branch
dangit branch feature_branch master
.Keduanya adalah perintah untuk menulis ulang komit dari satu cabang di atas yang lain: perbedaannya adalah di cabang mana - "milikmu" (yang saat ini diperiksa
HEAD
) atau "milik mereka" (cabang yang diteruskan sebagai argumen ke perintah) - adalah yang dasar untuk menulis ulang ini.git rebase
mengambil komit awal dan mengulang komit Anda setelah komit awal mereka (komit awal).git cherry-pick
mengambil satu set komit dan mengulang komit mereka setelah komit Anda ( milik AndaHEAD
).Dengan kata lain, kedua perintah tersebut, dalam perilaku intinya (mengabaikan karakteristik kinerja yang berbeda, konvensi pemanggilan, dan opsi peningkatan), simetris : memeriksa cabang
bar
dan menjalankangit rebase foo
setbar
cabang ke riwayat yang sama seperti memeriksa cabangfoo
dan menjalankangit cherry-pick ..bar
akan ditetapkanfoo
menjadi (perubahan darifoo
, diikuti oleh perubahan daribar
).Dari segi penamaan, perbedaan antara dua perintah dapat diingat karena masing-masing menjelaskan apa yang dilakukannya pada cabang saat ini :
rebase
menjadikan kepala yang lain sebagai basis baru untuk perubahan Anda, sedangkancherry-pick
mengambil perubahan dari cabang lain dan meletakkannya di atas AndaHEAD
(seperti ceri di atas sundae).sumber
Keduanya melakukan hal yang sangat mirip; Perbedaan konseptual utamanya adalah (dalam istilah yang disederhanakan) bahwa:
rebase memindahkan komit dari cabang saat ini ke cabang lain .
salinan cherry-pick melakukan dari cabang lain ke cabang saat ini .
Menggunakan diagram yang mirip dengan jawaban @Ken Ho :
Diberikan keadaan awal ini:
... dan dengan asumsi bahwa Anda ingin komit dari
topic
cabang diputar ulang di atasmaster
cabang saat ini , Anda memiliki dua opsi:Menggunakan rebase: Pertama-tama Anda pergi ke
topic
by doinggit checkout topic
, dan kemudian pindahkan cabang dengan menjalankangit rebase master
, menghasilkan:Hasil: cabang Anda saat
topic
ini di-rebased (dipindahkan) kemaster
.The
topic
cabang telah diupdate, sedangkanmaster
cabang tetap di tempat.Menggunakan cherry-pick : pertama-tama Anda akan pergi
master
dengan melakukangit checkout master
, dan kemudian menyalin cabang dengan menjalankangit cherry-pick topic~3..topic
(atau, setara,git cherry-pick B..G
), menghasilkan:Hasil: komit dari
topic
yang disalin ke dalammaster
.The
master
cabang telah diupdate, sedangkantopic
cabang tetap di tempat.Tentu saja, di sini Anda harus secara eksplisit memberi tahu cherry-pick untuk memilih urutan komit , menggunakan notasi rentang
foo..bar
. Jika Anda hanya memberikan nama cabang, seperti digit cherry-pick topic
, itu hanya akan mengambil komit di ujung cabang, menghasilkan:sumber