Có sự khác biệt giữa sáp nhập trong svn so với git hoặc đồng bóng?


12

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?

git  svn  mercurial  dvcs 

Câu trả lời:


21

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à

    • phiên bản tổ tiên chung lớn nhất
    • phiên bản trên một nhánh
    • phiên bản trên nhánh khác

    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 mergecung 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 pulltừ 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 mergevà 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.


4
câu trả lời chính xác! Tôi sẽ upvote hai lần nếu tôi có thể. :) Tôi cũng nói thêm rằng cuốn sách SVN mà bạn tham khảo trong câu trả lời SO thừa nhận rằng "Tính năng theo dõi hợp nhất của Subversion có một triển khai nội bộ cực kỳ phức tạp ..." - đây là một dấu hiệu khá tốt cho thấy tính năng này không đáng tin cậy
gnat

2
... Và ngay cả với việc thực hiện cực kỳ phức tạp đó cũng không thể tìm ra tổ tiên chung một cách chính xác trong bất kỳ trường hợp ngoại trừ đơn giản nào.
Jan Hudec

Về việc hợp nhất bị trì hoãn - không hiểu được - với SVN, đồng nghiệp của tôi có thể cập nhật lên / kiểm tra thân cây, sau đó hợp nhất từ ​​chi nhánh của tôi vào đó.
Gill Bates

@GillBates: Tôi đang nói về một tình huống mà bạn chưa bắt đầu một chi nhánh cho công việc của mình - khi bạn đang làm việc 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 commitsẽ ả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! :-)
Martin Geisler

6

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ếtthú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:

  • Bạn có thể có nhiều đầu và vẫn cam kết trên một trong hai; Không giống như lật đổ, bạn không cần kết hợp kéo, cập nhật và hợp nhất trước khi cam kết lại - nhiều đầu chỉ giữ nguyên như vậy cho đến khi bạn chọn hợp nhất
  • Thư mục không được đối xử đặc biệt; thay vào đó, đường dẫn chỉ được coi là một tên tệp lớn và tất cả các thư mục của bạn phải ở cùng một phiên bản mọi lúc. Điều này có nghĩa là bạn không thể thực hiện lật đổ voodoo nơi các thư mục con của dự án ở các phiên bản khác nhau, nhưng điều đó cũng có nghĩa là bản sao làm việc ít có khả năng trở thành một mớ hỗn độn bị hỏng không thể quản lý được và thú vị hơn, một động thái không được thể hiện dưới dạng xóa -và thêm (sẽ phá vỡ hoàn toàn trong svn nếu nó không dành cho siêu dữ liệu trang bị thêm), nhưng chỉ đơn giản là đổi tên; nếu bạn di chuyển một tập tin, toàn bộ lịch sử của nó được bảo tồn; hợp nhất thậm chí có thể áp dụng các thay đổi cho tệp đã di chuyển được thực hiện cho phiên bản không di chuyển của cùng một tệp sau khi di chuyển, trong một nhánh khác
  • Hầu hết thời gian, bạn thực sự thậm chí không cần phải phân nhánh: thay vào đó, bạn chỉ cần sao chép toàn bộ kho lưu trữ. Nhân bản là rẻ, đặc biệt là nếu nó được thực hiện trên cùng một hệ thống tập tin và nếu bạn quyết định muốn thoát khỏi bản sao, bạn chỉ cần xóa thư mục mà nó sống và đó là. Bạn thậm chí không cần sử dụng hg hoặc git cho điều đó.
  • Có một vài hạn chế (nếu có) về những gì bạn có thể hợp nhất. Bạn có thể có sáu bản sao của cùng một kho lưu trữ và hợp nhất (hoặc đúng hơn là đẩy hoặc kéo; một sự hợp nhất rõ ràng thường không bắt buộc) từ A đến B, sau đó C đến B, sau đó B đến D, sau đó C đến D, B trở lại đến A, D đến E, bất cứ lúc nào và bao nhiêu lần bạn muốn.
  • Bạn có thể kiểm tra hợp nhất bằng cách nhân bản một trong các kho lưu trữ mà bạn muốn hợp nhất, sau đó kéo vào đó từ kho kia. Nếu nó làm những gì bạn muốn, bạn có thể đẩy lùi về mục tiêu thực sự, nếu không, bạn sẽ vứt bỏ bản sao và bắt đầu lại từ đầu.

2
Tôi phải đề cập đến một số chỉnh sửa và thêm vào để trả lời: 1. Bản sửa đổi SVN là kho lưu trữ toàn cầu , bản sửa đổi đại diện cho tất cả các tệp trong repo trong giây lát 2. Công nghệ hợp nhất về cơ bản là phổ biến trong SVN và DVCS - nếu tệp trong tệp hợp nhất chỉ thay đổi cùng một cách , hợp nhất sẽ tạo ra cùng một lượng xung đột cho SVN và DVCS - tất cả các SCM vẫn hoạt động ở cấp độ chuỗi, không phải là khối logic 3. Các cam kết lớn trong SVN không phải là kết quả của kiến ​​trúc, nhưng vì người dùng thường là những kẻ ngốc lười biếng - họ bỏ qua các mẫu cơ bản. Chi nhánh | hợp nhất hoạt động trong SVN, nếu / dev / brain và / dev / hand hoạt động
Lazy Badger

2
Phần 2: Hợp nhất thông minh trong DVCS hầu hết xảy ra vì trái với Subversion, họ theo dõi và xử lý các động thái | đổi tên tệp và SVN hoàn toàn không làm điều đó - do đó - mọi thao tác, xử lý tệp, thay đổi ở một bên và đổi tên thành thứ hai, sẽ thất bại. Phân nhánh với các nhánh và nhân bản chỉ là các chiến lược khác nhau của việc phân nhánh với cùng quyền sống, sử dụng "... phụ thuộc vào ..."
Lazy Badger

@LazyBadger: Au contraire. Subversion không theo dõi di chuyển / đổi tên, điều này gây ra xung đột giả một phần vì việc xử lý các đổi tên trong hợp nhất chỉ là lỗi và một phần vì có các trường hợp góc khó hoặc không thể xử lý chính xác. Sau này là lý do tại sao git (và sao chép nó) bởi thiết kế không theo dõi tên và đoán chúng khi hợp nhất. Điều này hoạt động tốt nếu nội dung vẫn đủ tương tự để được hợp nhất (đó là khi bạn cần nó) và không làm những điều ngớ ngẩn khác.
Jan Hudec

@JanHudec - xin lỗi, SVN xử lý không di chuyển | đổi tên theo một hành động nguyên tử (cách DVCS - "đổi tên"), nhưng như "xóa + ...", do đó - tạo ra xung đột cây, trong đó nó không xảy ra trong DVCS ( đổi tên thật ). Theo dõi Mercurial đổi tên rõ ràng ( hg mvhoặ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.
Lazy Badger

5
Bây giờ chúng tôi đang nhận được khá kỹ thuật :-) Cả hai bản sao theo dõi Subversion và Mercurial , không đổi tên. Cả hai hệ thống theo dõi rename a bnhư copy a b; remove avà 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.
Martin Geisler
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.