Sự khác biệt giữa 'git merge' và 'git rebase' là gì?


499

Sự khác biệt giữa git mergevà là git rebasegì?


14
vì câu trả lời của tôi đã bị xóa, hãy truy cập liên kết này để có câu trả lời đúng cho câu hỏi này: git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase
HiB

6
Bằng cách này, tôi sẽ thêm trang web này. Tất cả những gì bạn cần biết về git tìm hiểu bằng cách chơi: pcption.github.io/learnGitBranching
Rollyng

Đọc cái này trước: git-scm.com/book/en/v2/. Sau đó: git-scm.com/book/en/v2/Git-Branching-Rebasing Bạn sẽ thực sự hiểu.
Liber

Câu trả lời:


867

Giả sử ban đầu có 3 cam kết, A, B, C:

ABC

Sau đó, nhà phát triển Dan đã tạo cam kết Dvà nhà phát triển Ed đã tạo cam kết E:

ABCDE

Rõ ràng, cuộc xung đột này nên được giải quyết bằng cách nào đó. Đối với điều này, có 2 cách:

MERGE :

ABCDEM

Cả hai cam kết DEvẫn ở đây, nhưng chúng tôi tạo ra cam kết hợp nhất Mkế thừa các thay đổi từ cả hai DE. Tuy nhiên, điều này tạo ra hình dạng kim cương , điều mà nhiều người thấy rất khó hiểu.

rebase :

ABCDER

Chúng tôi tạo cam kết R, nội dung tệp thực tế giống hệt với cam kết hợp nhất Mở trên. Nhưng, chúng tôi thoát khỏi cam kết E, giống như nó chưa từng tồn tại (biểu thị bằng dấu chấm - dòng biến mất). Do sự xóa sổ này, Enên là cục bộ cho nhà phát triển Ed và không bao giờ được đẩy sang bất kỳ kho lưu trữ nào khác. Ưu điểm của rebase là tránh được hình dạng kim cương và lịch sử vẫn ổn định - hầu hết các nhà phát triển đều thích điều đó!


53
Hình minh họa đẹp. Tuy nhiên, tôi không hoàn toàn đồng ý với giai điệu tích cực mà rebase được xử lý. Trong cả hai xung đột hợp nhất và rebase có thể xảy ra cần giải quyết thủ công. Và như mọi khi các lập trình viên tham gia, có một cơ hội không thể bỏ qua các lỗi hay còn gọi là lỗi. Nếu xảy ra lỗi hợp nhất, cả nhóm hoặc cộng đồng có thể thấy hợp nhất và xác minh xem có lỗi được đưa vào đó không. Lịch sử của cuộc nổi loạn ở lại trong repo của 1 nhà phát triển và thậm chí ở đó nó chỉ có giới hạn trong vòng đời của reflog. Nó có thể trông đẹp hơn, nhưng không ai khác có thể thấy dễ dàng những gì đã sai.
Uwe Geuder

> "Tuy nhiên, điều này tạo ra hình dạng kim cương, điều mà nhiều người thấy rất khó hiểu." Ừm ... bạn có thể giải thích không?
Greg Maletic

@GregMaletic: Hình dạng kim cương là lịch sử phi tuyến tính. Tôi không biết về bạn, nhưng tôi không thích những thứ phi tuyến tính nói chung. Điều đó nói rằng, bạn được hoan nghênh sử dụng hợp nhất với kim cương nếu bạn thực sự thích nó - không ai ép buộc bạn.
mvp

1
Mặc dù câu trả lời này cực kỳ hữu ích, nhưng sẽ tốt hơn nếu bạn thêm các lệnh git thực tế với các tệp foo.txt đơn giản để tái tạo nó cục bộ. Giống như người dùng trước đã nói, không rõ ai đang thực hiện rebase.
Vortex

1
@pferrel: Tôi không nghĩ bạn đã hiểu đúng. git mergekhông xen kẽ các cam kết (nhưng nó có thể xuất hiện như vậy bằng cách nhìn vào git log). Thay vào đó, git mergegiữ cho cả lịch sử phát triển của Dan và Ed được giữ nguyên, vì nó được nhìn thấy từ mỗi quan điểm tại một thời điểm. git rebaselàm cho nó trông giống như Dan làm việc trước, và Ed đi theo anh ta. Trong cả hai trường hợp (hợp nhất và rebase), cây tệp kết quả thực tế là hoàn toàn giống nhau.
mvp

158

Tôi thực sự thích đoạn trích này từ 10 điều tôi ghét về git (nó đưa ra một lời giải thích ngắn cho rebase trong ví dụ thứ hai của nó):

3. Tài liệu xảo quyệt

Các trang người đàn ông là một toàn năng “f *** you” 1 . Họ mô tả các lệnh từ quan điểm của một nhà khoa học máy tính, không phải người dùng. Trường hợp tại điểm:

git-push – Update remote refs along with associated objects

Đây là một mô tả cho con người:

git-push – Upload changes from your local repository into a remote repository

Cập nhật, một ví dụ khác: (cảm ơn cgd)

git-rebase – Forward-port local commits to the updated upstream head

Dịch:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

Và sau đó chúng ta có

git-merge - Join two or more development histories together

đó là một mô tả tốt.


1. không kiểm duyệt trong bản gốc


Vấn đề không phải là ngôn ngữ hay người dùng có phải là nhà khoa học máy tính hay không. Trong khi viết lại nó theo một cách khác giúp làm rõ các kết thúc (nghĩa là những gì xảy ra), nó thất bại trong việc giải thích các phương tiện (làm thế nào nó xảy ra). Git yêu cầu hiểu các phương tiện để hiểu các kết thúc. Đó là hiểu chính xác các phương tiện làm cho Git rất khó khăn. Là một công cụ, một cái gì đó được sử dụng để đơn giản hóa hoặc giảm bớt nỗ lực cần thiết trong nhiệm vụ, Git thất bại khủng khiếp. Đáng buồn thay, quá nhiều nhà phát triển không nhận ra nó.
ATL_DEV

128

Cá nhân tôi không thấy kỹ thuật lập biểu đồ tiêu chuẩn rất hữu ích - các mũi tên dường như luôn chỉ sai đường cho tôi. (Họ thường chỉ về phía "cha mẹ" của mỗi lần cam kết, kết cục là ngược thời gian, điều này thật kỳ lạ).

Để giải thích nó bằng lời:

  • Khi bạn rebase chi nhánh của bạn lên chi nhánh của họ, bạn nói với Git để làm cho nó trông như thể bạn đã kiểm tra chi nhánh của họ sạch sẽ, sau đó đã làm tất cả công việc của bạn bắt đầu từ đó. Điều đó làm cho một gói thay đổi rõ ràng, đơn giản về mặt khái niệm mà ai đó có thể xem xét. Bạn có thể lặp lại quá trình này một lần nữa khi có những thay đổi mới trên chi nhánh của họ và bạn sẽ luôn kết thúc với một tập hợp thay đổi rõ ràng "trên đầu" của chi nhánh.
  • Khi bạn hợp nhất chi nhánh của họ vào chi nhánh của mình, bạn gắn hai lịch sử chi nhánh lại với nhau tại thời điểm này. Nếu bạn làm điều này một lần nữa sau đó với nhiều thay đổi hơn, bạn bắt đầu tạo ra một chuỗi lịch sử xen kẽ: một số thay đổi của họ, một số thay đổi của tôi, một số thay đổi của họ. Một số người thấy điều này lộn xộn hoặc không mong muốn.

Vì những lý do tôi không hiểu, các công cụ GUI cho Git chưa bao giờ nỗ lực để trình bày lịch sử hợp nhất rõ ràng hơn, trừu tượng hóa các hợp nhất riêng lẻ. Vì vậy, nếu bạn muốn có một "lịch sử sạch", bạn cần sử dụng rebase.

Tôi dường như nhớ lại việc đã đọc các bài đăng trên blog từ các lập trình viên, những người chỉ sử dụng rebase và những người khác không bao giờ sử dụng rebase.

Thí dụ

Tôi sẽ cố gắng giải thích điều này với một ví dụ chỉ bằng lời nói. Giả sử những người khác trong dự án của bạn đang làm việc trên giao diện người dùng và bạn đang viết tài liệu. Nếu không có rebase, lịch sử của bạn có thể trông giống như:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

Đó là, hợp nhất và cam kết UI ở giữa các cam kết tài liệu của bạn.

Nếu bạn đã khởi động lại mã của mình thành chủ thay vì hợp nhất nó, nó sẽ trông như thế này:

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

Tất cả các cam kết của bạn đều ở trên cùng (mới nhất), tiếp theo là phần còn lại của masterchi nhánh.

( Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của bài đăng "10 điều tôi ghét về Git" được đề cập trong một câu trả lời khác )


42

Mặc dù câu trả lời được chấp nhận và được đánh giá cao nhất là tuyệt vời, nhưng tôi cũng thấy hữu ích khi cố gắng giải thích sự khác biệt chỉ bằng lời nói:

hợp nhất

  • Không sao, chúng tôi có hai trạng thái phát triển khác nhau của kho lưu trữ của chúng tôi. Hãy hợp nhất chúng lại với nhau. Hai cha mẹ, một đứa con kết quả.

nổi loạn

  • Cung cấp các thay đổi của nhánh chính (bất kể tên của nó) cho nhánh tính năng của tôi. Làm như vậy bằng cách giả vờ công việc tính năng của tôi bắt đầu sau, trên thực tế về trạng thái hiện tại của chi nhánh chính.
  • Viết lại lịch sử những thay đổi của tôi để phản ánh điều đó. (cần phải đẩy chúng, bởi vì phiên bản thông thường là tất cả về việc không can thiệp vào lịch sử đã cho)
  • Có khả năng là một trong những thay đổi mà tôi đã thực hiện ít có liên quan đến công việc của tôi

tóm tắt: Khi có thể, rebase hầu như luôn luôn tốt hơn. Làm cho việc tích hợp lại vào chi nhánh chính dễ dàng hơn.

Bởi vì? Work công việc tính năng của bạn có thể được trình bày dưới dạng một 'tệp vá' lớn (còn gọi là diff) đối với nhánh chính, không phải 'giải thích' nhiều phụ huynh: Ít nhất hai, đến từ một hợp nhất, nhưng có thể nhiều hơn nữa, nếu có là một số hợp nhất. Không giống như sáp nhập, nhiều cuộc nổi loạn không thêm vào. (một điểm cộng lớn khác)


18

Git rebase gần hơn với sự hợp nhất. Sự khác biệt trong rebase là:

  • các cam kết cục bộ được loại bỏ tạm thời khỏi chi nhánh.
  • chạy git kéo
  • chèn lại tất cả các cam kết địa phương của bạn.

Vì vậy, điều đó có nghĩa là tất cả các cam kết cục bộ của bạn được chuyển đến cuối cùng, sau khi tất cả các cam kết từ xa. Nếu bạn có một xung đột hợp nhất, bạn cũng phải giải quyết nó.


7

Để dễ hiểu có thể thấy con số của tôi.

Rebase sẽ thay đổi hash hash, để nếu bạn muốn tránh nhiều xung đột, chỉ cần sử dụng rebase khi nhánh đó được hoàn thành / hoàn thành ổn định.

nhập mô tả hình ảnh ở đây


0

Tôi tìm thấy một bài viết thực sự thú vị về git rebase vs merge , đã nghĩ đến việc chia sẻ nó ở đây

  • Nếu bạn muốn xem lịch sử hoàn toàn giống như nó đã xảy ra, bạn nên sử dụng hợp nhất. Hợp nhất bảo tồn lịch sử trong khi rebase viết lại nó.
  • Sáp nhập thêm một cam kết mới vào lịch sử của bạn
  • Rebasing tốt hơn để hợp lý hóa một lịch sử phức tạp, bạn có thể thay đổi lịch sử cam kết bằng cách rebase tương tác.
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.