2009-10-31 57 views
11

Big Three của kiểm soát phiên bản phân tán (Git, Bazaar, và Mercurial) mỗi phân nhánh xử lý khá khác nhau. Trong Bazaar, ví dụ, các chi nhánh là các repos riêng biệt (thực sự, các bản sao khác nhau của repo gốc); trên hệ thống tệp của bạn, các nhánh khác nhau sống trong các thư mục khác nhau. Trong Git, mặt khác, bạn có thể có nhiều chi nhánh tồn tại trong cùng một repo (và do đó trong cùng một thư mục trên hệ thống tệp của bạn). Mercurial hỗ trợ both behaviors, sau này với named branches.Ưu điểm và nhược điểm của các mô hình phân nhánh khác nhau trong DVCS

Ưu và khuyết điểm liên quan đến các mô hình phân nhánh khác nhau này là gì? Trong tâm trí của tôi, cách tiếp cận của Bazaar của một chi nhánh, một repo làm cho phân nhánh đau hơn cách tiếp cận của Git (ví dụ như sử dụng một chi nhánh ở Bazaar, trước tiên tôi phải tạo chi nhánh, sau đó cd ra khỏi bản sao làm việc hiện tại của tôi, sau đó kiểm tra nhánh mới, như tôi sẽ ở trong SVN).

+4

các chi nhánh được đặt tên khá khác với các chi nhánh git, xem tại đây để biết chi tiết: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/ – tonfa

+0

Xem thêm câu trả lời của tôi trong "Git và Mercurial - So sánh và tương phản", bao gồm các chi nhánh: http://stackoverflow.com/questions/1598759/git-and-mercurial-compare-and-contrast/1599930#1599930 –

+0

Man, tonfa luôn quản lý để đăng bài viết blog của tôi trước khi tôi làm! :) –

Trả lời

9

Bazaar không yêu cầu bạn làm việc theo cách bạn mô tả. Tôi đã thực sự viết a blog post về nó hai ngày trước. Bạn có thể làm việc khá nhiều chỉ với một cây làm việc duy nhất, chuyển đổi giữa các nhánh khác nhau và tạo ra các nhánh mới mà không cần rời khỏi cây làm việc. Các lệnh hữu ích cho việc này là: checkout, switch, branch --switch. Kiểm tra tài liệu workflow cho Bazaar, bạn sẽ thấy rằng bạn có thể cấu hình nó theo bất kỳ cách nào bạn muốn.

+0

Thật tuyệt khi biết rằng Bazaar linh hoạt hơn tôi nghĩ. Tôi đã thực sự tự hỏi nếu tạo ra một thư mục "chi nhánh" bên trong repo của bạn có thể giải quyết vấn đề tôi đã đề cập trong câu hỏi của tôi. Cảm ơn vì sự thấu hiểu. – ThisSuitIsBlackNot

6

Tôi không biết nhiều về các mô hình phân nhánh trong VCS ngoài Git. Tôi muốn nói rằng trong bất kỳ DVCS bạn có thể thực hiện phân nhánh bằng nhân bản (bạn tạo ra một chi nhánh bằng cách làm một bản sao). Mercurial cái gọi là "chi nhánh được đặt tên" là (từ những gì tôi hiểu nó) trong thực tế cam kết nhãn chỉ được hiểu là một chi nhánh, đôi khi yêu cầu đánh số địa phương của sửa đổi để giải quyết sự mơ hồ. Mercurial "bookmarks" ar, tôi nghĩ, khá giống với các nhánh Git. Hai DVCS có rất khái niệm phân nhánh khác nhau là MonotoneDarcs. Tôi nghĩ rằng "phân nhánh bằng cách sao chép" mà Subversion sử dụng, nơi tách biệt giữa tên dự án và tên chi nhánh là theo quy định quy ước, là một ý tưởng sai lầm.


Trong các bản sửa đổi Git tạo thành một đồ thị theo chu kỳ (DAG) cam kết. Nó được chỉ dẫn, bởi vì các cam kết có cha mẹ. Đó là một vấn đề rất quan trọng: các cạnh trong DAG của các cam kết là từ cam kết với cha mẹ của nó (hoặc, trong trường hợp cam kết hợp nhất, hai hoặc nhiều cha mẹ của nó). Đồ thị của các cam kết là tuần hoàn, có nghĩa là không có chuỗi (không có đường dẫn) bắt đầu và kết thúc với cùng một đối tượng.

Git glossary xác định "chi nhánh" là dòng hoạt động phát triển. Ý tưởng này là đằng sau việc thực hiện các chi nhánh trong Git.

Cam kết gần đây nhất trên một chi nhánh được gọi là mẹo của chi nhánh đó. Đầu của chi nhánh được tham chiếu bởi một chi nhánh chi nhánh, đó chỉ là một tên tượng trưng cho cam kết này. Ở dạng nhánh "lỏng lẻo" của nó (ví dụ như nhánh 'master') chỉ là một tệp ở đâu đó trong thư mục refs/heads/ bên trong kho git (bên trong .git dir), chứa tham chiếu đến mũi hiện tại của nhánh: SHA-1 của nó số nhận dạng của cam kết (dưới dạng chuỗi thập lục phân).

Khi bạn tạo một cam kết mới trong Git, đầu chi nhánh hiện đã được kiểm tra sẽ tiến lên phía trước. Nói cách khác, commit mới được tạo trên đỉnh của nhánh hiện tại, và nhánh tiến lên commit mới (tương tự như cách con trỏ lên đỉnh của stack có thể tiến lên).

Một kho lưu trữ git có thể theo dõi một số chi nhánh tùy ý, nhưng cây làm việc của bạn (nếu bạn có) chỉ được liên kết với một nhánh (nhánh "hiện tại" hoặc "đã chọn"). Nhánh hiện tại được đưa ra bởi con trỏ HEAD. HEAD là con trỏ (thường) đến chi nhánh hiện đã được kiểm tra (với một tên chi nhánh), giống như các nhánh chi nhánh là các con trỏ tới các mẹo của các nhánh.

Ví dụ, nếu hiện kiểm tra ra chi nhánh là 'thầy', sau đó .git/HEAD tập tin (đại diện HEAD) sẽ chứa LF đơn chấm dứt phù hợp với ref: refs/heads/master (một tài liệu tham khảo biểu tượng để refs/heads/master), và .git/refs/heads/master (người đứng đầu chi nhánh 'thầy') sẽ chứa ví dụ LF đã chấm dứt dòng 0b127cb8ab975e43398a2b449563ccb78c437255, whihc là mã định danh SHA-1 thành đầu nhánh 'master' (nghĩa là nếu nhánh hiện tại không được "đóng gói": thì bạn phải xem .git/packed-refs).

Một số lệnh trong Git, chẳng hạn như "git commit" hoặc "git reset" thao tác/thay đổi nhánh chi nhánh; khác như "git checkout" thao tác/thay đổi HEAD (tham chiếu tượng trưng cho nhánh hiện tại).

"git log branch" lệnh hiển thị tất cả các cam kết có thể truy cập từ mẹo chi nhánh, có nghĩa là mẹo chi nhánh, cha mẹ, cha mẹ (hoặc cha mẹ) của phụ huynh đó cam kết v.v.

Trong Git, xóa nhánh có nghĩa là chỉ cần xóa đầu nhánh. Điều đó có thể có nghĩa là một số cam kết trở thành "vô hình", không thể truy cập được (các chi nhánh và thẻ), có nghĩa là vào một thời điểm, các cam kết đó có thể lấy rác và lấy ra khỏi kho. Nhưng nếu bạn có thể xóa chi nhánh với "git branch -d <branchname>" thì điều đó có nghĩa là không có cam kết nào bị mất; bạn có thể buộc xóa chi nhánh bằng "git branch -D < tên chi nhánh >". Đổi tên một chi nhánh đơn giản chỉ là vấn đề đổi tên đầu nhánh, một tham chiếu tượng trưng (tên tượng trưng) của nhánh chi nhánh; tên nhánh không được lưu ở bất kỳ đâu trong đối tượng commit.


Git cũng có khái niệm về reflogs, mà là một lịch sử địa phương của nơi đầu chi nhánh chỉ (và khi nào). Ví dụ: nếu bạn sửa đổi cam kết với "git commit --amend", mẹo chi nhánh sẽ được thay thế bằng cam kết đã sửa đổi và HEAD^sẽ là phụ huynh cam kết trước và sau khi sửa đổi, trong khi sẽ có mục nhập trong reflog cho phiên bản trước khi sửa đổi và sau khi sửa đổi. Nếu bạn tua lại lịch sử bằng cách sử dụng "git reset", reflog sẽ chứa thông tin về mẹo chi nhánh cũ trước khi tua lại.

Trong bản giới thiệu ngắn gọn, hãy đảm bảo an toàn hơn và dễ dàng khôi phục các lệnh git.

Các vấn đề liên quan