Kantor saya sedang mencoba mencari tahu bagaimana kami menangani perpecahan dan penggabungan cabang, dan kami telah mengalami masalah besar.
Masalah kami adalah dengan sidebranch jangka panjang - jenis di mana Anda memiliki beberapa orang yang bekerja sidebranch yang terpisah dari master, kami berkembang selama beberapa bulan, dan ketika kami mencapai tonggak sejarah kami menyinkronkan keduanya.
Sekarang, IMHO, cara alami untuk menangani ini adalah, remas sidebranch menjadi komit tunggal. master
terus maju; sebagaimana mestinya - kita tidak secara surut membuang bulan pembangunan paralel ke master
dalam sejarah. Dan jika ada yang membutuhkan resolusi yang lebih baik untuk sejarah sidebranch, ya, tentu saja semuanya masih ada - hanya saja tidak ada master
, ada di sidebranch.
Inilah masalahnya: Saya bekerja secara eksklusif dengan baris perintah, tetapi anggota tim saya yang lain menggunakan GUIS. Dan saya telah menemukan GUIS tidak memiliki opsi yang masuk akal untuk menampilkan riwayat dari cabang lain. Jadi, jika Anda mencapai labu komit, mengatakan "perkembangan ini tergencet dari cabang XYZ
", itu besar rasa sakit untuk pergi melihat apa yang ada di XYZ
.
Pada SourceTree, sejauh yang saya bisa temukan, itu adalah sakit kepala yang sangat besar: Jika Anda aktif master
, dan Anda ingin melihat riwayat dari master+devFeature
, Anda juga perlu memeriksa master+devFeature
(menyentuh setiap file tunggal yang berbeda), atau yang lain gulirlah melalui log yang menampilkan SEMUA cabang repositori Anda secara paralel hingga Anda menemukan tempat yang tepat. Dan semoga beruntung mencari tahu di mana Anda berada di sana.
Rekan satu tim saya, dengan benar, tidak ingin memiliki sejarah pengembangan yang begitu sulit diakses. Jadi mereka ingin ini, sidebranch-development-long yang besar bergabung, selalu dengan komit gabungan. Mereka tidak ingin ada riwayat yang tidak dapat langsung diakses dari cabang utama.
Saya benci ide itu; itu berarti kusut yang tak ada habisnya, sejarah pengembangan paralel. Tetapi saya tidak melihat alternatif apa yang kita miliki. Dan saya cukup bingung; ini tampaknya menghalangi hampir semua yang saya tahu tentang manajemen cabang yang baik, dan itu akan membuat saya frustrasi terus-menerus jika saya tidak dapat menemukan solusi.
Apakah kita punya opsi di sini selain terus-menerus menggabungkan sidebranch menjadi master dengan gabungan-komitmen? Atau, adakah alasan bahwa terus menggunakan komit gabungan tidak seburuk yang saya takutkan?
git log master+bugfixDec10th
menjadi titikmerge --no-ff
yang kamu inginkan? Denganmaster
sendirinya Anda memiliki satu komit yang menjelaskan apa yang berubah di cabang, tetapi semua komit masih ada dan diasuh menjadi HEAD.Jawaban:
Meskipun saya menggunakan Git di baris perintah - saya harus setuju dengan kolega Anda. Tidak masuk akal untuk memeras perubahan besar menjadi satu komit. Anda kehilangan sejarah seperti itu, tidak hanya membuatnya kurang terlihat.
Titik kendali sumber adalah untuk melacak riwayat semua perubahan. Kapan apa yang berubah mengapa? Untuk itu, setiap komit berisi pointer ke induk, komit, dan metadata seperti pesan komit. Setiap komit menggambarkan status kode sumber dan riwayat lengkap semua perubahan yang mengarah ke status itu. Pengumpul sampah dapat menghapus komit yang tidak dapat dijangkau.
Tindakan seperti rebasing, memetik ceri, atau menekan menghapus atau menulis ulang sejarah. Secara khusus, commit yang dihasilkan tidak lagi merujuk pada commit yang asli. Pertimbangkan ini:
[1]: Beberapa server Git memungkinkan cabang dilindungi dari penghapusan tidak disengaja, tapi saya ragu Anda ingin menyimpan semua cabang fitur Anda untuk selamanya.
Sekarang Anda tidak lagi dapat mencari komit - itu tidak ada.
Merujuk nama cabang dalam pesan komit bahkan lebih buruk, karena nama cabang lokal untuk repo. Apa yang ada
master+devFeature
di checkout lokal Anda mungkin adadoodlediduh
di milik saya. Cabang hanya memindahkan label yang menunjuk ke beberapa objek komit.Dari semua teknik penulisan ulang sejarah, rebasing adalah yang paling jinak karena itu menduplikasi komitmen lengkap dengan semua sejarah mereka, dan hanya menggantikan komit orang tua.
Bahwa
master
sejarah mencakup sejarah lengkap dari semua cabang yang digabungkan ke dalamnya adalah hal yang baik, karena itu mewakili kenyataan. [2] Jika ada pengembangan paralel, itu harus terlihat di log.[2]: Untuk alasan ini, saya juga lebih suka komit gabungan eksplisit atas sejarah yang linier tapi akhirnya palsu akibat rebasing.
Pada baris perintah,
git log
berusaha keras untuk menyederhanakan riwayat yang ditampilkan dan menjaga semua komit yang ditampilkan tetap relevan. Anda dapat mengubah penyederhanaan riwayat sesuai kebutuhan Anda. Anda mungkin tergoda untuk menulis alat git log Anda sendiri yang berjalan pada grafik commit, tetapi umumnya tidak mungkin untuk menjawab "apakah komit ini awalnya dilakukan pada cabang ini atau itu?". Induk pertama gabungan komit adalah sebelumnyaHEAD
, yaitu komit di cabang yang Anda gabungkan . Tapi itu mengasumsikan bahwa Anda tidak melakukan penggabungan terbalik dari master ke cabang fitur, maka master yang diteruskan cepat ke gabungan.Solusi terbaik untuk cabang jangka panjang yang saya temui adalah mencegah cabang yang baru digabung setelah beberapa bulan. Penggabungan paling mudah bila perubahannya baru dan kecil. Idealnya, Anda akan bergabung setidaknya sekali seminggu. Integrasi berkelanjutan (seperti dalam Pemrograman Ekstrim, bukan seperti dalam "mari kita menyiapkan server Jenkins"), bahkan menyarankan beberapa penggabungan per hari, yaitu tidak mempertahankan cabang fitur yang terpisah tetapi berbagi cabang pengembangan sebagai sebuah tim. Penggabungan sebelum fitur QA akan mensyaratkan bahwa fitur disembunyikan di belakang bendera fitur.
Sebagai imbalannya, integrasi yang sering memungkinkan untuk menemukan masalah potensial jauh lebih awal, dan membantu menjaga arsitektur yang konsisten: perubahan yang jauh dimungkinkan karena perubahan ini dengan cepat dimasukkan dalam semua cabang. Jika perubahan memecah beberapa kode, itu hanya akan merusak beberapa hari, bukan beberapa bulan.
Penulisan ulang riwayat bisa masuk akal untuk proyek yang benar-benar besar ketika ada jutaan baris kode dan ratusan atau ribuan pengembang aktif. Dapat dipertanyakan mengapa proyek besar seperti itu harus menjadi repositori git tunggal daripada dibagi ke dalam perpustakaan yang terpisah, tetapi pada skala itu lebih nyaman jika repo pusat hanya berisi "rilis" dari masing-masing komponen. Misalnya kernel Linux menggunakan squashing untuk menjaga agar sejarah utama dapat dikelola. Beberapa proyek sumber terbuka memerlukan tambalan untuk dikirim melalui email, alih-alih penggabungan git-level.
sumber
git bisect
, hanya untuk mendapatkannya mencapai 10.000 baris uber-commit dari cabang samping.Saya suka jawaban Amon , tetapi saya merasa satu bagian kecil membutuhkan lebih banyak penekanan: Anda dapat dengan mudah menyederhanakan riwayat sambil melihat log untuk memenuhi kebutuhan Anda, tetapi yang lain tidak dapat menambahkan riwayat saat melihat log untuk memenuhi kebutuhan mereka. Inilah sebabnya mengapa menjaga sejarah saat itu terjadi lebih disukai.
Berikut ini contoh dari salah satu repositori kami. Kami menggunakan model tarik-permintaan, sehingga setiap fitur tampak seperti cabang Anda yang sudah berjalan lama dalam sejarah, meskipun biasanya hanya berjalan seminggu atau kurang. Pengembang individu kadang-kadang memilih untuk memeras riwayat mereka sebelum bergabung, tetapi kami sering memasangkan fitur, jadi itu relatif tidak biasa. Inilah beberapa komitmen teratas
gitk
, gui yang dibundel dengan git:Ya, agak kusut, tapi kami juga suka karena kami bisa melihat dengan tepat siapa yang berubah pada jam berapa. Secara akurat mencerminkan sejarah perkembangan kami. Jika kita ingin melihat tampilan tingkat yang lebih tinggi, satu permintaan tarik bergabung sekaligus, kita dapat melihat tampilan berikut, yang setara dengan
git log --first-parent
perintah:git log
memiliki lebih banyak opsi yang dirancang untuk memberi Anda pandangan yang Anda inginkan.gitk
dapat mengambilgit log
argumen sewenang-wenang apa pun untuk membangun tampilan grafis. Saya yakin GUI lain memiliki kemampuan serupa. Baca dokumen dan pelajari cara menggunakannya dengan benar, alih-alih menegakkangit log
pandangan pilihan Anda pada semua orang pada waktu penggabungan.sumber
merge --no-ff
- jangan gunakan penggabungan maju cepat, alih-alih selalu buat komit penggabungan sehingga--first-parent
memiliki sesuatu untuk dikerjakanPikiran pertama saya adalah - bahkan tidak melakukan ini kecuali benar-benar diperlukan. Penggabungan Anda terkadang harus menantang. Jaga agar cabang tetap independen dan berumur pendek. Ini pertanda bahwa Anda perlu memecah cerita menjadi potongan implementasi yang lebih kecil.
Jika Anda harus melakukan ini, maka dimungkinkan untuk menggabungkan git dengan opsi --no-ff sehingga sejarah disimpan berbeda di cabang mereka sendiri. Komit masih akan muncul dalam riwayat gabungan tetapi juga dapat dilihat secara terpisah pada cabang fitur sehingga setidaknya mungkin untuk menentukan jalur pengembangan mana yang menjadi bagiannya.
Saya harus mengakui ketika saya pertama kali mulai menggunakan git, saya merasa agak aneh bahwa cabang berkomitmen dalam sejarah yang sama dengan cabang utama setelah penggabungan. Agak membingungkan karena sepertinya komitmen itu tidak termasuk dalam sejarah itu. Tetapi dalam prakteknya, itu bukan sesuatu yang sangat menyakitkan sekali, jika seseorang menganggap bahwa cabang integrasi hanya itu - tujuannya adalah untuk menggabungkan cabang fitur. Di tim kami, kami tidak squash, dan kami sering menggabungkan komitmen. Kami menggunakan --no-ff setiap saat untuk memastikan bahwa mudah untuk melihat riwayat yang tepat dari fitur apa pun yang ingin kami selidiki.
sumber
git merge --no-ff
git merge --no-ff
. Jika Anda menggunakan gitflow, ini menjadi default.Biarkan saya menjawab poin Anda secara langsung dan jelas:
Anda biasanya tidak ingin membiarkan cabang Anda tidak disinkronkan selama berbulan-bulan.
Cabang fitur Anda telah bercabang dari sesuatu tergantung pada alur kerja Anda; sebut saja itu
master
demi kesederhanaan. Sekarang, kapan pun Anda berkomitmen untuk menguasainya, Anda bisa dan harus melakukannyagit checkout long_running_feature ; git rebase master
. Ini berarti bahwa cabang Anda, menurut desain, selalu sinkron.git rebase
juga hal yang benar untuk dilakukan di sini. Ini bukan hack atau sesuatu yang aneh atau berbahaya, tetapi sepenuhnya alami. Anda kehilangan sedikit informasi, yang merupakan "ulang tahun" dari cabang fitur, tetapi hanya itu. Jika beberapa orang menganggap itu penting, itu bisa diberikan dengan menyimpannya di tempat lain (dalam sistem tiket Anda, atau, jika kebutuhannya besar, dalamgit tag
...).Tidak, Anda sama sekali tidak ingin itu, Anda ingin komit gabungan. Komit gabungan juga merupakan "komit tunggal". Entah bagaimana, itu tidak memasukkan semua cabang individu melakukan "ke" master. Ini adalah komitmen tunggal dengan dua orang tua -
master
kepala dan kepala cabang pada saat penggabungan.Pastikan untuk menentukan
--no-ff
opsi, tentu saja; menggabungkan tanpa--no-ff
harus, dalam skenario Anda, dilarang keras. Sayangnya,--no-ff
ini bukan default; tapi saya yakin ada opsi yang bisa Anda atur yang membuatnya begitu. Lihatgit help merge
apa yang--no-ff
dilakukannya (singkatnya: itu mengaktifkan perilaku yang saya jelaskan di paragraf sebelumnya), itu sangat penting.Sama sekali tidak - Anda tidak pernah membuang sesuatu "ke dalam sejarah" dari beberapa cabang, terutama dengan komit gabungan.
Dengan komit gabungan, itu masih ada. Bukan di master, tapi di sidebranch, jelas terlihat sebagai salah satu orang tua dari gabungan melakukan, dan disimpan untuk selamanya, sebagaimana mestinya.
Lihat apa yang saya lakukan? Semua hal yang Anda jelaskan untuk komit squash Anda ada di sana dengan
--no-ff
komit gabungan .(Komentar samping: Saya hampir secara eksklusif bekerja dengan baris perintah juga (well, itu bohong, saya biasanya menggunakan emacs magit, tapi itu cerita lain - jika saya tidak berada di tempat yang nyaman dengan pengaturan emacs pribadi saya, saya lebih suka perintah baris juga). Tapi tolong jangan kebaikan dan mencoba setidaknya
git gui
sekali. Hal ini sangat jauh lebih efisien untuk memilih garis, bakhil dll untuk menambahkan / kehancuran menambahkan.)Itu karena apa yang Anda coba lakukan benar-benar bertentangan dengan semangat
git
.git
dibangun dari inti pada "grafik asiklik terarah", yang berarti, banyak informasi ada dalam hubungan orangtua-anak-komit. Dan, untuk penggabungan, itu berarti penggabungan yang benar dilakukan dengan dua orang tua dan satu anak. GUI kolega Anda akan baik-baik saja segera setelah Anda menggunakanno-ff
komit gabungan.Ya, tapi itu bukan masalah GUI, tetapi dari squash commit. Menggunakan squash berarti Anda membiarkan kepala cabang fitur menjuntai, dan membuat komitmen baru
master
. Ini memecah struktur pada dua level, menciptakan kekacauan besar.Dan mereka benar sekali. Tapi mereka tidak "bergabung dalam ", mereka hanya bergabung. Penggabungan adalah hal yang benar-benar seimbang, tidak memiliki sisi yang disukai yang digabungkan "ke" yang lain (
git checkout A ; git merge B
persis samagit checkout B ; git merge A
kecuali kecuali untuk perbedaan visual kecil seperti cabang yang ditukar digit log
dll.).Yang sepenuhnya benar. Pada saat tidak ada fitur yang tidak dihapus, Anda akan memiliki satu cabang
master
dengan sejarah kaya yang merangkum semua baris komit fitur yang pernah ada, kembali kegit init
komit sejak awal waktu (perhatikan bahwa saya secara khusus menghindari penggunaan istilah " cabang "di bagian akhir paragraf itu karena sejarah pada waktu itu bukan" cabang "lagi, walaupun grafik komit akan cukup bercabang).Maka Anda sedikit kesakitan, karena Anda bekerja melawan alat yang Anda gunakan. The
git
Pendekatan ini sangat elegan dan kuat, terutama di percabangan / daerah penggabungan; jika Anda melakukannya dengan benar (seperti yang disinggung di atas, terutama dengan--no-ff
) itu adalah dengan lompatan dan lebih unggul untuk pendekatan lain (misalnya, kekacauan subversi memiliki struktur direktori paralel untuk cabang).Tak berujung, paralel - ya.
Tidak dapat dinavigasi, kusut - tidak.
Mengapa tidak bekerja seperti yang dilakukan oleh penemu
git
, kolega Anda dan seluruh dunia, setiap hari?Tidak ada pilihan lain; tidak seburuk itu.
sumber
Memencet sidebranch jangka panjang akan membuat Anda kehilangan banyak informasi.
Apa yang akan saya lakukan adalah mencoba mengubah master menjadi sidebranch jangka panjang sebelum menggabungkan sidebranch menjadi master . Dengan begitu Anda menjaga setiap komit tetap ada, sambil membuat sejarah komit linier dan lebih mudah dipahami.
Jika saya tidak bisa melakukan itu dengan mudah di setiap komit, saya akan membiarkannya non-linear , agar konteks pengembangan tetap jelas. Menurut pendapat saya, jika saya memiliki penggabungan bermasalah selama rebase master ke sidebranche, itu berarti non-linearitas memiliki signifikansi dunia nyata. Itu berarti akan lebih mudah untuk memahami apa yang terjadi seandainya saya perlu menggali sejarah. Saya juga mendapatkan manfaat langsung karena tidak harus melakukan rebase.
sumber
rebase
. Terlepas dari apakah itu pendekatan terbaik di sini (saya pribadi belum memiliki pengalaman hebat dengannya, meskipun saya belum sering menggunakannya), itu tampaknya merupakan hal terdekat dengan apa yang tampaknya diinginkan OP - khususnya, sebuah kompromi antara dump sejarah out-of-order dan benar-benar menyembunyikan sejarah itu.Secara pribadi saya lebih suka melakukan pengembangan saya dalam garpu, kemudian menarik permintaan untuk bergabung ke repositori utama.
Itu berarti bahwa jika saya ingin mengubah perubahan saya di atas master, atau menekan beberapa komitmen WIP, saya benar-benar dapat melakukannya. Atau saya bisa meminta agar seluruh sejarah saya digabungkan juga.
Yang ingin saya lakukan adalah melakukan pengembangan pada cabang tetapi sering rebase terhadap master / dev. Dengan begitu saya mendapatkan perubahan terbaru dari master tanpa harus melakukan banyak merger ke cabang saya , atau harus berurusan dengan banyak konflik merger saat saatnya untuk bergabung menjadi master.
Untuk secara eksplisit menjawab pertanyaan Anda:
Ya - Anda bisa menggabungkan mereka sekali per cabang (ketika fitur atau perbaikannya "lengkap") atau jika Anda tidak suka memiliki gabungan melakukan dalam sejarah Anda, Anda bisa melakukan penggabungan maju cepat pada master setelah melakukan rebase akhir.
sumber
Kontrol revisi adalah sampah masuk sampah.
Masalahnya adalah pekerjaan dalam proses pada cabang fitur dapat berisi banyak "mari kita coba ini ... tidak ada yang tidak bekerja, mari kita ganti dengan itu" dan semua komitmen kecuali yang terakhir "yang" baru saja berakhir sampai mencemari sejarah sia-sia.
Pada akhirnya, sejarah harus disimpan (sebagian mungkin bermanfaat di masa depan), tetapi hanya "salinan bersih" yang harus digabungkan.
Dengan Git, ini dapat dilakukan dengan melakukan bercabang pada cabang fitur terlebih dahulu (untuk menyimpan semua sejarah), kemudian (secara interaktif) memundurkan cabang dari cabang fitur dari master dan kemudian menggabungkan cabang rebased.
sumber
git
, dan mereka lokal. Apa yang dinamaifoo
dalam satu repo mungkin dinamaibar
berbeda. Dan itu dimaksudkan untuk sementara: Anda tidak ingin mengacaukan repo Anda dengan ribuan cabang fitur yang perlu dijaga agar tetap hidup agar tidak kehilangan riwayat. Dan Anda perlu menyimpan cabang-cabang itu untuk menjaga sejarah referensi, karenagit
pada akhirnya akan menghapus komit yang tidak dapat dijangkau oleh cabang lagi.