Khi thực hiện rebase, Git sẽ "dịch chuyển" các commit từ branch hiện tại lên đầu của branch đích. Trong quá trình này, Git cần áp dụng lại từng commit một lên branch mới.
Vấn đề nảy sinh khi các commit đang được rebase có sửa đổi cùng một file hoặc cùng một vị trí trong file với các commit đã tồn tại trên branch đích.
Nếu một commit đang được rebase sửa đổi cùng một vị trí trong file với commit trên branch đích, Git sẽ gặp khó khăn vì nó không biết nên chọn phiên bản sửa đổi nào. Rebase conflicts xảy ra khi Git cần sự can thiệp thủ công từ phía người dùng (là bạn) để hoàn tất việc rebase.
Thậm chí trước khi thao tác rebase có thể bắt đầu, Git có thể báo lỗi ngay lập tức nếu trong working directory của bạn đang có những thay đổi untracked hoặc uncommitted mà có nguy cơ bị ghi đè bởi lệnh rebase. Nếu gặp trường hợp này, bạn sẽ thấy thông báo sau:
error: Your local changes to the following files would be overwritten by rebase:
index.html
Please commit your changes or stash them before you merge.
hoặc
error: The following untracked working tree files would be overwritten by rebase:
_includes/newsletter_signup.html
Please move or remove them before you merge.
Aborting
Khi điều này xảy ra, Git chưa thể bắt đầu quy trình rebase. Để khắc phục, bạn bắt buộc phải xử lý bằng cách commit hoặc stash các file được nhắc trong thông báo trước khi có thể tiến hành rebase.
Sau khi đã xử lý xong lỗi False Start ở trên, bạn có thể bắt đầu thực hiện việc rebase, và các xung đột rebase có thể xảy ra tại đây. Khi gặp loại xung đột này, Git thực sự đã bắt đầu thao tác rebase nhưng buộc phải tạm dừng giữa chừng vì không thể tự giải quyết.
Bạn sẽ thấy thông báo như sau:
CONFLICT (content): Merge conflict in ...
CONFLICT (modify/delete): Merge conflict in ...
error: could not apply abc1234... Commit message here
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
Trong ví dụ này, chúng ta cố gắng rebase nhánh feature lên nhánh main bằng lệnh git rebase main, nhưng xung đột đã xảy ra ở commit abc1234. Hãy làm theo các bước dưới đây để giải quyết.
Nếu bạn cảm thấy quá rối hoặc chưa có thời gian để sửa conflict ngay, hãy dùng lệnh abort để hủy bỏ thao tác rebase. Lệnh này sẽ đưa repository của bạn quay về trạng thái trước khi rebase.
git rebase --abort
Sau khi nhận được thông báo rebase conflict, bạn bắt buộc phải hoàn thành tất cả các bước bên dưới hoặc hủy bỏ (abort) nó. Đừng cố gắng làm việc khác hoặc sửa file khác cho đến khi conflict được giải quyết hoặc bị hủy bỏ.
Khi rebase gặp conflict, Git sẽ tạm dừng ở commit đang gây ra xung đột. Để tìm ra chính xác file nào đang bị conflict, hãy chạy:
git status
Output:
interactive rebase in progress; onto abc1234
Last command done (1 command done):
pick def5678 Add new feature
No commands remaining.
You are currently rebasing branch 'feature' on 'abc1234'.
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: _layouts/page.html
deleted by us: about.md
Untracked files not listed (use "git add <file>..." to track)
new_file.txt
Các file nằm dưới mục Unmerged paths: Đây là các file cần bạn can thiệp thủ công. Trong ví dụ này là _layouts/page.html và about.md.
Lưu ý rằng bạn đang ở giữa quá trình rebase (thấy dòng "You are currently rebasing..."), không phải trong trạng thái merge.
Các loại xung đột thường gặp:
deleted by us hoặc deleted by them: File tồn tại ở commit đang được rebase nhưng bị xóa ở branch đích (hoặc ngược lại).
both modified: File bị sửa đổi bởi cả commit đang được rebase và commit trên branch đích, Git không biết nên chọn phiên bản nào.
Hãy mở (các) file bị both modified bằng trình soạn thảo văn bản (editor) của bạn. Tiếp theo, hãy tìm các conflict markers bắt đầu bằng <<<<<<< mà Git đã thêm vào.
Những dấu hiệu này chỉ ra vị trí cụ thể mà Git không thể tự giải quyết.
Phần trên cùng (HEAD) là nội dung của branch đích (main) - đây là phiên bản hiện tại trên branch mà bạn đang rebase lên.
Phần dưới cùng là nội dung của commit đang được rebase (commit từ branch feature).
Chúng được ngăn cách bởi dấu =====.
Cấu trúc sẽ trông như thế này:
<<<<<<< HEAD
Changes from the target branch (main) - Code của nhánh Main
======
Changes from the commit being rebased (feature) - Code của commit đang rebase
>>>>>>> def5678... Commit message here
Nhiệm vụ của bạn là xóa bỏ thủ công các dòng đánh dấu (<<<, ===, >>>) và thay thế toàn bộ khối đó bằng đoạn code cuối cùng mà bạn muốn giữ lại (có thể là code của main, code của commit đang rebase, hoặc kết hợp cả hai).
Sau khi sửa xong, thực hiện lưu file và lặp lại quy trình này cho tất cả các file both modified được xác định ở bước 1.
Sau khi sửa xong nội dung file, đã đến lúc đưa chúng vào staging area để tiếp tục rebase.
Đối với các file bị deleted by us hoặc deleted by them, hãy chọn giữ hay xóa file:
# Nếu muốn GIỮ lại file đó
git add <filename(s)>
# Nếu muốn XÓA bỏ file đó
git rm <filename(s)>
Đối với các file both modified (file bạn vừa sửa thủ công ở bước 2), luôn sử dụng lệnh:
git add <filename(s)>
Để chắc chắn rằng mọi xung đột đã được xử lý xong, hãy dùng lệnh git status để kiểm tra lại:
Output:
interactive rebase in progress; onto abc1234
Last command done (1 command done):
pick def5678 Add new feature
No commands remaining.
You are currently rebasing branch 'feature' on 'abc1234'.
All conflicts fixed but you are still rebasing.
(use "git rebase --continue" to continue rebasing)
Nếu bạn thấy dòng chữ: "All conflicts fixed but you are still rebasing" (Mọi xung đột đã sửa xong nhưng bạn vẫn đang trong quá trình rebase) thì tức là bạn đã hoàn tất việc giải quyết xung đột cho commit hiện tại. Git gợi ý bước tiếp theo cho bạn là tiếp tục rebase.
Sau khi đã giải quyết xong conflict cho commit hiện tại, bạn cần tiếp tục quá trình rebase bằng lệnh:
git rebase --continue
Lệnh này sẽ:
Rebase có thể gặp nhiều conflict ở nhiều commit khác nhau. Bạn cần giải quyết từng conflict một cho đến khi tất cả các commit đã được rebase thành công.
Khi rebase hoàn tất, bạn sẽ thấy thông báo:
Successfully rebased and updated refs/heads/feature.
Mặc dù quy trình giải quyết conflict khi rebase và merge có nhiều điểm tương đồng, nhưng có một số khác biệt quan trọng:
| Đặc điểm | Merge Conflict | Rebase Conflict |
|---|---|---|
| Số lần xảy ra | Một lần duy nhất | Có thể nhiều lần (mỗi commit một lần) |
| Lệnh hủy bỏ | git merge --abort | git rebase --abort |
| Lệnh hoàn tất | git commit | git rebase --continue |
| Conflict markers | <<<<<<< HEAD vs >>>>>>> branch-name | <<<<<<< HEAD vs >>>>>>> commit-hash... |
| Trạng thái | "You are still merging" | "You are currently rebasing" |
Các bước để giải quyết rebase conflict trong Git gồm:
git statusgit add hoặc git rmgit status để đảm bảo "All conflicts fixed"git rebase --continue (lặp lại cho đến khi hoàn tất)Tiếp theo hãy tìm hiểu bài so sánh giữa Rebase và Merge trong bài học tiếp theo nhé!
Tiếp theo: So sánh Rebase và Merge