Mempertahankan Dua Versi Perangkat Lunak Terpisah Dari Kode Dasar yang Sama dalam Kontrol Versi

45

Katakanlah saya sedang menulis dua versi berbeda dari perangkat lunak / program / aplikasi / skrip yang sama dan menyimpannya di bawah kontrol versi. Versi pertama adalah versi "Dasar" gratis, sedangkan yang kedua adalah versi "Premium" berbayar yang mengambil basis kode dari versi gratis dan memperluasnya dengan beberapa fitur nilai tambah tambahan. Setiap tambalan, perbaikan, atau fitur baru perlu menemukan jalannya ke kedua versi.

Saat ini saya sedang mempertimbangkan menggunakan masterdan developcabang untuk basis kode utama (versi gratis) di samping master-premiumdan develop-premiumcabang untuk versi berbayar. Ketika perubahan dibuat ke versi gratis dan digabung ke mastercabang (setelah pengujian menyeluruh developtentu saja), itu akan disalin ke develop-premiumcabang melalui cherry-pickperintah untuk pengujian lebih lanjut dan kemudian digabung menjadi master-premium.

Apakah ini alur kerja terbaik untuk menangani situasi ini? Adakah potensi masalah, peringatan, atau perangkap yang harus diperhatikan? Apakah ada strategi percabangan yang lebih baik daripada apa yang telah saya buat?

Umpan balik Anda sangat dihargai!

PS Ini untuk skrip PHP yang disimpan di Git, tetapi jawabannya harus berlaku untuk bahasa atau VCS apa pun.

Joseph Leedy
sumber

Jawaban:

83

Alih-alih memiliki dua versi kode dengan basis umum, Anda harus mendesain aplikasi Anda dengan cara membuat fitur-fitur premium plug-mampu dan didorong oleh konfigurasi daripada basis kode yang berbeda.

Jika Anda takut untuk mengirim fitur-fitur premium tersebut (dinonaktifkan oleh konfigurasi) dengan versi dasar, Anda masih dapat menghapus kode itu dalam langkah pembuatan / pengemasan akhir dan hanya memiliki dua profil pembuatan.

Dengan desain ini Anda juga dapat mengirimkan 5 rasa yang berbeda dan menjadi sangat fleksibel, bahkan mungkin memungkinkan pihak ketiga untuk berkontribusi.

Oliver
sumber
2
Ya inilah yang saya mulai pikirkan tadi malam sebelum saya pergi tidur. Terima kasih!
Joseph Leedy
3
Windows modern dirancang dengan cara ini, semua versi memiliki semua kode yang sama, dan memiliki fitur tidak terkunci tergantung pada kunci lisensi yang digunakan.
Mooing Duck
39

Saya sangat menyarankan untuk tidak menggunakan cabang untuk tujuan ini. Secara umum, Anda harus mempertimbangkan cabang untuk hal-hal yang akan (atau mungkin) digabungkan kembali lagi nanti (atau untuk cabang rilis, di mana Anda akhirnya menghentikan pengembangan salah satu cabang). Dalam kasus Anda, Anda tidak akan pernah menyatukan versi "dasar" dan "premium" Anda, dan keduanya akan dipertahankan tanpa batas waktu, sehingga cabang tidak sesuai.

Sebagai gantinya, pertahankan satu versi umum dari kode sumber dan gunakan kompilasi bersyarat (mis. #ifdefDalam C / C ++, tidak yakin apa yang setara untuk PHP) untuk memasukkan atau mengecualikan bagian-bagian kode yang berbeda antara "dasar" dan "premium".

Sepertinya PHP mungkin tidak memiliki fitur kompilasi bersyarat seperti itu, jadi Anda dapat menggunakan prepro C (( cppAnda mungkin sudah memilikinya) untuk memproses ulang kode sumber umum Anda dan dari situ, menghasilkan "dasar" dan "premium" versi tanpa arahan preprocessor. Tentu saja, jika Anda memilih untuk melakukan ini, Anda harus menggunakan makeatau sesuatu yang serupa untuk mengotomatiskan proses menjalankan preprosesor.

Greg Hewgill
sumber
Apa yang Anda katakan tentang cabang sangat masuk akal! Mungkin sebaliknya saya bisa membuat repo terpisah yang hanya berisi kode Premium dan menggunakan semacam skrip rilis atau sub-modul untuk menggabungkannya dengan kode dasar? Ini mungkin membuat TDD lebih sulit, meskipun ...
Joseph Leedy
14
Membuat repositori lain bahkan lebih buruk daripada membuat cabang! Anda pasti ingin memilih solusi yang melibatkan duplikasi kode versi paling sedikit.
Greg Hewgill
2
Titik repo kedua adalah untuk rumah hanya kode tambahan - tidak salinan lain dari seluruh aplikasi.
Joseph Leedy
1
Ah saya mengerti, itu akan lebih seperti model "plugin", di mana kode dasar Anda memiliki kemampuan untuk memuat dan menjalankan plugin (jika ada). Kode plugin terpisah dan menyediakan fitur premium.
Greg Hewgill
4
@ Joseph: menggunakan dua repo hanya sesuai jika versi dua basis kode hampir independen satu sama lain. Jika bukan itu masalahnya, saya akan sangat menyarankan untuk melakukan apa yang ditulis Greg dan menyimpan semuanya dalam satu repo. Satu-satunya hal yang saya pikirkan adalah penggunaan "prepro C". Saya kira skrip kecil yang ditulis dalam bahasa pilihan Anda (PHP itu sendiri baik-baik saja, Perl atau Python lebih baik) yang membuat salinan kode Anda tanpa (beberapa yang ditandai) fitur premium akan melakukan trik.
Doc Brown
8

Kami menggunakan 2 proyek terpisah, proyek Dasar dan proyek Premium yang bergantung pada proyek Dasar. Jangan gunakan braches, mereka biasanya digunakan untuk fitur.

Silviu Burcea
sumber
Ini menarik bagi saya, karena Anda dapat menggunakan skrip build Anda untuk mengotomatisasi pembuatan program dasar dan premium.
neontapir
1
dalam kasus umum Anda memerlukan 3 proyek: bagian umum, sering disusun sebagai perpustakaan, dan bagian kustom untuk dua versi yang berbeda.
Andriy Tylychko
3

Sementara sebagian besar jawaban saat ini lebih memilih kompilasi bersyarat daripada cabang, ada satu skenario di mana ada manfaat yang jelas untuk menggunakan cabang: jika Anda (sekarang atau nanti) memutuskan untuk membuat kode sumber dari versi dasar tersedia, termasuk semua versi sejarah tetapi tidak termasuk semua fitur premium, maka Anda dapat melakukannya dengan pendekatan cabang tetapi tidak dengan satu cabang dan kompilasi bersyarat.

Saya menyarankan agar memetik ceri, dan gantinya menggabungkan semua perubahan dari versi dasar ke versi premium. Seharusnya tidak ada perbaikan fitur atau bug yang termasuk dalam dasar tetapi tidak ada dalam versi premium. Untuk membuat hal-hal tanpa rasa sakit mungkin, Anda harus memastikan bahwa cabang premium memodifikasi file umum sesedikit mungkin. Jadi cabang premium sebagian besar harus berisi file tambahan, dan mungkin sedikit modifikasi untuk membangun instruksi. Dengan begitu, perubahan dari versi dasar akan bergabung secara otomatis tanpa menyebabkan konflik.

Jawaban Greg menyarankan agar Anda "mempertimbangkan cabang-cabang untuk hal-hal yang akan (atau mungkin) digabungkan kembali lagi nanti". Dengan pendekatan yang baru saja saya jelaskan inilah masalahnya, kecuali bahwa cabang terakhir untuk semua komit master-premiumtidak akan master(yang sebenarnya master-basic).

Sub-modul tentu saja akan menjadi pilihan juga. Itu tergantung pada proses build Anda, tetapi jika Anda dapat membuat versi premium menjadi proyek yang menggunakan versi dasar sebagai modul, itu akan baik-baik saja. Namun Anda mungkin mengalami kesulitan jika pada suatu saat Anda memutuskan untuk memilih fitur dari cabang premium ke cabang dasar. Dengan sub-modul, perubahan seperti itu akan direpresentasikan sebagai dua komitmen yang berbeda, sedangkan dengan cabang, ini akan menjadi komitmen tunggal untuk versi dasar, dan penggabungan berikutnya ke dalam versi premium akan tahu bahwa perubahan ini sudah termasuk dan tidak memiliki untuk digabung lagi.

MvG
sumber
0

Dalam "perangkat keras" ini sering dilakukan, mereka adalah sistem yang dijual untuk mengendalikan kekacauan, maaf saya tidak ingat apa namanya.

Setelah mesin cuci "mid range" dikirimkan, kodenya tidak berubah selain untuk perbaikan bug yang sangat penting, bahkan ketika kode yang sama diubah di mesin cuci "low end" yang dikirimkan beberapa bulan kemudian.

Pelanggan tidak berharap mendapatkan upgrade ke mesin cuci yang telah mereka bawa, model baru juga tidak dikirimkan setiap beberapa bulan.

Sebagian besar dari kita tidak hidup di dunia itu, jadi lakukan apa yang dikatakan Greg kecuali jika Anda menulis perangkat lunak untuk mesin cuci.

Ian
sumber