Theo hiểu biết của tôi, SVN là 'Dễ dàng phân nhánh. Khó hợp nhất '. Tại sao vậy? Có một sự khác biệt làm thế nào họ hợp nhất?
Theo hiểu biết của tôi, SVN là 'Dễ dàng phân nhánh. Khó hợp nhất '. Tại sao vậy? Có một sự khác biệt làm thế nào họ hợp nhất?
Câu trả lời:
Vui lòng xem câu trả lời Stack Overflow của tôi cho một tình huống rất cụ thể trong đó Mercurial (và Git) hợp nhất mà không gặp vấn đề gì và khi Subversion trình bày cho bạn một cuộc xung đột không có thật. Tình huống này là một phép tái cấu trúc đơn giản được thực hiện trên một nhánh nơi bạn đổi tên một số tệp.
Liên quan đến câu trả lời của tdammers, sau đó có một số hiểu lầm ở đó:
Subversion, Mercurial và Git đều theo dõi các ảnh chụp nhanh trên toàn kho lưu trữ của dự án. Gọi họ phiên bản , sửa đổi , hoặc changesets làm cho không có sự khác biệt. Chúng đều là ảnh chụp nhanh nguyên tử của một tập hợp các tệp.
Kích thước của các cam kết của bạn không có sự khác biệt khi hợp nhất. Tất cả ba hệ thống hợp nhất với thuật toán hợp nhất ba chiều tiêu chuẩn và các đầu vào cho thuật toán đó là
Không quan trọng làm thế nào hai phiên bản chi nhánh được tạo ra. Bạn có thể đã sử dụng 1000 cam kết nhỏ kể từ phiên bản tổ tiên hoặc bạn có thể đã sử dụng 1 cam kết. Tất cả những gì quan trọng là phiên bản cuối cùng của các tập tin. (Vâng, điều này thật đáng ngạc nhiên! Vâng, rất nhiều hướng dẫn DVCS đã nhận sai lầm khủng khiếp này.)
Ông cũng nêu lên một số điểm tốt về sự khác biệt:
Subversion có một số "voodoo" nơi bạn có thể hợp nhất từ /trunk
, nói , /branches/foo
. Mercurial và Git không sử dụng mô hình này - các nhánh thay vào đó được mô hình hóa trực tiếp trong lịch sử. Do đó, lịch sử trở thành một biểu đồ chu kỳ có hướng thay vì tuyến tính. Đây là một mô hình đơn giản hơn nhiều so với mô hình được sử dụng bởi Subversion và điều này cắt đi một số trường hợp góc.
Bạn có thể dễ dàng trì hoãn hợp nhất hoặc thậm chí để người khác xử lý nó. Nếu hg merge
cung cấp cho bạn rất nhiều xung đột, thì bạn có thể yêu cầu đồng nghiệp của bạn hg pull
từ bạn và sau đó anh ta có trạng thái chính xác như vậy. Vì vậy, anh ta có thể hg merge
và có thể anh ta tốt hơn trong việc giải quyết xung đột hơn bạn.
Điều này rất khó với Subversion nơi bạn bắt buộc phải cập nhật trước khi bạn có thể cam kết. Bạn không thể bỏ qua các thay đổi trên máy chủ và tiếp tục cam kết trên nhánh ẩn danh của riêng bạn. Nói chung, Subversion buộc bạn phải chơi xung quanh với một bản sao làm việc bẩn khi bạn svn update
. Đây là một loại rủi ro vì bạn đã không lưu trữ các thay đổi của mình ở bất cứ đâu an toàn. Git và Mercurial cho phép bạn cam kết trước, sau đó cập nhật và hợp nhất khi cần thiết.
Lý do thực sự khiến Git và Mercurial hợp nhất tốt hơn Subversion là vấn đề thực hiện. Có những xung đột đổi tên mà Subversion chỉ đơn giản là không thể xử lý thậm chí còn nghĩ rằng câu trả lời đúng là gì. Mercurial và Git xử lý những người dễ dàng. Nhưng không có lý do tại sao Subversion không thể xử lý tốt những điều đó - tập trung hóa chắc chắn không phải là lý do.
trunk
ở SVN. Với DVCS bạn có thể cam kết mà không cần chia sẻ, nhưng trong SVN, ý chí của bạn svn commit
sẽ ảnh hưởng trực tiếp đến những người khác làm việc trong cùng chi nhánh. Ngay cả khi hai chúng tôi làm việc tại một chi nhánh ở SVN, tôi không thể cam kết công việc của mình mà không phải hợp nhất ngay lập tức với công việc của bạn. Điều đó làm cho cam kết hơi đáng sợ - đó là một tài sản đáng sợ cho một hệ thống kiểm soát phiên bản! :-)
Vấn đề cốt lõi nằm ở cách các hệ thống này thể hiện cấu trúc thư mục được phiên bản.
Khái niệm cơ bản của Subversion mà toàn bộ hệ thống xoay quanh là phiên bản (hoặc, trong singo lingo, "revision"): ảnh chụp nhanh của một tệp tại một điểm nhất định. Miễn là lịch sử hoàn toàn tuyến tính, tất cả đều ổn, nhưng nếu bạn cần hợp nhất các thay đổi từ hai dòng phát triển độc lập, svn phải so sánh các phiên bản hiện tại của cả hai, và sau đó thực hiện so sánh ba chiều giữa phiên bản chia sẻ cuối cùng và hai phiên bản đầu. Các dòng xuất hiện thay đổi ở một trong những đầu, nhưng không phải là đầu khác, có thể dễ dàng được giải quyết; các đường lệch chính xác theo cùng một cách trong cả hai đầu thì khó hơn, nhưng thường có thể thực hiện được; những dòng đi chệch hướng theo những cách khác nhau là điều khiến svn nói "Tôi không thể hiểu điều này, con người, xin vui lòng giải quyết vấn đề này cho tôi."
Ngược lại, git và theo dõi lanh lợi changesets chứ không phải phiên bản. Toàn bộ kho lưu trữ là một cây thay đổi, mỗi bộ tùy thuộc vào cha mẹ, trong đó bộ thay đổi cha mẹ có thể có bất kỳ số lượng con nào và gốc cây đại diện cho một thư mục trống. Nói cách khác, git / hg nói "đầu tiên tôi không có gì, sau đó bản vá này được áp dụng, sau đó là bản vá đó, v.v.". Khi bạn cần hợp nhất hai dòng phát triển, git / hg không chỉ biết mỗi đầu hiện tại trông như thế nào và phiên bản chung cuối cùng trông như thế nào, nó còn biết quá trình chuyển đổi xảy ra như thế nào, cho phép hợp nhất thông minh hơn nhiều.
Một điều nữa làm cho việc hợp nhất dễ dàng hơn trong DVCS là hậu quả gián tiếp của việc tách biệt các khái niệm về cam kết và thúc đẩyvà cho phép tất cả các loại hợp nhất chéo giữa bất kỳ hai bản sao của cùng một kho lưu trữ bất cứ lúc nào. Với svn, mọi người có xu hướng cam kết các thay đổi lớn với các thay đổi thường không liên quan, bởi vì một cam kết cũng là một bản cập nhật trên kho lưu trữ trung tâm ảnh hưởng đến tất cả các thành viên khác trong nhóm; nếu bạn phạm phải một phiên bản bị hỏng, mọi người sẽ tức giận với bạn. Vì hầu hết các thiết lập liên quan đến máy chủ svn được nối mạng, nên việc cam kết cũng liên quan đến việc bơm dữ liệu qua mạng, điều đó có nghĩa là cam kết giới thiệu một độ trễ đáng kể cho quy trình làm việc (đặc biệt là khi bản sao làm việc của bạn đã lỗi thời và bạn phải kéo trước). Với git và mercurial, cam kết xảy ra cục bộ và vì cả hai đều rất hiệu quả trong việc xử lý các hệ thống tệp cục bộ, nên nó thường kết thúc ngay lập tức. Kết quả là, mọi người (một khi họ đã quen với nó) cam kết những thay đổi nhỏ dần, và sau đó khi nó hoạt động, đẩy một tá hoặc hơn cam kết trong một lần. Sau đó, khi thời gian hợp nhất xuất hiện, SCM có nhiều thông tin chi tiết hơn và có thể thực hiện công việc tốt hơn để giải quyết xung đột một cách an toàn và tự động.
Và sau đó là những chi tiết đẹp khiến mọi thứ trở nên dễ dàng hơn:
hg mv
hoặc hg addremove --similarity...
), trong khi Git sử dụng heuristic, nhưng cả hai đều xử lý đổi tên . Tôi có thể nhận được xung đột cây ngay cả với 1 chuỗi khác biệt trong các tệp được hợp nhất! Bạn phải học lại một số khía cạnh Subversion, xin lỗi.
rename a b
như copy a b; remove a
và cả hai làm điều đó trong một nguyên tử cam kết. Sự khác biệt trong hành vi hợp nhất bắt nguồn từ việc xử lý các trường hợp góc khác nhau và từ Subversion cho phép hợp nhất nhiều hơn Mercurial và Git. Cuối cùng, Git phát hiện các đổi tên vào thời gian hợp nhất và đăng nhập - chúng tôi cũng đang nghĩ đến việc thêm cái này vào Mercurial.