Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào

  1. Trang chủ
  2. Blog
  3. Phát triển phần mềm
Phát triển phần mềm

Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào

Git merge vs rebase quyết định lịch sử dự án của bạn trông ra sao. Xem cả hai trên cùng một ví dụ với đầu ra log thực tế, học quy tắc duy nhất giúp tránh thảm họa và sao chép một quy trình làm việc nhóm an toàn.

7 phút đọc
Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào
Điểm chính
  • Merge nối hai nhánh bằng một commit merge mới và giữ lịch sử đúng như đã diễn ra.
  • Rebase phát lại các commit của bạn lên trên nhánh khác, cho một đường thẳng nhưng hash commit mới.
  • Đừng bao giờ rebase các commit mà người khác đã kéo về.
  • Rebase nhánh tính năng của riêng bạn trước khi mở pull request, và dùng merge khi đưa nó vào nhánh chính.

Nhánh tính năng của bạn tụt lại so với main và bạn cần phần việc mới. Git merge vs rebase là lựa chọn giữa hai cách để có nó, và cả hai đều đúng. Chúng khác nhau ở chỗ lịch sử trông thế nào sau đó.

Chúng tôi dựng một kho nhỏ, chạy cả hai lệnh và dán đầu ra thực tế bên dưới, để bạn so sánh kết quả thay vì tưởng tượng. Mới dùng Git? Hãy bắt đầu với hướng dẫn Git cho người mới (tiếng Anh).

git merge và git rebase làm gì

git merge lấy đầu của hai nhánh và kết hợp chúng. Nếu cả hai có commit mới, Git tạo một commit merge có hai cha. Không có gì đã tồn tại bị thay đổi.

git rebase lấy các commit chỉ có ở nhánh của bạn, đặt sang một bên, chuyển nhánh của bạn đến đầu nhánh kia rồi phát lại từng commit. Các commit được phát lại là commit mới với hash mới, dù thay đổi bên trong giống nhau.

Git merge trong thực tế

Điểm xuất phát của chúng tôi: commit A trên main, hai commit (F1, F2) trên feature, và thêm một commit (M1) được thêm vào main sau đó. Bây giờ chúng tôi merge main vào feature.

git switch feature
git merge main
git log --oneline --graph

*   f507aab Merge main into feature
|\
| * 8842fb5 M1
* | 082cc6a F2
* | 5a71e3c F1
|/
* 8766865 A

Biểu đồ cho thấy câu chuyện thật: hai dòng công việc được nối lại. Các commit gốc F1 và F2 giữ nguyên hash. Cái giá là thêm một commit merge, và trong dự án sôi động, biểu đồ trở thành một mạng nhện.

Git rebase trong thực tế

Cùng điểm xuất phát, nhưng lần này chúng tôi rebase feature lên main.

git switch feature
git rebase main
git log --oneline --graph

* 1ff474b F2
* bf9149e F1
* 8842fb5 M1
* 8766865 A

Lịch sử là một đường thẳng, như thể bạn bắt đầu làm sau M1. Hãy nhìn các hash: F1 trước là 5a71e3c nay là bf9149e, còn F2 đổi từ 082cc6a sang 1ff474b. Git đã viết lại chúng, và đó là lý do rebase cần cẩn thận.

Merge và rebase song song

Khía cạnhMergeRebase
Hình dạng lịch sửBiểu đồ phân nhánh có commit mergeMột đường thẳng
Commit hiện cóKhông thay đổiĐược viết lại với hash mới
Xung độtGiải quyết một lần, trong commit mergeCó thể phải sửa ở từng commit được phát lại
An toàn trên nhánh dùng chungCóKhông
Phù hợp nhất choĐưa công việc đã xong vào mainCập nhật nhánh của riêng bạn trước khi review

Mẹo: nếu không quyết định được, hãy hỏi còn ai khác có nhánh của bạn. Nếu không ai, rebase là an toàn. Nếu đồng nghiệp đã kéo về, hãy dùng merge.

Quy tắc vàng của rebase

Đừng rebase các commit tồn tại bên ngoài kho của riêng bạn. Sau khi rebase, nhánh của bạn không còn khớp với bản sao trên máy chủ, nên việc push cần ép buộc. Nếu đồng nghiệp đã xây công việc trên các commit cũ, lịch sử của họ giờ mâu thuẫn với của bạn, và gỡ rối rất đau đầu.

Rebase nhánh tính năng riêng tư của bạn thì không sao. Rebase main hoặc bất kỳ nhánh nào người khác dùng thì không được.

Quy trình làm việc nhóm an toàn

Quy trình này giữ lịch sử sạch mà không làm ai bất ngờ. Đây cũng là cách đa số nhóm dùng trước pipeline CI của họ, như pipeline trong hướng dẫn GitHub Actions CI/CD (tiếng Anh) của chúng tôi.

git switch feature
git fetch origin
git rebase origin/main        # or: git pull --rebase
# fix conflicts, then: git add <file> && git rebase --continue
git push --force-with-lease   # only on your own branch

--force-with-lease từ chối ghi đè nhánh trên máy chủ nếu ai đó đã push kể từ lần fetch cuối của bạn, điều mà --force thường sẽ âm thầm phá hủy. Khi pull request được duyệt, hãy merge nó vào main.

Cách hoàn tác một rebase hỏng

Rebase trông có vẻ phá hoại, nhưng các commit cũ vẫn nằm trong reflog của Git một thời gian, nên bạn có thể quay lại.

git reflog                    # find the commit before the rebase
git reset --hard HEAD@{5}     # example position, check reflog first

Hãy tạo nhánh sao lưu bằng git branch backup trước bất kỳ rebase rủi ro nào, và việc khôi phục chỉ còn một lệnh. Đang chạy cơ sở dữ liệu hoặc công cụ trong container? Xem hướng dẫn Docker cho người mới (tiếng Anh) của chúng tôi.

Lời kết

Merge giữ sự thật, rebase giữ nó gọn gàng. Hãy dùng rebase để làm mới nhánh của riêng bạn, dùng merge để bàn giao, và đừng bao giờ viết lại lịch sử mà người khác phụ thuộc.

Câu hỏi thường gặp

Khác biệt giữa git merge và git rebase là gì?

Merge kết hợp hai nhánh bằng một commit merge và giữ mọi commit hiện có. Rebase chuyển các commit của bạn lên trên nhánh khác và viết lại chúng, tạo ra lịch sử tuyến tính.

Tôi nên dùng merge hay rebase?

Rebase nhánh tính năng của bạn để luôn cập nhật, và merge khi bàn giao vào nhánh dùng chung như main. Hãy dùng merge bất cứ khi nào người khác cùng dùng nhánh.

git rebase có nguy hiểm không?

An toàn trên nhánh riêng tư và rủi ro trên nhánh dùng chung, vì nó viết lại hash commit. Hãy dùng nhánh sao lưu và reflog để khôi phục nếu có sự cố.

force-with-lease làm gì?

Nó chỉ push ép khi nhánh từ xa vẫn ở nơi bạn thấy lần cuối, nên bạn không vô tình ghi đè các commit mới của đồng nghiệp.

Rebase có xóa commit của tôi không?

Không. Nó tạo commit mới với cùng thay đổi, và các commit cũ vẫn nằm trong reflog cho đến khi Git dọn dẹp.

Tiếp tục học (bài viết tiếng Anh)

Làm việc với Stack Quora

Cần hỗ trợ về kiểm thử, WordPress hoặc SEO?

Chúng tôi giúp các nhóm phát hành phần mềm tốt hơn và phát triển website. Hãy cho chúng tôi biết bạn đang làm gì, chúng tôi sẽ gợi ý bước tiếp theo rõ ràng.

Tiếp tục đọc

Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại

Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.

Trí tuệ nhân tạo

Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó

Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …

Đọc bài viết →
DevOps

Giải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng

Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…

Đọc bài viết →
Phát triển phần mềm

Giải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429

Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …

Đọc bài viết →
Tự động hóa kiểm thử

Chế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối

Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…

Đọc bài viết →
Kiểm thử phần mềm

Giải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%

Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…

Đọc bài viết →
Cơ sở dữ liệu & SQL

DELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại

DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ

Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…

Đọc bài viết →
Phát triển phần mềm

Giao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch

Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …

Đọc bài viết →
Phát triển phần mềm

Giải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng

Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…

Đọc bài viết →
Phát triển phần mềm

Hàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng

Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …

Đọc bài viết →
Trí tuệ nhân tạo

Đại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy

Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …

Đọc bài viết →
DevOps

Giám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết

Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…

Đọc bài viết →
DevOps

Docker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách

Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …

Đọc bài viết →
Tự động hóa kiểm thử

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…

Đọc bài viết →
Phát triển phần mềm

Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào

Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.

Đọc bài viết →
Phát triển phần mềm

List comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh

List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)

Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.

Đọc bài viết →