Duy trì hai phiên bản phần mềm riêng biệt từ cùng một Codebase trong Kiểm soát phiên bản


45

Giả sử tôi đang viết hai phiên bản khác nhau của cùng một phần mềm / chương trình / ứng dụng / tập lệnh và lưu trữ chúng dưới sự kiểm soát phiên bản. Phiên bản đầu tiên là phiên bản "Cơ bản" miễn phí, trong khi phiên bản thứ hai là phiên bản "Premium" trả phí, lấy mã cơ sở của phiên bản miễn phí và mở rộng dựa trên nó với một vài tính năng bổ sung giá trị gia tăng. Bất kỳ bản vá, sửa lỗi hoặc tính năng mới nào cũng cần tìm đường vào cả hai phiên bản.

Tôi hiện đang xem xét việc sử dụng masterdevelopcác nhánh cho codebase chính (phiên bản miễn phí) dọc theo bên master-premiumdevelop-premiumcác nhánh cho phiên bản trả phí. Khi một thay đổi được thực hiện cho phiên bản miễn phí và được sáp nhập vào masterchi nhánh ( developdĩ nhiên sau khi kiểm tra kỹ lưỡng ), nó sẽ được sao chép sang develop-premiumchi nhánh thông qua cherry-picklệnh để kiểm tra thêm và sau đó được sáp nhập vào master-premium.

Đây có phải là quy trình làm việc tốt nhất để xử lý tình huống này? Có bất kỳ vấn đề tiềm ẩn, hãy cẩn thận, hoặc cạm bẫy để nhận thức? Có một chiến lược phân nhánh tốt hơn những gì tôi đã đưa ra?

Phản hồi của bạn được đánh giá cao!

PS Đây là một tập lệnh PHP được lưu trữ trong Git, nhưng câu trả lời nên áp dụng cho bất kỳ ngôn ngữ hoặc VCS nào.

Câu trả lời:


83

Thay vì có hai phiên bản mã với một cơ sở chung, bạn nên thiết kế ứng dụng của mình theo cách làm cho các tính năng cao cấp đó có thể cắm và được điều khiển bởi cấu hình thay vì các cơ sở mã khác nhau.

Nếu bạn ngại gửi các tính năng cao cấp đó (bị vô hiệu hóa bởi cấu hình) với phiên bản cơ bản, bạn vẫn có thể xóa mã đó trong bước xây dựng / đóng gói cuối cùng và chỉ cần có hai cấu hình xây dựng.

Có thiết kế này, bạn cũng có thể vận chuyển 5 hương vị khác nhau và rất linh hoạt, thậm chí có thể cho phép các bên thứ ba đóng góp.


2
Vâng, đây là những gì tôi bắt đầu nghĩ về đêm qua trước khi tôi đi ngủ. Cảm ơn!
Joseph Leedy

3
Windows hiện đại được thiết kế theo cách này, tất cả các phiên bản đều có cùng một mã và có các tính năng được mở khóa tùy thuộc vào khóa giấy phép sử dụng.
Vịt Mooing

39

Tôi thực sự khuyên bạn không nên sử dụng các chi nhánh cho mục đích này. Nói chung, bạn nên xem xét các nhánh cho những thứ sẽ (hoặc có thể) được hợp nhất lại với nhau sau đó (hoặc cho các nhánh phát hành, nơi cuối cùng bạn ngừng phát triển một trong các nhánh). Trong trường hợp của bạn, bạn sẽ không bao giờ hợp nhất các phiên bản "cơ bản" và "cao cấp" của mình với nhau và cả hai sẽ được duy trì vô thời hạn, do đó các chi nhánh không phù hợp.

Thay vào đó, hãy duy trì một phiên bản chung của mã nguồn và sử dụng biên dịch có điều kiện (ví dụ: #ifdeftrong C / C ++, không chắc chắn tương đương với PHP) để bao gồm hoặc loại trừ các phần mã khác nhau giữa "cơ bản" và "cao cấp".

Có vẻ như PHP có thể không có tính năng biên dịch có điều kiện như vậy, vì vậy bạn có thể sử dụng bộ tiền xử lý C ( cpp, có lẽ bạn đã có nó) để tiền xử lý mã nguồn chung của bạn và từ đó, tạo ra "cơ bản" và "cao cấp" phiên bản không có chỉ thị tiền xử lý. Tất nhiên, nếu bạn chọn làm điều này, bạn nên sử dụng makehoặc một cái gì đó tương tự để tự động hóa quá trình chạy bộ tiền xử lý.


Những gì bạn đang nói về các chi nhánh có ý nghĩa tổng thể! Có lẽ thay vào đó tôi có thể tạo một repo riêng chỉ chứa mã Premium và sử dụng một số loại kịch bản phát hành hoặc mô-đun phụ để kết hợp nó với mã cơ sở? Điều này có thể làm TDD khó hơn, mặc dù ...
Joseph Leedy

14
Tạo một kho lưu trữ khác thậm chí còn tồi tệ hơn việc tạo các chi nhánh! Bạn chắc chắn muốn chọn một giải pháp liên quan đến việc sao chép ít nhất mã được phiên bản.
Greg Hewgill

2
Điểm của repo thứ hai là chỉ chứa mã bổ sung - không phải là bản sao khác của toàn bộ ứng dụng.
Joseph Leedy

1
À tôi hiểu rồi, nó sẽ giống mô hình "plugin" hơn, nơi mã cơ bản của bạn có khả năng tải và chạy plugin (nếu chúng tồn tại). Mã plugin là riêng biệt và cung cấp các tính năng cao cấp.
Greg Hewgill

4
@Joseph: sử dụng hai repos chỉ thích hợp nếu phiên bản của hai cơ sở mã gần như độc lập với nhau. Nếu đó không phải là trường hợp, tôi thực sự khuyên bạn nên làm những gì Greg đã viết và giữ mọi thứ trong một repo. Điều duy nhất tôi sẽ suy nghĩ lại là việc sử dụng "tiền xử lý C". Tôi đoán một tập lệnh nhỏ được viết bằng ngôn ngữ bạn chọn (bản thân PHP cũng ổn, Perl hoặc Python thậm chí còn tốt hơn), điều này tạo ra một bản sao mã của bạn mà không có các tính năng cao cấp (được đánh dấu) sẽ làm được điều đó.
Doc Brown

8

Chúng tôi đang sử dụng 2 dự án riêng biệt, dự án cơ bản và dự án cao cấp phụ thuộc vào dự án cơ bản. Không sử dụng braches, chúng thường được sử dụng cho các tính năng.


Điều này hấp dẫn tôi, bởi vì bạn có thể sử dụng tập lệnh xây dựng của mình để tự động hóa việc tạo cả chương trình cơ bản và cao cấp.
neontapir

1
trong trường hợp chung, bạn cần 3 dự án: phần chung, thường được tổ chức dưới dạng thư viện và các phần tùy chỉnh cho hai phiên bản khác nhau.
Andriy Tylychko

3

Mặc dù hầu hết các câu trả lời hiện tại đều có lợi cho việc biên dịch có điều kiện thay vì các nhánh, có một kịch bản có lợi ích rõ ràng khi sử dụng các nhánh: nếu bạn (bây giờ hoặc sau này) quyết định cung cấp mã nguồn của phiên bản cơ bản, bao gồm tất cả lịch sử phiên bản nhưng không bao gồm tất cả các tính năng cao cấp, sau đó bạn có thể làm như vậy với cách tiếp cận các nhánh nhưng không phải với một nhánh duy nhất và biên dịch có điều kiện.

Tôi khuyên bạn không nên chọn cherry, và thay vào đó, hợp nhất tất cả các thay đổi từ phiên bản cơ bản thành phiên bản cao cấp. Không nên có tính năng hoặc sửa lỗi trong phiên bản cơ bản nhưng thiếu trong phiên bản cao cấp. Để làm cho mọi thứ không đau đớn nhất có thể, bạn nên đảm bảo rằng nhánh cao cấp sửa đổi các tệp phổ biến càng ít càng tốt. Vì vậy, nhánh cao cấp chủ yếu nên chứa các tệp bổ sung và có lẽ một số sửa đổi nhỏ để xây dựng hướng dẫn. Bằng cách đó, các thay đổi từ phiên bản cơ bản sẽ tự động hợp nhất mà không gây ra xung đột.

Câu trả lời của Greg đề nghị bạn nên xem xét các nhánh cho những thứ sẽ (hoặc có thể) được hợp nhất trở lại với nhau sau này. Với cách tiếp cận tôi chỉ mô tả đây là trường hợp, ngoại trừ rằng nhánh cuối cùng cho tất cả các cam kết sẽ master-premiumkhông master(thực tế master-basic).

Các mô-đun phụ tất nhiên cũng là một lựa chọn. Nó phụ thuộc vào quá trình xây dựng của bạn, nhưng nếu bạn có thể biến phiên bản cao cấp thành dự án sử dụng phiên bản cơ bản làm mô-đun, điều đó sẽ ổn. Tuy nhiên, bạn có thể gặp khó khăn hơn nếu đến một lúc nào đó bạn quyết định chọn các tính năng cherry từ nhánh cao cấp vào nhánh cơ bản. Với các mô-đun phụ, một thay đổi như vậy sẽ được biểu thị thành hai cam kết riêng biệt, trong khi với các nhánh, đây sẽ là một cam kết duy nhất cho phiên bản cơ bản và việc hợp nhất tiếp theo vào phiên bản cao cấp sẽ biết rằng những thay đổi này đã được bao gồm và không có được sáp nhập lại.


0

Trong phần cứng của hệ thống, điều này được thực hiện thường xuyên, chúng là các hệ thống được bán để kiểm soát sự lộn xộn, xin lỗi tôi không thể nhớ chúng được gọi là gì.

Sau khi máy giặt tầm trung tầm cao của nhà máy xuất hiện, mã của nó không thay đổi ngoài việc sửa lỗi rất quan trọng, ngay cả khi mã tương tự được thay đổi trong máy giặt cấp thấp của sen mà xuất xưởng vài tháng sau đó.

Khách hàng không mong đợi được nâng cấp cho máy giặt mà họ đã mang theo, một mẫu mới cũng không được xuất xưởng cứ sau vài tháng.

Hầu hết chúng ta không sống trong thế giới đó, vì vậy hãy làm những gì Greg nói trừ khi bạn viết phần mềm cho máy giặt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.