2009-08-06 31 views
263

Giả sử tôi là duy trì một repo, và tôi muốn kéo những thay đổi từ một người đóng góp, có một vài công việc có thể:Git Cherry-pick vs Merge Workflow

  1. tôi cherry-pick từng cam kết từ xa (theo thứ tự). Trong trường hợp này git ghi lại cam kết không liên quan đến nhánh từ xa.
  2. I merge nhánh, kéo tất cả thay đổi và thêm cam kết "xung đột" mới (nếu cần).
  3. I merge mỗi cam kết từ nhánh từ xa riêng rẽ (theo thứ tự), cho phép xung đột được ghi lại cho mỗi lần commit, thay vì được nhóm lại với nhau thành một.
  4. Để hoàn tất, bạn có thể thực hiện rebase (giống như tùy chọn cherry-pick?), Tuy nhiên, sự hiểu biết của tôi là điều này có thể gây nhầm lẫn cho người đóng góp. Có lẽ đó là loại bỏ tùy chọn 1.

Trong cả hai trường hợp 2 và 3, git ghi lại lịch sử chi nhánh của các cam kết, không giống như 1.

là gì của pro và con của giữa việc sử dụng một trong hai cherry-pick hoặc merge phương pháp mô tả ? Sự hiểu biết của tôi là phương pháp 2 là tiêu chuẩn, nhưng tôi cảm thấy rằng việc giải quyết một cam kết lớn với một "xung đột" hợp nhất, không phải là giải pháp sạch nhất.

Trả lời

253

Cả hai rebase (và cherry-pick) và merge đều có những ưu điểm và nhược điểm của chúng. Tôi tranh luận cho merge tại đây, nhưng đáng để hiểu cả hai. (Nhìn vào đây để yêu cầu thay, nổi lập luận answer trường hợp liệt kê nơi rebase được ưa thích.)

merge được ưa thích hơn cherry-pickrebase cho một vài lý do.

  1. Độ bền. Số nhận dạng SHA1 của một cam kết xác định nó không chỉ trong và của chính nó mà còn liên quan đến tất cả các cam kết khác đứng trước nó. Điều này cung cấp cho bạn một đảm bảo rằng trạng thái của kho lưu trữ tại một SHA1 đã cho giống hệt nhau trên tất cả các dòng vô tính. Có (theo lý thuyết) không có cơ hội ai đó đã thực hiện những gì trông giống như thay đổi tương tự nhưng thực sự đang làm hỏng hoặc chiếm đoạt kho lưu trữ của bạn. Bạn có thể chọn anh đào trong những thay đổi riêng lẻ và chúng có thể giống nhau, nhưng bạn không có bảo đảm. (Do vấn đề thứ cấp, các cam kết mới được chọn bằng anh đào sẽ chiếm thêm không gian nếu một người nào khác anh đào hái trong cùng một cam kết một lần nữa, vì cả hai sẽ có mặt trong lịch sử ngay cả khi các bản sao làm việc của bạn kết thúc giống hệt nhau.)
  2. Dễ sử dụng. Mọi người có xu hướng hiểu quy trình làm việc merge khá dễ dàng. rebase có xu hướng được xem là nâng cao hơn. Tốt nhất là nên hiểu cả hai, nhưng những người không muốn trở thành chuyên gia trong việc kiểm soát phiên bản (theo kinh nghiệm của tôi đã bao gồm nhiều đồng nghiệp làm tốt những gì họ làm, nhưng không muốn dành thêm thời gian) thời gian vừa mới hợp nhất.

Ngay cả với một quy trình làm việc hợp nhất nặng rebasecherry-pick vẫn còn hữu ích cho các trường hợp cụ thể:

  1. Một nhược điểm để merge là lịch sử lộn xộn.rebase ngăn chặn một loạt các cam kết bị phân tán trong lịch sử của bạn, vì chúng sẽ là nếu bạn hợp nhất theo định kỳ trong các thay đổi của người khác. Đó là thực tế mục đích chính của nó khi tôi sử dụng nó. Những gì bạn muốn là rất cẩn thận, không bao giờ là mã số rebase mà bạn đã chia sẻ với các kho lưu trữ khác. Sau khi cam kết là push, người khác có thể đã cam kết trên đầu trang của nó và việc rebasing sẽ tốt nhất là nguyên nhân gây ra sự trùng lặp được thảo luận ở trên. Tại tồi tệ nhất bạn có thể kết thúc với một kho lưu trữ rất bối rối và lỗi tinh tế nó sẽ đưa bạn một thời gian dài để chồn ra.
  2. cherry-pick hữu ích cho việc lấy mẫu ra một tập hợp con nhỏ các thay đổi từ nhánh chủ đề mà bạn đã quyết định loại bỏ cơ bản, nhưng nhận ra có một vài phần hữu ích.

Đối với việc thích hợp nhiều thay đổi hơn một: nó đơn giản hơn rất nhiều. Nó có thể nhận được rất tẻ nhạt để làm sáp nhập của changesets cá nhân một khi bạn bắt đầu có rất nhiều người trong số họ. Độ phân giải hợp nhất trong git (và trong Mercurial, và ở Bazaar) là rất rất tốt. Bạn sẽ không gặp phải vấn đề lớn khi sáp nhập ngay cả các nhánh dài. Tôi thường hợp nhất tất cả mọi thứ cùng một lúc và chỉ nếu Tôi nhận được một số lượng lớn các xung đột để tôi sao lưu và chạy lại phần kết hợp. Thậm chí sau đó tôi làm điều đó trong khối lớn. Như một ví dụ rất thực tế, tôi đã có một đồng nghiệp có giá trị thay đổi trong 3 tháng để hợp nhất và có khoảng 9000 xung đột trong 250000 mã vạch. Những gì chúng tôi đã thực hiện để khắc phục là thực hiện hợp nhất giá trị của một tháng tại một thời điểm: các xung đột không tích lũy tuyến tính và thực hiện theo các kết quả trong số xa hơn ít hơn 9000 xung đột. Nó vẫn còn rất nhiều công việc, nhưng không nhiều như cố gắng để làm điều đó một cam kết tại một thời điểm.

+1

Thực ra, về lý thuyết có khả năng Mallory có thể làm hỏng kho lưu trữ của bạn bằng cách tạo các cam kết có cùng SHA1 nhưng nội dung khác nhau, nó có thể sẽ không bao giờ xảy ra trong thực tế. :) – Bombe

+1

Ha :) Tôi có nghĩa là "trong lý thuyết tỷ lệ cược rất thấp mà bạn có thể dựa vào nó không xảy ra", nhưng bạn là đúng rằng nó đọc topsy-turvy. – quark

+0

Bạn nghĩ gì về "hợp nhất - yêu cầu"? – cmcginty

84

Theo quan điểm của tôi, bạn nên dành riêng cho các trường hợp hiếm hoi, ví dụ nếu bạn đã sửa trực tiếp trên nhánh 'master' (nhánh chính, nhánh phát triển) và sau đó nhận ra rằng nó nên được áp dụng cũng để 'duy trì'. Bạn nên làm việc cơ bản hoặc trên hợp nhất, hoặc trên rebase (hoặc "git pull --rebase").

Hãy nhớ rằng cam kết đã chọn hoặc được rebased là khác nhau từ quan điểm của Git (có định danh SHA-1 khác) so với bản gốc, vì vậy nó khác với cam kết trong kho từ xa. (Rebase thường có thể đối phó với điều này, vì nó kiểm tra bản vá id tức là các thay đổi, không phải là một cam kết id).

Cũng trong git bạn có thể hợp nhất nhiều chi nhánh cùng một lúc: được gọi là bạch tuộc hợp nhất. Lưu ý rằng hợp nhất bạch tuộc phải thành công mà không có xung đột. Tuy nhiên nó có thể hữu ích.

HTH.

+16

+1 cho điểm mà rebase/cherry-pick thực sự "sao chép" các cam kết và do đó mất liên kết đến cam kết ban đầu. – studgeek

+1

Chúng tôi sử dụng lựa chọn anh đào theo cách này, độc quyền để chuyển các cam kết sửa lỗi (có thể là các tính năng VERY SMALL) thành một nhánh phát hành hiện có để chuẩn bị một bản vá. Các tính năng mở rộng nhiều cam kết thường đảm bảo đi vào nhánh phát hành dựa trên tổng thể. – foxxtrot

+3

@foxxtrot: Một giải pháp khác là tạo một nhánh riêng biệt cho một bugfix, dựa trên cam kết lâu đời nhất mà triển khai lỗi này và kết hợp nó thành 'maint' và thành 'master' ... mặc dù trong trường hợp này bạn cần biết bugfix áp dụng cho cả hai nhánh. –

0

Rebase và chọn Cherry là cách duy nhất bạn có thể giữ lịch sử cam kết sạch. Tránh sử dụng hợp nhất và tránh tạo xung đột hợp nhất. Nếu bạn đang sử dụng gerrit, hãy thiết lập một dự án để Hợp nhất nếu cần và một dự án để chọn chế độ anh đào và tự thử.

+0

bạn có thể xây dựng thêm một chút nữa không. ... –