Git workflow dan rebase vs gabungkan pertanyaan

971

Saya telah menggunakan Git sekarang selama beberapa bulan pada proyek dengan satu pengembang lain. Saya memiliki beberapa tahun pengalaman dengan SVN , jadi saya rasa saya membawa banyak bagasi ke hubungan itu.

Saya telah mendengar bahwa Git sangat baik untuk percabangan dan penggabungan, dan sejauh ini, saya hanya tidak melihatnya. Tentu, percabangan itu sederhana, tetapi ketika saya mencoba untuk menggabungkan, semuanya berjalan ke neraka. Sekarang, saya sudah terbiasa dengan itu dari SVN, tetapi bagi saya sepertinya saya baru saja menukar satu sistem versi sub-par dengan yang lain.

Mitra saya memberi tahu saya bahwa masalah saya berasal dari keinginan saya untuk bergabung dengan mau tak mau, dan bahwa saya harus menggunakan rebase daripada bergabung dalam banyak situasi. Sebagai contoh, inilah alur kerja yang dia buat:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature

Pada dasarnya, buat cabang fitur, SELALU rebase dari master ke cabang, dan bergabung dari cabang kembali ke master. Penting untuk dicatat adalah bahwa cabang selalu tetap lokal.

Inilah alur kerja yang saya mulai

clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch

Ada dua perbedaan mendasar (saya pikir): Saya selalu menggunakan gabungan alih-alih rebasing, dan saya mendorong cabang fitur saya (dan cabang fitur saya komit) ke repositori jarak jauh.

Alasan saya untuk cabang jarak jauh adalah bahwa saya ingin pekerjaan saya didukung saat saya sedang bekerja. Repositori kami secara otomatis dicadangkan dan dapat dikembalikan jika terjadi kesalahan. Laptop saya tidak, atau tidak menyeluruh. Karena itu, saya benci memiliki kode pada laptop saya yang tidak dicerminkan di tempat lain.

Alasan saya untuk penggabungan bukannya rebase adalah bahwa penggabungan tampaknya menjadi standar dan rebase tampaknya merupakan fitur lanjutan. Perasaan saya adalah bahwa apa yang saya coba lakukan bukanlah pengaturan lanjutan, jadi rebase seharusnya tidak perlu. Saya bahkan membaca dengan seksama buku Pemrograman Pragmatis baru pada Git, dan mereka membahas penggabungan secara luas dan nyaris tidak menyebutkan rebase.

Ngomong-ngomong, saya mengikuti alur kerja saya di cabang baru-baru ini, dan ketika saya mencoba menggabungkannya kembali menjadi master, semuanya pergi ke neraka. Ada banyak konflik dengan hal-hal yang seharusnya tidak penting. Konflik tidak masuk akal bagi saya. Butuh satu hari bagi saya untuk menyelesaikan semuanya, dan akhirnya memuncak dengan paksa ke master jarak jauh, karena master lokal saya memiliki semua konflik diselesaikan, tetapi yang jauh masih tidak bahagia.

Apa alur kerja yang "benar" untuk sesuatu seperti ini? Git seharusnya membuat percabangan dan penggabungan menjadi sangat mudah, dan saya tidak melihatnya.

Perbarui 2011-04-15

Ini sepertinya pertanyaan yang sangat populer, jadi saya pikir saya akan memperbarui dengan pengalaman dua tahun saya sejak saya pertama kali bertanya.

Ternyata alur kerja asli sudah benar, setidaknya dalam kasus kami. Dengan kata lain, inilah yang kami lakukan dan berhasil:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature

Faktanya, alur kerja kami sedikit berbeda, karena kami cenderung melakukan penggabungan squash dan bukan penggabungan mentah. ( Catatan: Ini kontroversial, lihat di bawah. ) Ini memungkinkan kami untuk mengubah seluruh cabang fitur kami menjadi satu komit pada master. Kemudian kami menghapus cabang fitur kami. Ini memungkinkan kami untuk menyusun komit kami secara logis pada master, bahkan jika mereka sedikit berantakan di cabang kami. Jadi, inilah yang kami lakukan:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature

Kontroversi Penggabungan Squash - Seperti yang ditunjukkan beberapa komentator, penggabungan squash akan membuang semua riwayat di cabang fitur Anda. Seperti namanya, itu meremas semua komit menjadi satu. Untuk fitur kecil, ini masuk akal karena mengembunnya menjadi satu paket. Untuk fitur yang lebih besar, itu mungkin bukan ide bagus, terutama jika komitmen individu Anda sudah bersifat atom. Itu benar-benar turun ke preferensi pribadi.

Github dan Bitbucket (lain-lain?) Tarik Permintaan - Jika Anda bertanya-tanya bagaimana merger / rebase berhubungan dengan Tarik Permintaan, saya sarankan mengikuti semua langkah di atas sampai Anda siap untuk bergabung kembali ke master. Alih-alih secara manual bergabung dengan git, Anda hanya menerima PR. Perhatikan bahwa ini tidak akan melakukan penggabungan squash (setidaknya tidak secara default), tetapi non-squash, non-fast-forward adalah konvensi penggabungan yang diterima di komunitas Permintaan Tarik (sejauh yang saya tahu). Secara khusus, ini berfungsi seperti ini:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin

Saya datang untuk mencintai Git dan tidak pernah ingin kembali ke SVN. Jika Anda kesulitan, terus saja dan akhirnya Anda akan melihat cahaya di ujung terowongan.

Mikha
sumber
31
Sayangnya, buku Pragmstic Programming baru sebagian besar ditulis dari menggunakan Git sambil masih berpikir dalam SVN, dan dalam hal ini ia telah menyesatkan Anda. Dalam Git, rebase membuat hal-hal sederhana ketika mereka bisa. Pengalaman Anda bisa memberi tahu Anda bahwa alur kerja Anda tidak bekerja di Git, bukan bahwa Git tidak bekerja.
Paul
18
Saya tidak akan merekomendasikan penggabungan squash dalam kasus ini, karena tidak menyimpan informasi tentang apa yang digabungkan (seperti svn, tetapi tidak ada mergeinfo di sini).
Marius K
7
Cinta catatan di bagian bawah, saya punya pengalaman yang sama perjuangan dengan Git, tetapi sekarang berjuang untuk membayangkan tidak menggunakannya. Terima kasih atas penjelasan terakhirnya, banyak membantu dengan rebasepengertian
Jon Phenow
6
Setelah Anda menyelesaikan fitur, bukankah seharusnya Anda rebase terakhir kali sebelum menggabungkan new_feature untuk dikuasai?
Softarn
17
Alur kerja Anda kehilangan semua riwayat komit dari cabang yang dihapus :(
Max Nanasy

Jawaban:

372

"Konflik" berarti "evolusi paralel dari konten yang sama". Jadi jika itu "all to hell" selama penggabungan, itu berarti Anda memiliki evolusi besar-besaran pada set file yang sama.

Alasan mengapa rebase lebih baik daripada gabungan adalah bahwa:

  • Anda menulis ulang riwayat komit lokal Anda dengan salah satu master (dan kemudian mengajukan kembali pekerjaan Anda, menyelesaikan konflik apa pun kemudian)
  • gabungan terakhir tentu saja akan menjadi "maju cepat", karena akan memiliki semua sejarah komit master, ditambah hanya perubahan Anda untuk diterapkan kembali.

Saya mengkonfirmasi bahwa alur kerja yang benar dalam kasus itu (evolusi pada set file umum) adalah rebase pertama, lalu gabungkan .

Namun, itu berarti bahwa, jika Anda mendorong cabang lokal Anda (untuk alasan cadangan), cabang itu tidak boleh ditarik (atau setidaknya digunakan) oleh orang lain (karena sejarah komit akan ditulis ulang oleh rebase berturut-turut).


Pada topik itu (rebase lalu gabungkan alur kerja), barraponto menyebutkan dalam komentar dua posting menarik, keduanya dari randyfay.com :

Dengan menggunakan teknik ini, pekerjaan Anda selalu berjalan di atas cabang publik seperti tambalan yang mutakhir dengan arus HEAD.

(Teknik serupa ada untuk bazaar )

VONC
sumber
27
Untuk teknik yang memungkinkan rebasing dan berbagi, lihat softwareswirl.blogspot.com/2009/04/…
mhagger
2
randyfay.com/node/91 dan randyfay.com/node/89 adalah bacaan yang bagus. artikel ini membuat saya mengerti apa yang terjadi dengan alur kerja saya, dan apa alur kerja yang ideal nantinya.
Capi Etheriel
hanya untuk meluruskannya, rebasing dari cabang master ke lokal Anda pada dasarnya adalah untuk memperbarui setiap sejarah lokal Anda mungkin telah terjawab bahwa master memiliki pengetahuan setelah segala macam penggabungan?
hellatan
@dtan apa yang saya jelaskan di sini adalah rebasing lokal di atas master. Anda tidak benar-benar memperbarui sejarah lokal, melainkan menerapkan kembali sejarah lokal di atas master untuk menyelesaikan konflik di cabang lokal.
VonC
386

TL; DR

Alur kerja git rebase tidak melindungi Anda dari orang-orang yang buruk dalam penyelesaian konflik atau orang-orang yang terbiasa dengan alur kerja SVN, seperti yang disarankan dalam Menghindari Bencana Git: A Gory Story . Itu hanya membuat resolusi konflik lebih membosankan bagi mereka dan membuatnya lebih sulit untuk pulih dari resolusi konflik yang buruk. Sebaliknya, gunakan diff3 sehingga tidak begitu sulit di tempat pertama.


Alur kerja rebase tidak lebih baik untuk resolusi konflik!

Saya sangat pro-rebase untuk membersihkan sejarah. Namun jika saya pernah mencapai konflik, saya segera membatalkan rebase dan melakukan penggabungan! Benar-benar membunuh saya bahwa orang merekomendasikan alur kerja rebase sebagai alternatif yang lebih baik daripada alur kerja gabungan untuk resolusi konflik (yang persis seperti apa pertanyaan ini).

Jika itu "all to hell" selama penggabungan, itu akan "all to hell" selama rebase, dan berpotensi lebih banyak neraka juga! Inilah alasannya:

Alasan # 1: Selesaikan konflik sekali, alih-alih satu kali untuk setiap komit

Saat Anda rebase alih-alih bergabung, Anda harus melakukan resolusi konflik hingga sebanyak yang telah Anda berkomitmen untuk rebase, untuk konflik yang sama!

Skenario nyata

Saya bercabang master untuk memperbaiki metode yang rumit di cabang. Pekerjaan refactoring saya terdiri dari 15 komit total saat saya bekerja untuk refactor dan mendapatkan ulasan kode. Bagian dari refactoring saya melibatkan memperbaiki tab dan ruang campuran yang ada di master sebelumnya. Ini perlu, tapi sayangnya itu akan bertentangan dengan perubahan yang dibuat setelahnya untuk metode ini secara master. Benar saja, saat saya sedang mengerjakan metode ini, seseorang membuat perubahan sederhana, sah ke metode yang sama di cabang utama yang harus digabungkan dengan perubahan saya.

Ketika tiba waktunya untuk menggabungkan cabang saya kembali dengan master, saya memiliki dua opsi:

git merge: Saya mendapat konflik. Saya melihat perubahan yang mereka buat untuk menguasai dan menggabungkannya dengan (produk akhir) cabang saya. Selesai

git rebase: Saya mendapat konflik dengan komit pertama saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit kedua saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit ketiga saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen keempat saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen kelima saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit keenam saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan ketujuhmelakukan. Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit kedelapan saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen kesembilan saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen kesepuluh saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit kesebelas saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen kedua belas saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komit ketigabelas saya . Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan keempat belas sayamelakukan. Saya menyelesaikan konflik dan melanjutkan rebase. Saya mendapat konflik dengan komitmen kelima belas saya . Saya menyelesaikan konflik dan melanjutkan rebase.

Anda harus bercanda jika ini adalah alur kerja pilihan Anda. Yang diperlukan hanyalah perbaikan spasi putih yang konflik dengan satu perubahan yang dibuat pada master, dan setiap komit akan konflik dan harus diselesaikan. Dan ini adalah skenario sederhana dengan hanya konflik spasi putih. Surga melarang Anda memiliki konflik nyata yang melibatkan perubahan kode utama di seluruh file dan harus tekad yang beberapa kali.

Dengan semua resolusi konflik tambahan yang perlu Anda lakukan, itu hanya meningkatkan kemungkinan bahwa Anda akan membuat kesalahan . Tetapi kesalahan baik-baik saja di git karena Anda dapat membatalkan, bukan? Kecuali tentu saja ...

Alasan # 2: Dengan rebase, tidak ada yang dibatalkan!

Saya pikir kita semua bisa sepakat bahwa penyelesaian konflik bisa sulit, dan juga bahwa beberapa orang sangat buruk dalam hal itu. Itu bisa sangat rentan terhadap kesalahan, yang mengapa begitu hebat sehingga git membuatnya mudah untuk dibatalkan!

Ketika Anda menggabungkan cabang, git membuat komit gabungan yang dapat dibuang atau diubah jika resolusi konflik berjalan buruk. Bahkan jika Anda telah mendorong komit gabungan yang buruk ke repo publik / otoritatif, Anda bisa menggunakan git revertuntuk membatalkan perubahan yang diperkenalkan oleh gabungan tersebut dan mengulangi gabungan tersebut dengan benar dalam komit gabungan baru.

Saat Anda rebase cabang, dalam hal kemungkinan resolusi konflik salah, Anda kacau. Setiap komit sekarang berisi gabungan buruk, dan Anda tidak bisa hanya mengulangi rebase *. Paling-paling, Anda harus kembali dan mengubah setiap komitmen yang terpengaruh. Tidak menyenangkan.

Setelah rebase, tidak mungkin untuk menentukan apa yang awalnya merupakan bagian dari komitmen dan apa yang diperkenalkan sebagai hasil dari penyelesaian konflik yang buruk.

* Dimungkinkan untuk membatalkan rebase jika Anda dapat menggali referensi lama dari log internal git, atau jika Anda membuat cabang ketiga yang menunjuk ke komit terakhir sebelum rebasing.

Keluarkan resolusi konflik: gunakan diff3

Ambil contoh konflik ini:

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

Melihat konflik, tidak mungkin untuk mengetahui apa yang masing-masing cabang ubah atau apa maksudnya. Ini adalah alasan terbesar menurut saya mengapa resolusi konflik membingungkan dan sulit.

diff3 untuk menyelamatkan!

git config --global merge.conflictstyle diff3

Saat Anda menggunakan dif3, setiap konflik baru akan memiliki bagian ke-3, leluhur bersama yang digabungkan.

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

Pertama, periksa leluhur bersama yang digabungkan. Kemudian bandingkan setiap sisi untuk menentukan niat masing-masing cabang. Anda dapat melihat bahwa HEAD mengubah EmailMessage menjadi TextMessage. Maksudnya adalah untuk mengubah kelas yang digunakan untuk TextMessage, melewati parameter yang sama. Anda juga dapat melihat bahwa maksud fitur-cabang adalah untuk memberikan false, bukan true untuk opsi: include_timestamp. Untuk menggabungkan perubahan ini, gabungkan maksud dari keduanya:

TextMessage.send(:include_timestamp => false)

Secara umum:

  1. Bandingkan leluhur bersama dengan setiap cabang, dan tentukan cabang mana yang memiliki perubahan paling sederhana
  2. Terapkan perubahan sederhana itu ke versi kode cabang lain, sehingga berisi perubahan yang lebih sederhana dan lebih kompleks
  3. Hapus semua bagian kode konflik selain yang baru saja Anda gabungkan perubahannya

Alternatif: Putuskan dengan menerapkan perubahan cabang secara manual

Akhirnya, beberapa konflik mengerikan untuk dipahami bahkan dengan diff3. Ini terjadi terutama ketika diff menemukan garis yang sama yang tidak umum secara semantik (mis. Kedua cabang kebetulan memiliki garis kosong di tempat yang sama!). Misalnya, satu cabang mengubah lekukan tubuh kelas atau menata ulang metode yang sama. Dalam kasus ini, strategi resolusi yang lebih baik dapat memeriksa perubahan dari kedua sisi penggabungan dan secara manual menerapkan diff ke file lain.

Mari kita lihat bagaimana kita bisa menyelesaikan konflik dalam skenario di mana menggabungkan konflik origin/feature1mana lib/message.rb.

  1. Putuskan apakah cabang yang kami periksa saat ini ( HEAD, atau --ours) atau cabang yang kami gabungkan ( origin/feature1, atau --theirs) adalah perubahan yang lebih sederhana untuk diterapkan. Menggunakan diff dengan triple dot ( git diff a...b) menunjukkan perubahan yang terjadi bsejak divergensi terakhir dari a, atau dengan kata lain, membandingkan leluhur bersama a dan b dengan b.

    git diff HEAD...origin/feature1 -- lib/message.rb # show the change in feature1
    git diff origin/feature1...HEAD -- lib/message.rb # show the change in our branch
    
  2. Lihat versi file yang lebih rumit. Ini akan menghapus semua penanda konflik dan menggunakan sisi yang Anda pilih.

    git checkout --ours -- lib/message.rb   # if our branch's change is more complicated
    git checkout --theirs -- lib/message.rb # if origin/feature1's change is more complicated
    
  3. Dengan perubahan yang rumit diperiksa, tarik ke atas perbedaan dari perubahan yang lebih sederhana (lihat langkah 1). Terapkan setiap perubahan dari diff ini ke file yang bertentangan.

Edward Anderson
sumber
4
Bagaimana menggabungkan semua konflik sekaligus menjadi lebih baik daripada komitmen individu? Saya sudah mendapatkan masalah karena menggabungkan satu komitmen (terutama dari orang yang tidak membagi komitmen menjadi bagian yang logis DAN memberikan tes yang cukup untuk verifikasi). Juga, rebase tidak lebih buruk daripada menggabungkan ketika datang ke opsi cadangan, penggunaan cerdas rebase interaktif dan alat-alat seperti tortoisegit (yang memungkinkan pemilihan yang berkomitmen untuk dimasukkan) akan banyak membantu.
prusswan
8
Saya merasa seperti saya membahas alasan di # 1. Jika komitmen individu tidak konsisten secara logis, semakin banyak alasan untuk menggabungkan cabang yang konsisten secara logis, sehingga Anda dapat benar-benar memahami konflik. Jika komit 1 bermasalah dan komit 2 memperbaikinya, menggabungkan komit 1 akan membingungkan. Ada alasan sah Anda mungkin mendapatkan 15 konflik berturut-turut, seperti yang saya uraikan di atas. Argumen Anda untuk rebase tidak menjadi lebih buruk agak tidak berdasar. Rebase mencampurkan penggabungan buruk ke dalam komitmen baik awal dan tidak meninggalkan komitmen baik di sekitar untuk membiarkan Anda mencoba lagi. Menggabungkan tidak.
Edward Anderson
6
Saya sepenuhnya setuju dengan Anda nilbus. Pos yang bagus; yang membersihkan beberapa hal. Saya bertanya-tanya apakah rerere akan membantu di sini. Juga, terima kasih atas sarannya menggunakan diff3, saya pasti akan beralih yang di sekarang.
derick
45
Saya memberi tahu saya tentang diff3 saja - seberapa sering melihat pada konflik yang tidak dapat dipahami mengutuk siapa pun yang bertanggung jawab karena tidak memberi tahu saya apa yang dikatakan oleh leluhur umum. Terima kasih banyak.
John
4
Ini seharusnya jawaban yang diterima. Alur kerja rebase juga mengerikan karena menyembunyikan fakta bahwa ada perbedaan besar dalam basis kode di beberapa titik waktu, yang mungkin berguna untuk mengetahui jika Anda ingin memahami bagaimana kode yang Anda lihat ditulis. Hanya cabang kecil yang tidak konflik yang harus diubah menjadi master.
Robert Rüger
32

Dalam alur kerja saya, saya rebase sebanyak mungkin (dan saya sering mencoba melakukannya. Tidak membiarkan perbedaan menumpuk secara drastis mengurangi jumlah dan tingkat keparahan tabrakan antar cabang).

Namun, bahkan di sebagian besar alur kerja berbasis rebase, ada tempat untuk penggabungan.

Ingat bahwa penggabungan sebenarnya menciptakan simpul yang memiliki dua orang tua. Sekarang pertimbangkan situasi berikut: Saya memiliki dua fitur dedak independen A dan B, dan sekarang ingin mengembangkan hal-hal pada fitur cabang C yang tergantung pada A dan B, sementara A dan B sedang ditinjau.

Apa yang saya lakukan, adalah sebagai berikut:

  1. Buat (dan checkout) cabang C di atas A.
  2. Gabungkan dengan B

Sekarang cabang C menyertakan perubahan dari A dan B, dan saya bisa terus mengembangkannya. Jika saya melakukan perubahan apa pun ke A, maka saya merekonstruksi grafik cabang dengan cara berikut:

  1. buat cabang T di bagian atas baru A
  2. menggabungkan T dengan B
  3. rebase C ke T
  4. hapus cabang T

Dengan cara ini saya benar-benar dapat mempertahankan grafik cabang yang berubah-ubah, tetapi melakukan sesuatu yang lebih kompleks daripada situasi yang dijelaskan di atas sudah terlalu rumit, mengingat bahwa tidak ada alat otomatis untuk melakukan rebasing ketika induknya berubah.

Alex Gontmakher
sumber
1
Anda dapat mencapai hal yang sama hanya dengan rebases. Penggabungan sebenarnya tidak perlu di sini (kecuali jika Anda tidak ingin menduplikasi komit - tapi saya hampir tidak melihat itu sebagai argumen).
odwl
1
Memang saya tidak ingin menduplikasi komitmen. Saya ingin menjaga struktur penerbangan dalam pekerjaan saya sebersih mungkin. Tapi itu masalah selera pribadi dan belum tentu cocok untuk semua orang.
Alex Gontmakher
Saya 100% setuju dengan paragraf pertama. (@ Edward jawaban bekerja di mana bukan itu masalahnya, tapi saya lebih suka semua proyek di dunia bekerja seperti yang Anda sarankan). Sisa dari jawaban tampaknya agak masuk akal dalam arti bahwa bekerja pada C sementara A dan B sedang berlangsung sudah agak berisiko (setidaknya sejauh itu benar - benar tergantung pada A dan B), dan bahkan pada akhirnya Anda mungkin tidak akan mempertahankan penggabungan (C akan mendapatkan rebased di atas yang terbaru & terhebat).
Alois Mahdal
23

JANGAN gunakan git push origin --mirror DI BAWAH SELURUH SINGKAT.

Itu tidak menanyakan apakah Anda yakin ingin melakukan ini, dan Anda sebaiknya yakin, karena itu akan menghapus semua cabang jauh Anda yang tidak ada di kotak lokal Anda.

http://twitter.com/dysinger/status/1273652486

Scott Brown
sumber
6
Atau jangan lakukan hal-hal yang Anda tidak yakin hasilnya akan seperti apa? Mesin yang saya gunakan untuk admin miliki Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions di MOTD.
richo
gunakan itu jika Anda memiliki repo mirrored (walaupun dalam kasus saya ini sekarang dijalankan oleh pengguna khusus pada repo sumber pada kait pasca-terima)
prusswan
14

Saya punya satu pertanyaan setelah membaca penjelasan Anda: Mungkinkah Anda tidak pernah melakukan

git checkout master
git pull origin
git checkout my_new_feature

sebelum melakukan 'git rebase / merge master' di cabang fitur Anda?

Karena cabang master Anda tidak akan diperbarui secara otomatis dari repositori teman Anda. Anda harus melakukannya dengan git pull origin. Yaitu mungkin Anda akan selalu rebase dari cabang master lokal yang tidak pernah berubah? Dan kemudian datanglah waktu push, Anda mendorong dalam repositori yang memiliki (lokal) melakukan Anda tidak pernah melihat dan dengan demikian push gagal.

knweiss
sumber
13

Dalam situasi Anda, saya pikir pasangan Anda benar. Apa yang baik tentang rebasing adalah bahwa bagi orang luar perubahan Anda terlihat seperti itu semua terjadi dalam urutan yang bersih sendiri. Ini berarti

  • perubahan Anda sangat mudah ditinjau
  • Anda dapat terus membuat komitmen kecil yang baik, namun Anda dapat membuat set komitmen tersebut di depan umum (dengan menggabungkan diri menjadi master) sekaligus
  • ketika Anda melihat cabang master publik Anda akan melihat serangkaian komit yang berbeda untuk fitur yang berbeda oleh pengembang yang berbeda tetapi mereka semua tidak akan dicampur

Anda masih dapat terus mendorong cabang pengembangan pribadi Anda ke repositori jarak jauh demi cadangan, tetapi orang lain tidak boleh menganggapnya sebagai cabang "publik" karena Anda akan rebasing. BTW, perintah mudah untuk melakukan ini adalah git push --mirror origin.

Artikel Pengemasan perangkat lunak menggunakan Git melakukan pekerjaan yang cukup bagus menjelaskan trade off dalam penggabungan versus rebasing. Ini konteks yang sedikit berbeda tetapi prinsipnya sama - pada dasarnya tergantung pada apakah cabang Anda publik atau pribadi dan bagaimana Anda berencana untuk mengintegrasikannya ke jalur utama.

Pat Notz
sumber
1
Tautan ke perangkat lunak Pengemasan menggunakan git tidak berfungsi lagi. Saya tidak dapat menemukan tautan yang bagus untuk mengedit jawaban asli.
Chetan
Anda tidak harus mirror untuk origin, Anda harus mirror ke repositori cadangan khusus ketiga.
Miral
12

Ngomong-ngomong, saya mengikuti alur kerja saya di cabang baru-baru ini, dan ketika saya mencoba menggabungkannya kembali menjadi master, semuanya pergi ke neraka. Ada banyak konflik dengan hal-hal yang seharusnya tidak penting. Konflik tidak masuk akal bagi saya. Butuh satu hari bagi saya untuk menyelesaikan semuanya, dan akhirnya memuncak dengan paksa ke master jarak jauh, karena master lokal saya memiliki semua konflik diselesaikan, tetapi yang jauh masih tidak bahagia.

Baik dalam alur kerja pasangan Anda maupun saran Anda seandainya Anda menemukan konflik yang tidak masuk akal. Bahkan jika Anda punya, jika Anda mengikuti alur kerja yang disarankan maka setelah resolusi dorongan 'paksa' tidak diperlukan. Ini menunjukkan bahwa Anda belum benar-benar menggabungkan cabang yang Anda dorong, tetapi harus mendorong cabang yang bukan turunan dari ujung terpencil.

Saya pikir Anda perlu melihat dengan cermat apa yang terjadi. Bisakah orang lain (dengan sengaja atau tidak) memutar ulang cabang master jarak jauh antara pembuatan cabang lokal Anda dan titik di mana Anda mencoba menggabungkannya kembali ke cabang lokal?

Dibandingkan dengan banyak sistem kontrol versi lain, saya menemukan bahwa menggunakan Git melibatkan lebih sedikit upaya melawan alat ini dan memungkinkan Anda untuk mengerjakan masalah yang mendasar bagi aliran sumber Anda. Git tidak melakukan sihir, sehingga perubahan yang saling bertentangan menyebabkan konflik, tetapi seharusnya membuatnya mudah untuk melakukan penulisan dengan melacak asal-usul komit.

CB Bailey
sumber
Anda menyiratkan bahwa OP memiliki beberapa rebase atau kesalahan yang belum ditemukan dalam prosesnya, bukan?
krosenvold
8

"Bahkan jika Anda seorang pengembang tunggal dengan hanya beberapa cabang, ada baiknya membiasakan menggunakan rebase dan bergabung dengan benar. Pola kerja dasar akan terlihat seperti:

  • Buat cabang baru B dari cabang yang ada A

  • Tambahkan / komit perubahan pada cabang B

  • Rebase pembaruan dari cabang A

  • Gabungkan perubahan dari cabang B ke cabang A "

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/

Rakka Rage
sumber
7

Dari apa yang saya amati, git merge cenderung untuk menjaga cabang terpisah bahkan setelah penggabungan, sedangkan rebase kemudian menggabungkan menggabungkannya menjadi satu cabang tunggal. Yang terakhir keluar jauh lebih bersih, sedangkan di yang pertama, akan lebih mudah untuk menemukan yang berkomitmen milik cabang mana bahkan setelah penggabungan.

Pepe
sumber
4

Dengan Git tidak ada alur kerja yang "benar". Gunakan apa pun yang mengapung perahu Anda. Namun, jika Anda terus-menerus mendapatkan konflik saat menggabungkan cabang, mungkin Anda harus mengoordinasikan upaya Anda lebih baik dengan rekan pengembang Anda? Kedengarannya seperti kalian berdua terus mengedit file yang sama. Juga, perhatikan kata kunci spasi putih dan subversi (yaitu, “$ Id $” dan lainnya).

Bombe
sumber
0

Saya hanya menggunakan alur kerja rebase, karena lebih jelas secara visual (tidak hanya di GitKraken, tetapi juga di Intellij dan masuk gitk, tetapi saya paling merekomendasikan yang pertama): Anda memiliki cabang, itu berasal dari master, dan kembali ke master . Ketika diagram itu bersih dan indah, Anda akan tahu bahwa tidak ada yang masuk neraka, selamanya .

masukkan deskripsi gambar di sini

Alur kerja saya hampir sama dengan Anda, tetapi dengan hanya satu perbedaan kecil: Saya squashmelakukan satu di cabang lokal rebasesaya sebelum cabang saya ke perubahan terbaru master, karena:

rebasebekerja berdasarkan komitmen masing - masing

yang berarti, jika Anda memiliki 15 komit yang mengubah garis yang sama dengan masterAnda, Anda harus memeriksa 15 kali jika Anda tidak menekan, tetapi yang penting adalah hasil akhirnya, bukan?

Jadi, keseluruhan alur kerjanya adalah:

  1. Periksa masterdan tarik untuk memastikan bahwa Anda memiliki versi terbaru

  2. Dari sana, buat cabang baru

  3. Lakukan pekerjaan Anda di sana, Anda dapat dengan bebas melakukan beberapa kali, dan mendorong ke jarak jauh, jangan khawatir, karena itu adalah cabang Anda .

  4. Jika seseorang memberi tahu Anda, "hei, PR / MR saya disetujui, sekarang digabung untuk dikuasai", Anda dapat mengambilnya / menariknya. Anda dapat melakukannya kapan saja, atau pada langkah 6.

  5. Setelah melakukan semua pekerjaan Anda, komitlah mereka, dan jika Anda memiliki beberapa komit, hancurkan mereka (itu semua adalah pekerjaan Anda, dan berapa kali Anda mengubah sebaris kode tidak masalah; satu-satunya yang penting adalah versi final). Dorong atau tidak, itu tidak masalah.

  6. Checkout ke master, pulllagi untuk memastikan Anda memiliki yang terbaru masterdi lokal. Diagram Anda harus serupa dengan ini:

masukkan deskripsi gambar di sini

Seperti yang Anda lihat, Anda berada di cabang lokal Anda, yang berasal dari status yang kedaluwarsa pada master, sementara master(baik lokal dan jarak jauh) telah bergerak maju dengan perubahan kolega Anda.

  1. Periksa kembali ke cabang Anda, dan rebase untuk menguasai. Anda sekarang akan memiliki satu komit saja, sehingga Anda menyelesaikan konflik hanya sekali . (Dan di GitKraken, Anda hanya perlu menyeret cabang Anda ke masterdan memilih "Rebase"; alasan lain mengapa saya menyukainya.) Setelah itu, Anda akan menjadi Suka:

masukkan deskripsi gambar di sini

  1. Jadi sekarang, Anda memiliki semua perubahan pada yang terbaru master, dikombinasikan dengan perubahan di cabang Anda. Anda sekarang dapat mendorong ke remote Anda, dan, jika Anda telah mendorong sebelumnya, Anda harus memaksa mendorong; Git akan memberi tahu Anda bahwa Anda tidak bisa begitu saja maju. Itu normal, karena rebase, Anda telah mengubah titik awal cabang Anda. Tapi Anda tidak perlu takut: gunakan kekuatan, dengan bijak . Pada akhirnya, remote juga merupakan cabang Anda sehingga Anda tidak mempengaruhi masterbahkan jika Anda melakukan sesuatu yang salah.

  2. Buat PR / MR dan tunggu sampai disetujui, sehingga masterakan memiliki kontribusi Anda. Selamat! Jadi sekarang Anda dapat checkout ke master, tarik perubahan Anda, dan hapus cabang lokal Anda untuk membersihkan diagram. Cabang jarak jauh juga harus dihapus, jika ini tidak dilakukan ketika Anda menggabungkannya ke master.

Diagram terakhir bersih dan bersih lagi:

masukkan deskripsi gambar di sini

WesternGun
sumber