Rebase: nó là gì, khác Merge như thế nào và nguyên lý hoạt động

Tác giả: IT Sectr Đã đăng: 2026-05-10 Thời gian đọc: 10 phút

Rebase là một thao tác trong Git di chuyển một chuỗi commit đến một commit cơ sở mới, viết lại lịch sử của nhánh. Không giống như Merge, Rebase không tạo commit hợp nhất mà áp dụng lại các commit lên trạng thái hiện tại của nhánh đích. Theo git-scm.com, 2026, rebase được sử dụng trong 58% dự án Git để duy trì lịch sử commit tuyến tính sạch sẽ.

Những điểm chính

  • Rebase di chuyển commit đến cơ sở mới, viết lại lịch sử nhánh
  • Lịch sử tuyến tính là lợi thế chính của rebase: git log đọc được mà không có phân nhánh
  • Không dùng cho nhánh công khai — rebase viết lại commit, phá vỡ lịch sử của đồng nghiệp
  • Rebase tương tác cho phép hợp nhất, đổi tên và xóa commit
  • Nguyên tắc vàng: không bao giờ rebase một nhánh mà ai đó đã push

Rebase là gì?

Rebase (tái cơ sở) là một thao tác Git di chuyển các commit từ nhánh hiện tại đến một điểm cơ sở mới. Thay vì tạo commit hợp nhất, rebase lấy từng commit từ nhánh nguồn và áp dụng từng cái một lên cơ sở mới. Kết quả là một chuỗi commit tuyến tính không có phân nhánh.

Tên rebase bắt nguồn từ “re-base” — thay đổi cơ sở. Trong khi merge kết hợp hai nhánh tại một điểm, rebase di chuyển toàn bộ nhánh của bạn đến một vị trí mới, làm cho nó trông như thể bạn bắt đầu phát triển từ trạng thái hiện tại của nhánh đích. Điều này tạo ra ảo giác về công việc tuần tự hoàn hảo.

Theo Atlassian, 2025, các nhóm sử dụng rebase cho nhánh tính năng dành ít hơn 30% thời gian phân tích lịch sử commit so với các nhóm chỉ sử dụng merge. Lịch sử tuyến tính đơn giản hóa git blame, bisect và xem log qua git log --oneline.

Sự khác biệt cơ bản với Merge

Merge hợp nhất các nhánh bằng cách tạo một commit có hai cha. Rebase viết lại lịch sử: các commit mới được tạo với hash mới, mặc dù các thay đổi của chúng giống với bản gốc. Điều này có nghĩa là rebase thay đổi định danh SHA của commit, điều rất quan trọng đối với các nhánh công khai.

Rebase hoạt động như thế nào

Cơ chế rebase bao gồm bốn bước: Git xác định tổ tiên chung (cơ sở hợp nhất) của nhánh hiện tại và nhánh đích, sau đó tuần tự áp dụng từng commit của nhánh hiện tại lên nhánh đích. Nếu xảy ra xung đột ở bước nào, rebase dừng lại và chờ giải quyết.

bash
# Tình huống ban đầu: nhánh feature chậm hơn develop 3 commit
git checkout feature/new-login
git rebase develop

# Git lấy 3 commit từ feature và áp dụng chúng lên develop
# Nếu không có xung đột — rebase hoàn thành tự động
# Nếu có — Git dừng lại tại commit xung đột

Sau rebase, nhánh tính năng chứa tất cả commit từ develop cộng với các commit riêng của nó, xuất hiện như một sự tiếp nối của develop. Điều này cho phép hợp nhất vào develop qua fast-forward mà không tạo commit hợp nhất.

Quy trình từng bước

Hãy xem một ví dụ chi tiết: một nhà phát triển đã tạo nhánh tính năng từ develop, thực hiện hai commit, trong khi đó các nhà phát triển khác đã thêm ba commit vào develop. Rebase sẽ di chuyển hai commit tính năng đến vị trí mới, tạo bản sao của chúng với SHA mới.

bash
# 1. Tạo nhánh feature
git checkout -b feature/payment-refactor develop

# 2. Thực hiện commit trong feature
git commit -m "refactor: extract payment validation"
git commit -m "refactor: add payment gateway interface"

# 3. Cập nhật develop (công việc của đồng nghiệp)
git checkout develop
git pull

# 4. Rebase feature lên develop mới
git checkout feature/payment-refactor
git rebase develop

# 5. Bây giờ feature có thể được hợp nhất qua fast-forward
git checkout develop
git merge feature/payment-refactor

Nếu xung đột xảy ra ở bước 4, Git dừng lại ở commit có vấn đề. Nhà phát triển giải quyết xung đột, chạy git add và thực hiện git rebase --continue. Để bỏ qua commit — git rebase --skip, để hủy toàn bộ rebase — git rebase --abort.

Tự động bỏ qua commit rỗng

Cờ --empty kiểm soát hành vi của rebase với commit rỗng — tình huống mà tất cả thay đổi của một commit đã có trong nhánh đích. Theo mặc định, rebase dừng lại và yêu cầu quyết định. Với --empty=drop, Git tự động bỏ qua các commit đó mà không dừng lại, tăng tốc rebase hàng loạt với số lượng lớn commit.

Rebase tương tác

Rebase tương tác (git rebase -i) là một công cụ mạnh mẽ để chỉnh sửa lịch sử commit. Nó mở trình soạn thảo với danh sách commit và các lệnh chính: pick (giữ lại), reword (thay đổi thông điệp), edit (thay đổi nội dung), squash (hợp nhất với commit trước), fixup (hợp nhất không cần thông điệp), drop (xóa).

bash
# Rebase tương tác 4 commit cuối cùng
git rebase -i HEAD~4

# Trình soạn thảo sẽ mở ra với kế hoạch rebase:
# pick a1b2c3 feat: add login screen
# pick d4e5f6 fix: login validation
# pick g7h8i9 fix: login layout
# pick j0k1l2 docs: add login comments

# Thay đổi thành:
# pick a1b2c3 feat: add login screen
# squash d4e5f6 fix: login validation
# squash g7h8i9 fix: login layout
# drop j0k1l2 docs: add login comments

Kết quả: ba commit (màn hình đăng nhập, xác thực, bố cục) được nén thành một, và commit có bình luận bị xóa. Điều này cho phép gửi lịch sử sạch sẽ để xem xét mã mà không có bản nháp và sửa chữa. Rebase tương tác là công cụ tiêu chuẩn để chuẩn bị nhánh tính năng trước Pull Request.

Rebase vs Merge: so sánh

Rebase và Merge giải quyết cùng một vấn đề — tích hợp các thay đổi — nhưng theo những cách khác nhau về cơ bản. Sự lựa chọn giữa chúng phụ thuộc vào loại lịch sử bạn muốn thấy trong git log và ai khác đang làm việc với nhánh của bạn.

Tiêu chíMergeRebase
Lịch sửGiữ phân nhánhTuyến tính, không nhánh
Commit hợp nhấtĐược tạo (trừ ff)Không được tạo
SHA commitKhông thay đổiĐược tạo mới
An toànAn toàn cho nhánh công khaiNguy hiểm — viết lại lịch sử
Khả năng đọc logĐồ thị phân nhánhĐường thẳng
git bisectTiện lợi — thấy điểm hợp nhấtTiện lợi — chuỗi tuyến tính

Quy tắc thực tế: sử dụng merge để tích hợp vào các nhánh chia sẻ (develop, main) và rebase để cập nhật các nhánh tính năng cá nhân. Nhiều nhóm kết hợp cả hai: rebase tính năng lên develop, sau đó --no-ff merge vào develop.

Tác động đến git bisect

Git bisect là công cụ để tìm commit đã gây ra hồi quy. Khi sử dụng merge, git bisect đi qua các commit hợp nhất một cách chính xác, xem xét cả hai cha. Với rebase, bisect hoạt động nhanh hơn vì lịch sử tuyến tính và không yêu cầu phân nhánh. Tuy nhiên, nếu rebase được thực hiện sau khi các commit đã được nhóm biết đến, SHA gốc bị mất và bisect có thể không tìm thấy commit có vấn đề.

Khi nào sử dụng Rebase

Rebase là tối ưu trong ba tình huống: chuẩn bị nhánh tính năng cho Pull Request, cập nhật nhánh cá nhân lên trạng thái hiện tại của main/develop, và dọn dẹp lịch sử trước khi hợp nhất. Trong mỗi trường hợp, rebase cải thiện khả năng đọc lịch sử mà không gây rủi ro cho công việc nhóm.

Trước Pull Request, nên thực hiện rebase tương tác để kết hợp các commit nháp (WIP, sửa chữa sau đánh giá) thành các đơn vị logic có ý nghĩa. Điều này giúp việc đánh giá mã dễ dàng hơn: người đánh giá thấy không phải 15 commit nhỏ mà là 3-5 thay đổi có cấu trúc với thông điệp rõ ràng.

Để cập nhật nhánh tính năng, rebase được ưu tiên hơn merge vì nó không tạo các commit hợp nhất không cần thiết. Nếu bạn định kỳ chạy git rebase develop trong nhánh tính năng, việc hợp nhất cuối cùng sẽ không có một loạt 10 commit hợp nhất — chỉ có các commit tính năng sạch sẽ trên develop.

Dọn dẹp lịch sử qua rebase tương tác trước khi hợp nhất cho phép ẩn các sửa chữa nhỏ (lỗi chính tả, định dạng) và nhóm commit theo chức năng. Thông điệp Git nên tuân theo quy ước Conventional Commits (fix:, feat:, refactor:, docs:), tạo ra changelog tự động.

Rủi ro và quy tắc của Rebase

Rebase là một thao tác nguy hiểm nếu áp dụng sai cách. Rủi ro chính là viết lại lịch sử đã được công bố. Nếu một nhà phát triển rebase một nhánh mà người khác đã push và đang sử dụng, các bản sao cục bộ của họ sẽ mất đồng bộ và họ sẽ phải thực hiện force-pull với nguy cơ mất dữ liệu.

  • Nguyên tắc vàng: không bao giờ rebase các commit đã tồn tại trong kho lưu trữ chung. Điều này áp dụng cho bất kỳ nhánh nào mà các thành viên khác trong nhóm có thể truy cập
  • Force push: sau khi rebase nhánh tính năng cục bộ, cần push với cờ --force-with-lease, an toàn hơn --force vì nó kiểm tra xem ai đó đã cập nhật nhánh trên máy chủ chưa
  • Mất ngữ cảnh: rebase phá hủy thông tin về thời điểm và từ nhánh nào nhánh tính năng được tạo. Nếu việc giữ ngày tạo nhánh là quan trọng, hãy sử dụng merge
  • Xung đột: trong rebase, xung đột phải được giải quyết cho từng commit riêng lẻ, có thể tốn thời gian với số lượng lớn commit

Để giảm thiểu rủi ro, hãy tuân theo quy tắc này: chỉ rebase cho các nhánh cá nhân chưa được công bố. Nếu một nhánh đã có trong kho lưu trữ chung, hãy sử dụng merge với --no-ff. Nếu bạn cần rebase một nhánh đã công bố, hãy cảnh báo nhóm và phối hợp force push trước.

Bảo vệ tự động chống lại rebase nguy hiểm được thực hiện thông qua hook phía máy chủ: hook pre-receive trên máy chủ Git có thể kiểm tra xem push có viết lại các commit đã công bố không. GitHub và GitLab cung cấp bảo vệ tích hợp cho các nhánh được bảo vệ — force push bị chặn trừ khi quản trị viên gỡ bỏ bảo vệ.

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

Điều gì xảy ra nếu bạn rebase một nhánh công khai?

Lịch sử của nhánh sẽ thay đổi — SHA của commit sẽ khác. Tất cả những người đã push nhánh này hoặc tạo nhánh con từ nó sẽ gặp xung đột khi git pull. Việc khôi phục sẽ yêu cầu can thiệp thủ công và có thể dẫn đến mất commit.

Có thể hoàn tác rebase không?

Trước khi hoàn thànhgit rebase --abort. Sau khi hoàn thành — chỉ qua git reflog, nếu rebase được thực hiện gần đây. reflog lưu trữ lịch sử di chuyển của HEAD, qua đó có thể quay lại trạng thái trước rebase: git reset --hard HEAD@{1}.

Rebase khác cherry-pick như thế nào?

Rebase di chuyển một chuỗi commit đến cơ sở mới. Cherry-pick áp dụng một hoặc nhiều commit cụ thể vào nhánh hiện tại. Rebase tự động cho toàn bộ chuỗi, cherry-pick yêu cầu chọn thủ công từng commit.

Có nên rebase trước mỗi Pull Request không?

Được khuyến nghị, nhưng không bắt buộc. Rebase trước PR cập nhật nhánh lên trạng thái hiện tại của main/develop và dọn dẹp lịch sử. Nếu nhánh được tạo gần đây và không cần cập nhật, chỉ cần rebase tương tác để dọn dẹp commit là đủ.

Rebase ảnh hưởng đến thẻ (tag) như thế nào?

Thẻ không bị di chuyển trong quá trình rebase. Nếu một commit đã được rebase có thẻ, thẻ đó sẽ vẫn ở trên commit cũ không còn là một phần của lịch sử nhánh. Không nên gắn thẻ cho commit trên nhánh tính năng, chỉ trên main.

Tổng kết

  • Rebase — tái cơ sở commit lên cơ sở mới, tạo lịch sử tuyến tính
  • Không giống Merge không tạo commit hợp nhất và viết lại SHA commit
  • Rebase tương tác cho phép nén, đổi tên và xóa commit
  • Nguyên tắc vàng: chỉ rebase nhánh cá nhân, không bao giờ rebase nhánh công khai
  • Sau rebase cần force push (tốt nhất là --force-with-lease)
  • Cho Pull Request nên rebase + dọn dẹp lịch sử qua -i
  • Cách tiếp cận kết hợp: rebase để cập nhật nhánh tính năng, --no-ff merge để hoàn tất

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm