Kapan direkomendasikan untuk menggunakan Git rebase vs. Git merge?
Apakah saya masih perlu bergabung setelah rebase yang berhasil?
Kapan direkomendasikan untuk menggunakan Git rebase vs. Git merge?
Apakah saya masih perlu bergabung setelah rebase yang berhasil?
Jawaban:
Jadi kapan Anda menggunakan keduanya?
init
repo baru, add
file dan commit
. Periksa cabang fitur baru ( checkout -b feature
.) Ubah file teks, komit dan ulangi sehingga ada dua komitmen baru pada cabang fitur. Lalu checkout master
dan merge feature
. Di log
, saya melihat komit awal saya pada master, diikuti oleh dua yang digabungkan dari fitur. Jika Anda merge --squash feature
, fitur digabung menjadi master tetapi tidak berkomitmen, sehingga satu-satunya commit baru pada master akan menjadi yang Anda buat sendiri.
Itu mudah. Dengan rebase Anda mengatakan untuk menggunakan cabang lain sebagai basis baru untuk pekerjaan Anda.
Jika Anda memiliki, misalnya, cabang master
, Anda membuat cabang untuk mengimplementasikan fitur baru, dan mengatakan Anda beri nama cool-feature
, tentu saja cabang master adalah basis untuk fitur baru Anda.
Sekarang pada titik tertentu Anda ingin menambahkan fitur baru yang Anda terapkan di master
cabang. Anda bisa beralih ke master
dan menggabungkan cool-feature
cabang:
$ git checkout master
$ git merge cool-feature
Tapi dengan cara ini dummy commit baru ditambahkan. Jika Anda ingin menghindari sejarah spageti, Anda dapat rebase :
$ git checkout cool-feature
$ git rebase master
Dan kemudian menggabungkannya dalam master
:
$ git checkout master
$ git merge cool-feature
Kali ini, karena cabang topik memiliki komit yang sama ditambah komit dengan fitur baru, penggabungan akan menjadi langkah maju.
but this way a new dummy commit is added, if you want to avoid spaghetti-history
- bagaimana kabar buruknya?
Sean Schofield
dimasukkan pengguna dalam komentar: "Rebase juga bagus karena sekali Anda akhirnya menggabungkan barang-barang Anda kembali ke master (yang sepele seperti yang sudah dijelaskan) Anda memilikinya duduk di" atas "dari sejarah komit Anda. memproyeksikan di mana fitur dapat ditulis tetapi digabung beberapa minggu kemudian, Anda tidak ingin hanya menggabungkan mereka ke dalam master karena mereka "dimasukkan" ke dalam master jalan kembali dalam sejarah. Secara pribadi saya suka bisa melakukan git log dan melihat fitur baru-baru ini tepat di "atas." Perhatikan tanggal komit dipertahankan - rebase tidak mengubah informasi itu. "
merge
, rebase
, fast-forward
, dll) mengacu pada manipulasi tertentu dari grafik asiklik diarahkan. Mereka menjadi lebih mudah untuk berpikir dengan model mental itu dalam pikiran.
Untuk melengkapi jawaban saya sendiri yang disebutkan oleh TSamper ,
rebase seringkali merupakan ide yang baik untuk dilakukan sebelum penggabungan, karena idenya adalah bahwa Anda mengintegrasikan Y
pekerjaan cabang Anda di cabang B
yang akan Anda gabungkan.
Tetapi sekali lagi, sebelum penggabungan, Anda menyelesaikan konflik apa pun di cabang Anda (yaitu: "rebase", seperti dalam "memutar ulang pekerjaan saya di cabang saya mulai dari titik baru-baru ini dari cabang B
).
Jika dilakukan dengan benar, penggabungan berikutnya dari cabang Anda ke cabang B
bisa maju cepat.
gabungan secara langsung berdampak pada cabang tujuan B
, yang berarti gabungan sebaiknya sepele, jika tidak cabang itu B
bisa lama untuk kembali ke keadaan stabil (waktu untuk Anda menyelesaikan semua konflik)
titik penggabungan setelah rebase?
Dalam hal yang saya jelaskan, saya B
naik ke cabang saya, hanya untuk memiliki kesempatan untuk memutar ulang pekerjaan saya dari titik yang lebih baru B
, tetapi sambil tetap berada di cabang saya.
Dalam hal ini, penggabungan masih diperlukan untuk membawa pekerjaan "replayed" saya B
.
Skenario lain ( dijelaskan dalam Git Ready misalnya), adalah membawa pekerjaan Anda langsung B
melalui rebase (yang menghemat semua komitmen baik Anda, atau bahkan memberi Anda kesempatan untuk memesan ulang melalui rebase interaktif).
Dalam hal itu (di mana Anda rebase saat berada di cabang B), Anda benar: tidak diperlukan penggabungan lebih lanjut:
Sebuah pohon Git secara default ketika kami belum bergabung atau rebased
kita dapatkan dengan rebasing:
Skenario kedua adalah semua tentang: bagaimana cara mendapatkan fitur baru kembali menjadi master.
Maksud saya, dengan menggambarkan skenario rebase pertama, adalah untuk mengingatkan semua orang bahwa rebase juga dapat digunakan sebagai langkah awal untuk itu (yaitu "mendapatkan fitur baru kembali menjadi master").
Anda dapat menggunakan rebase untuk pertama kali membawa master "dalam" cabang fitur baru: rebase akan memutar ulang fitur baru yang dilakukan dari HEAD master
, tetapi masih di cabang fitur baru, secara efektif memindahkan titik awal cabang Anda dari komit master lama HEAD-master
.
Itu memungkinkan Anda untuk menyelesaikan konflik apa pun di cabang Anda (artinya, dalam isolasi, sambil memungkinkan master untuk terus berkembang secara paralel jika tahap resolusi konflik Anda terlalu lama).
Kemudian Anda dapat beralih ke master dan menggabungkan new-feature
(atau rebase new-feature
ke master
jika Anda ingin mempertahankan komit dilakukan di Andanew-feature
cabang).
Begitu:
master
,.Jika Anda ragu, gunakan gabungan.
Satu-satunya perbedaan antara rebase dan gabungan adalah:
Jadi jawaban singkatnya adalah memilih rebase atau gabung berdasarkan seperti apa Anda ingin sejarah Anda terlihat .
Ada beberapa faktor yang harus Anda pertimbangkan ketika memilih operasi mana yang akan digunakan.
Jika demikian, jangan rebase. Rebase menghancurkan cabang dan pengembang-pengembang itu akan merusak / repositori yang tidak konsisten kecuali jika mereka gunakan git pull --rebase
. Ini adalah cara yang baik untuk membuat marah pengembang lain dengan cepat.
Rebase adalah operasi yang merusak. Itu berarti, jika Anda tidak menerapkannya dengan benar, Anda dapat kehilangan pekerjaan yang dilakukan dan / atau merusak konsistensi repositori pengembang lainnya.
Saya telah bekerja pada tim-tim tempat semua pengembang berasal dari masa ketika perusahaan dapat membeli staf yang berdedikasi untuk menangani percabangan dan penggabungan. Pengembang itu tidak tahu banyak tentang Git dan tidak ingin tahu banyak. Dalam tim ini saya tidak akan mengambil risiko merekomendasikan rebiling dengan alasan apa pun.
Beberapa tim menggunakan model branch-per-feature di mana setiap cabang mewakili fitur (atau perbaikan bug, atau sub-fitur, dll.) Dalam model ini cabang membantu mengidentifikasi set komit terkait. Sebagai contoh, seseorang dapat dengan cepat mengembalikan fitur dengan mengembalikan gabungan cabang itu (agar adil, ini adalah operasi yang jarang terjadi). Atau perbaiki fitur dengan membandingkan dua cabang (lebih umum). Rebase akan menghancurkan cabang dan ini tidak akan langsung.
Saya juga bekerja pada tim yang menggunakan model branch-per-developer (kita semua pernah ke sana). Dalam hal ini cabang itu sendiri tidak menyampaikan informasi tambahan (komit sudah memiliki penulis). Tidak akan ada salahnya rebasing.
Mengembalikan (seperti dalam kehancuran) suatu rebase adalah sangat sulit dan / atau tidak mungkin (jika rebase memiliki konflik) dibandingkan dengan mengembalikan suatu penggabungan. Jika Anda berpikir ada kemungkinan Anda ingin kembali, gunakan penggabungan.
Operasi rebase perlu ditarik dengan yang sesuai git pull --rebase
. Jika Anda bekerja sendiri, Anda mungkin dapat mengingat mana yang harus Anda gunakan pada waktu yang tepat. Jika Anda bekerja dalam tim, ini akan sangat sulit untuk dikoordinasikan. Inilah sebabnya mengapa sebagian besar alur kerja rebase merekomendasikan penggunaan rebase untuk semua penggabungan (dan git pull --rebase
untuk semua tarikan).
Dengan asumsi Anda memiliki gabungan berikut:
B -- C
/ \
A--------D
Beberapa orang akan menyatakan bahwa penggabungan "menghancurkan" sejarah komit karena jika Anda melihat log hanya cabang master (A - D) Anda akan kehilangan pesan komit penting yang terkandung dalam B dan C.
Jika ini benar, kami tidak akan memiliki pertanyaan seperti ini . Pada dasarnya, Anda akan melihat B dan C kecuali jika Anda secara eksplisit meminta untuk tidak melihatnya (menggunakan --first-parent). Ini sangat mudah untuk dicoba sendiri.
Kedua pendekatan bergabung secara berbeda, tetapi tidak jelas bahwa satu selalu lebih baik daripada yang lain dan mungkin tergantung pada alur kerja pengembang. Misalnya, jika pengembang cenderung melakukan komitmen secara rutin (mis. Mungkin mereka berkomitmen dua kali sehari saat mereka beralih dari kantor ke rumah) maka mungkin ada banyak komitmen untuk cabang tertentu. Banyak dari komitmen tersebut mungkin tidak terlihat seperti produk akhir (saya cenderung memperbaiki pendekatan saya satu atau dua kali per fitur). Jika orang lain sedang mengerjakan bidang kode yang terkait dan mereka mencoba untuk mengubah perubahan saya itu bisa menjadi operasi yang cukup membosankan.
Jika Anda ingin alias rm
untuk rm -rf
"menghemat waktu" maka mungkin rebase adalah untuk Anda.
Saya selalu berpikir bahwa suatu hari nanti saya akan menemukan skenario di mana Git rebase adalah alat yang luar biasa yang memecahkan masalah. Sama seperti saya pikir saya akan menemukan skenario di mana Git reflog adalah alat yang luar biasa yang memecahkan masalah saya. Saya telah bekerja dengan Git selama lebih dari lima tahun sekarang. Itu belum terjadi.
Sejarah berantakan tidak pernah benar-benar menjadi masalah bagi saya. Saya tidak pernah hanya membaca sejarah komit saya seperti novel yang menarik. Sebagian besar waktu saya membutuhkan sejarah saya akan menggunakan menyalahkan Git atau membagi dua Git. Dalam hal itu, memiliki komit gabungan benar-benar berguna bagi saya, karena jika gabungan tersebut memperkenalkan masalah, itu adalah informasi yang berarti bagi saya.
Saya merasa berkewajiban untuk menyebutkan bahwa saya secara pribadi telah melunak menggunakan rebase meskipun saran umum saya masih berlaku. Saya baru-baru ini banyak berinteraksi dengan proyek Angular 2 Material . Mereka telah menggunakan rebase untuk menjaga riwayat commit yang sangat bersih. Ini memungkinkan saya untuk dengan mudah melihat komit mana yang memperbaiki cacat yang diberikan dan apakah komit itu termasuk dalam rilis. Ini berfungsi sebagai contoh yang bagus untuk menggunakan rebase dengan benar.
Banyak jawaban di sini mengatakan bahwa menggabungkan mengubah semua komit Anda menjadi satu, dan karenanya menyarankan untuk menggunakan rebase untuk mempertahankan komit Anda. Ini salah. Dan ide yang buruk jika Anda sudah mendorong komitmen Anda .
Gabung tidak melenyapkan komitmen Anda. Gabung menjaga sejarah! (lihat saja gitk) Rebase riwayat penulisan ulang, yang merupakan Hal Buruk setelah Anda mendorongnya .
Gunakan penggabungan - jangan rebase kapan pun Anda sudah mendorong.
Ini Linus (penulis Git) mengambil alih (sekarang di-host di blog saya sendiri, seperti yang dipulihkan oleh Mesin Wayback ). Ini bacaan yang sangat bagus.
Atau Anda dapat membaca versi saya sendiri dari ide yang sama di bawah ini.
Rebasing cabang pada master:
Sebaliknya, menggabungkan cabang topik menjadi master:
TLDR: Itu tergantung pada apa yang paling penting - sejarah yang rapi atau representasi sebenarnya dari urutan pembangunan
Jika riwayat rapi adalah yang paling penting, maka Anda akan rebase pertama dan kemudian menggabungkan perubahan Anda, jadi jelas apa kode baru itu. Jika Anda telah mendorong cabang Anda, jangan rebase kecuali Anda dapat mengatasi konsekuensinya.
Jika representasi urutan yang benar adalah yang paling penting, Anda akan bergabung tanpa rebasing.
Menggabungkan berarti: Membuat satu komit baru yang menggabungkan perubahan saya ke tujuan. Catatan: Komit baru ini akan memiliki dua orang tua - komit terbaru dari serangkaian komit Anda dan komit terbaru dari cabang lain yang Anda gabungkan.
Rebase berarti: Buat serangkaian komit baru, menggunakan set komit saya saat ini sebagai petunjuk. Dengan kata lain, hitung seperti apa perubahan saya seandainya saya mulai membuatnya dari saat saya melanjutkan. Karena itu, setelah rebase, Anda mungkin perlu menguji kembali perubahan Anda dan selama rebase, Anda mungkin akan mengalami beberapa konflik.
Mengingat ini, mengapa Anda akan rebase? Hanya untuk menjaga sejarah perkembangan tetap jelas. Katakanlah Anda sedang mengerjakan fitur X dan ketika Anda selesai, Anda menggabungkan perubahan Anda. Tujuan sekarang akan memiliki satu komit yang akan mengatakan sesuatu di sepanjang baris "Fitur tambahan X". Sekarang, alih-alih penggabungan, jika Anda diubah kembali dan kemudian digabungkan, riwayat pengembangan tujuan akan berisi semua komitmen individu dalam satu perkembangan logis tunggal. Ini membuat meninjau perubahan nanti lebih mudah. Bayangkan betapa sulitnya Anda untuk meninjau riwayat pengembangan jika 50 pengembang menggabungkan berbagai fitur setiap saat.
Yang mengatakan, jika Anda sudah mendorong cabang yang Anda kerjakan di hulu, Anda tidak harus rebase, tetapi gabungkan Untuk cabang yang belum didorong ke hulu, rebase, uji dan gabungkan.
Waktu lain Anda mungkin ingin melakukan rebase adalah ketika Anda ingin menghilangkan komitmen dari cabang Anda sebelum mendorong hulu. Sebagai contoh: Komit yang memperkenalkan beberapa kode debug sejak awal dan komit lainnya lebih lanjut pada yang membersihkan kode itu. Satu-satunya cara untuk melakukan ini adalah dengan melakukan rebase interaktif:git rebase -i <branch/commit/tag>
UPDATE: Anda juga ingin menggunakan rebase ketika Anda menggunakan Git untuk antarmuka ke sistem kontrol versi yang tidak mendukung sejarah non-linear ( Subversion misalnya). Saat menggunakan jembatan git-svn, sangat penting bahwa perubahan yang Anda gabungkan kembali ke Subversion adalah daftar perubahan yang berurutan di atas perubahan terbaru dalam trunk. Hanya ada dua cara untuk melakukan itu: (1) Membuat ulang perubahan secara manual dan (2) Menggunakan perintah rebase, yang jauh lebih cepat.
UPDATE 2: Salah satu cara tambahan untuk memikirkan rebase adalah bahwa hal itu memungkinkan semacam pemetaan dari gaya pengembangan Anda ke gaya yang diterima dalam repositori yang Anda komit. Katakanlah Anda suka melakukan dalam potongan kecil, kecil. Anda memiliki satu komit untuk memperbaiki kesalahan ketik, satu komit untuk menyingkirkan kode yang tidak digunakan dan sebagainya. Pada saat Anda menyelesaikan apa yang perlu Anda lakukan, Anda memiliki serangkaian komitmen yang panjang. Sekarang katakanlah repositori yang Anda komit untuk mendorong komit besar, jadi untuk pekerjaan yang Anda lakukan, orang akan mengharapkan satu atau mungkin dua komit. Bagaimana Anda mengambil komitmen Anda dan mengompres mereka ke apa yang diharapkan? Anda akan menggunakan rebase interaktif dan remas komit kecil Anda menjadi potongan yang lebih sedikit. Hal yang sama berlaku jika kebalikannya diperlukan - jika gaya Anda adalah beberapa komit besar, tetapi repositori menuntut serangkaian komitmen kecil. Anda akan menggunakan rebase untuk melakukannya juga. Jika Anda telah bergabung sebagai gantinya, Anda sekarang telah mencangkokkan gaya komit Anda ke repositori utama. Jika ada banyak pengembang, Anda bisa membayangkan betapa sulitnya mengikuti sejarah dengan beberapa gaya komit yang berbeda setelah beberapa waktu.
UPDATE 3: Does one still need to merge after a successful rebase?
Ya, benar. Alasannya adalah bahwa rebase pada dasarnya melibatkan "pengalihan" komitmen. Seperti yang saya katakan di atas, komit-komit ini dihitung, tetapi jika Anda memiliki 14 komit dari titik percabangan, maka dengan asumsi tidak ada yang salah dengan rebase Anda, Anda akan 14 komit di depan (dari poin yang Anda rebound) setelah rebase dilakukan. Anda memiliki cabang sebelum rebase. Anda akan memiliki cabang dengan panjang yang sama setelahnya. Anda masih perlu menggabungkan sebelum mempublikasikan perubahan Anda. Dengan kata lain, rebase sebanyak yang Anda inginkan (sekali lagi, hanya jika Anda belum mendorong perubahan Anda ke atas). Gabungkan hanya setelah Anda rebase.
git merge
mendukung --no-ff
opsi yang memaksanya untuk membuat komit gabungan.
Meskipun penggabungan jelas merupakan cara termudah dan paling umum untuk mengintegrasikan perubahan, itu bukan satu-satunya: Rebase adalah cara alternatif integrasi.
Memahami Gabung Sedikit Lebih Baik
Ketika Git melakukan penggabungan, Git mencari tiga komit:
Komitmen Maju Cepat atau Gabung
Dalam kasus yang sangat sederhana, salah satu dari dua cabang tidak memiliki komitmen baru sejak percabangan terjadi - komit terbaru masih merupakan leluhur bersama.
Dalam hal ini, melakukan integrasi itu benar-benar sederhana: Git bisa menambahkan semua komit dari cabang lain di atas komit leluhur yang sama. Di Git, bentuk integrasi paling sederhana ini disebut gabungan "maju cepat". Kedua cabang kemudian berbagi sejarah yang sama persis.
Namun, dalam banyak kasus, kedua cabang bergerak maju secara individual.
Untuk membuat integrasi, Git harus membuat komit baru yang berisi perbedaan di antara mereka - komit gabungan.
Komitmen Manusia & Komitmen Gabung
Biasanya, komit dibuat dengan hati-hati oleh manusia. Ini adalah unit yang bermakna yang hanya membungkus perubahan terkait dan membubuhi keterangan dengan komentar.
Komitmen gabungan sedikit berbeda: alih-alih dibuat oleh pengembang, itu dibuat secara otomatis oleh Git. Dan alih-alih membungkus satu set perubahan terkait, tujuannya adalah untuk menghubungkan dua cabang, seperti simpul. Jika Anda ingin memahami operasi gabungan nanti, Anda perlu melihat sejarah kedua cabang dan grafik komit yang sesuai.
Integrasi dengan Rebase
Beberapa orang memilih untuk pergi tanpa komitmen penggabungan otomatis tersebut. Sebaliknya, mereka ingin sejarah proyek terlihat seolah-olah telah berkembang dalam satu garis lurus. Tidak ada indikasi yang tersisa bahwa itu telah dipecah menjadi beberapa cabang di beberapa titik.
Mari kita berjalan melalui operasi rebase langkah demi langkah. Skenarionya sama seperti pada contoh sebelumnya: kami ingin mengintegrasikan perubahan dari cabang-B ke cabang-A, tetapi sekarang dengan menggunakan rebase.
Kami akan melakukan ini dalam tiga langkah
git rebase branch-A // Synchronises the history with branch-A
git checkout branch-A // Change the current branch to branch-A
git merge branch-B // Merge/take the changes from branch-B to branch-A
Pertama, Git akan "membatalkan" semua komit pada cabang-A yang terjadi setelah garis mulai bercabang (setelah leluhur bersama melakukan). Namun, tentu saja, itu tidak akan mengabaikan mereka: Anda dapat menganggap komit tersebut sebagai "disimpan sementara".
Selanjutnya, ini menerapkan komit dari cabang-B yang ingin kita integrasikan. Pada titik ini, kedua cabang terlihat persis sama.
Pada langkah terakhir, komit baru pada cabang-A sekarang diterapkan kembali - tetapi pada posisi baru, di atas komit terintegrasi dari cabang-B (didasarkan kembali).
Hasilnya terlihat seperti perkembangan yang terjadi dalam garis lurus. Alih-alih komit gabungan yang berisi semua perubahan gabungan, struktur komit asli dipertahankan.
Akhirnya, Anda mendapatkan cabang cabang-A yang bersih tanpa komitmen yang tidak diinginkan dan dihasilkan secara otomatis.
Catatan: Diambil dari pos luar biasa oleh git-tower
. The kelemahan dari rebase
ini juga baik dibaca dalam posting yang sama.
Sebelum bergabung / rebase:
A <- B <- C [master]
^
\
D <- E [branch]
Setelah git merge master
:
A <- B <- C
^ ^
\ \
D <- E <- F
Setelah git rebase master
:
A <- B <- C <- D' <- E'
(A, B, C, D, E dan F adalah komitmen)
Contoh ini dan banyak informasi lainnya yang diilustrasikan dengan baik tentang Git dapat ditemukan di Git The Basics Tutorial .
Kalimat ini menerimanya:
Secara umum, cara untuk mendapatkan yang terbaik dari kedua dunia adalah dengan rebase perubahan lokal yang telah Anda buat, tetapi belum dibagikan, sebelum Anda mendorongnya untuk membersihkan cerita Anda, tetapi tidak pernah rebase apa pun yang Anda mendorong di suatu tempat .
Jawaban ini berorientasi luas di sekitar Git Flow . Tabel-tabel telah dihasilkan dengan Generator Tabel ASCII yang bagus , dan pohon-pohon sejarah dengan perintah yang luar biasa ini ( alias sebagai git lg
):
git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
Tabel dalam urutan kronologis terbalik agar lebih konsisten dengan pohon sejarah. Lihat juga perbedaan antara git merge
dan git merge --no-ff
pertama (Anda biasanya ingin menggunakan git merge --no-ff
karena membuat sejarah Anda terlihat lebih dekat dengan kenyataan):
git merge
Perintah:
Time Branch "develop" Branch "features/foo"
------- ------------------------------ -------------------------------
15:04 git merge features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
| Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
| Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge --no-ff
Perintah:
Time Branch "develop" Branch "features/foo"
------- -------------------------------- -------------------------------
15:04 git merge --no-ff features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/ Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge
vs. git rebase
Poin pertama: selalu menggabungkan fitur ke dalam pengembangan, tidak pernah rebase mengembangkan dari fitur . Ini adalah konsekuensi dari Aturan Emas Rebasing :
Aturan emas
git rebase
adalah untuk tidak pernah menggunakannya di cabang publik .
Jangan pernah rebase apapun yang Anda dorong ke suatu tempat.
Saya pribadi akan menambahkan: kecuali itu cabang fitur DAN Anda dan tim Anda sadar akan konsekuensinya .
Jadi pertanyaan git merge
vs git rebase
berlaku hampir hanya untuk cabang fitur (dalam contoh berikut, --no-ff
selalu digunakan saat penggabungan). Perhatikan bahwa karena saya tidak yakin ada satu solusi yang lebih baik ( ada perdebatan ), saya hanya akan memberikan bagaimana kedua perintah berperilaku. Dalam kasus saya, saya lebih suka menggunakan git rebase
karena menghasilkan pohon sejarah yang lebih bagus :)
git merge
Perintah:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\ Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | | Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | | Fourth commit - Christophe
* | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \ Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Perintah:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git rebase features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
develop
ke cabang fiturgit merge
Perintah:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git merge --no-ff develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\ Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | | Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ / Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Perintah:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git rebase develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git cherry-pick
Ketika Anda hanya perlu satu komit tertentu, git cherry-pick
adalah solusi yang bagus ( -x
opsi menambahkan baris yang mengatakan " (cherry pick from komit ...) " ke badan pesan komit asli, jadi biasanya ide yang baik untuk menggunakannya - git log <commit_sha1>
untuk melihat Itu):
Perintah:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git cherry-pick -x <second_commit_sha1>
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Hasil:
* 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| | Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git pull --rebase
Saya tidak yakin saya bisa menjelaskannya lebih baik daripada Derek Gourlay ... Pada dasarnya, gunakan git pull --rebase
alih-alih git pull
:) Yang hilang dalam artikel ini adalah Anda dapat mengaktifkannya secara default :
git config --global pull.rebase true
git rerere
Sekali lagi, dijelaskan dengan baik di sini . Tapi sederhananya, jika Anda mengaktifkannya, Anda tidak perlu menyelesaikan konflik yang sama beberapa kali lagi.
Buku Pro Git memiliki penjelasan yang sangat bagus di halaman rebasing .
Pada dasarnya penggabungan akan mengambil dua komit dan menggabungkannya.
Rebase akan diberikan kepada leluhur yang sama pada keduanya dan secara bertahap menerapkan perubahan di atas satu sama lain. Ini membuat 'bersih' dan sejarah yang lebih linier.
Tetapi ketika Anda rebase, Anda meninggalkan komit sebelumnya dan membuat yang baru. Jadi, Anda tidak boleh me-rebase repositori yang bersifat publik. Orang lain yang mengerjakan repositori akan membencimu.
Untuk alasan itu saja saya hampir secara eksklusif bergabung. 99% waktu cabang saya tidak jauh berbeda, jadi jika ada konflik hanya ada di satu atau dua tempat.
Git rebase digunakan untuk membuat jalur percabangan dalam pembersih riwayat dan struktur repositori menjadi linier.
Ini juga digunakan untuk menjaga cabang yang dibuat oleh Anda pribadi, seperti setelah rebasing dan mendorong perubahan ke server, jika Anda menghapus cabang Anda, tidak akan ada bukti dari cabang yang Anda kerjakan. Jadi cabang Anda sekarang menjadi perhatian lokal Anda.
Setelah melakukan rebase, kami juga menyingkirkan komit ekstra yang biasa kami lihat jika kami melakukan penggabungan normal.
Dan ya, seseorang masih perlu melakukan penggabungan setelah rebase berhasil karena perintah rebase hanya menempatkan pekerjaan Anda di atas cabang yang Anda sebutkan selama rebase, katakanlah master, dan buat komit pertama dari cabang Anda sebagai keturunan langsung dari cabang master . Ini berarti kita sekarang dapat melakukan penggabungan maju untuk membawa perubahan dari cabang ini ke cabang master.
Beberapa contoh praktis, agak terkoneksi dengan pengembangan skala besar tempat Gerrit digunakan untuk meninjau dan mengintegrasikan pengiriman:
Saya menggabungkan ketika saya mengangkat cabang fitur saya ke master jarak jauh yang baru. Ini memberi kerja pengangkatan minimal dan mudah untuk mengikuti sejarah pengembangan fitur misalnya gitk .
git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature
Saya bergabung ketika saya menyiapkan komitmen pengiriman.
git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master
Saya rebase ketika komit pengiriman gagal integrasi dengan alasan apa pun, dan saya perlu memperbaruinya ke master jarak jauh yang baru.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
Sudah berkali-kali dijelaskan apa itu rebase dan penggabungan apa, tetapi kapan Anda harus menggunakan apa?
Kapan Anda harus menggunakan rebase?
Saat Git rebase mengubah sejarah. Karena itu Anda tidak boleh menggunakannya saat orang lain mengerjakan cabang yang sama / jika Anda mendorongnya. Tetapi jika Anda memiliki cabang lokal, Anda bisa melakukan master rebase gabungan sebelum menggabungkan cabang Anda menjadi master untuk menjaga sejarah yang lebih bersih. Melakukan ini, setelah penggabungan ke cabang master tidak akan terlihat bahwa Anda menggunakan cabang di cabang master - sejarahnya "bersih" karena Anda tidak memiliki "gabungan" yang dibuat secara otomatis, tetapi masih memiliki riwayat lengkap di cabang master Anda tanpa melakukan "digabung .." yang dilakukan secara otomatis.
Namun pastikan, Anda menggunakan git merge feature-branch --ff-only
untuk memastikan tidak ada konflik membuat komit tunggal ketika Anda menggabungkan fitur Anda kembali ke utama.Ini menarik jika Anda menggunakan cabang fitur untuk setiap tugas yang Anda kerjakan saat Anda mendapatkan riwayat cabang fitur, tetapi bukan komit "digabung .."
Skenario kedua adalah, jika Anda bercabang dari cabang dan ingin tahu apa yang telah berubah di cabang utama. Rebase memberi Anda informasi karena mencakup setiap komit.
Kapan Anda harus menggunakan gabungan?
Ketika Anda tidak perlu atau ingin memiliki semua sejarah cabang fitur di cabang master Anda atau jika orang lain bekerja pada cabang yang sama / Anda telah mendorongnya. Jika Anda masih ingin memiliki riwayat, gabungkan saja master ke cabang fitur sebelum menggabungkan cabang fitur menjadi master. Ini akan menghasilkan penggabungan maju cepat di mana Anda memiliki riwayat cabang fitur di master Anda (termasuk komit gabungan yang ada di cabang fitur Anda karena Anda menggabungkan master ke dalamnya).
Kapan saya menggunakan git rebase
? Hampir tidak pernah, karena menulis ulang sejarah. git merge
hampir selalu merupakan pilihan yang lebih disukai, karena itu menghormati apa yang sebenarnya terjadi dalam proyek Anda.