Giải quyết Git Merge Conflict: Quy trình 3 bước xử lý xung đột tận gốc mà không làm mất code
Hướng dẫn giải quyết Git merge conflict theo quy trình 3 bước: bảo toàn trạng thái, xử lý từng xung đột, kiểm tra và hoàn tất merge an toàn, kèm lỗi thường gặp.
ShanverseCập nhật 11 phút đọc— lượt xemĐang tải lượt xem
Git
Developer Tools
Xung đột thường xuất hiện khi hai branch thay đổi cùng một vùng code, một bên xóa file trong khi bên kia chỉnh sửa, hoặc cấu trúc file đã thay đổi quá nhiều. Điều nguy hiểm không phải conflict, mà là xử lý vội bằng cách chọn toàn bộ một phía, xóa marker máy móc hoặc chạy lệnh phá hủy khi chưa tạo đường lui.
Bài này sử dụng quy trình ba bước:
Dừng lại và bảo toàn trạng thái.
Hiểu rồi giải quyết từng conflict.
Kiểm tra, hoàn tất và xác minh lịch sử.
Merge conflict xảy ra khi nào?
Ví dụ, main và feature/login cùng phát triển từ commit B:
Nếu
Bình luận
D
và
E
sửa cùng một vùng, khi merge:
Git có thể dừng lại và yêu cầu bạn quyết định nội dung cuối cùng.
Trước khi merge: giảm rủi ro từ đầu
Một quy trình an toàn bắt đầu trước khi conflict xuất hiện.
Đảm bảo working tree sạch
Nếu đang có thay đổi dở dang, commit chúng vào branch phù hợp hoặc stash:
Cập nhật thông tin remote
Tạo điểm khôi phục khi merge phức tạp
Branch backup chỉ là một con trỏ nhẹ, nhưng giúp bạn quay lại commit trước merge dễ dàng.
Hiểu hướng merge
Ở đây:
main là branch đang nhận thay đổi.
feature/login là branch được đưa vào.
HEAD đại diện cho phía main trong merge thông thường.
Bước 1 — Dừng lại, đọc trạng thái và bảo toàn code
Khi Git báo conflict, đừng chạy ngay git reset --hard hoặc xóa file. Bắt đầu bằng:
Liệt kê các file chưa được merge:
Xem phần conflict:
Kiểm tra loại thao tác đang diễn ra:
Git sẽ cho biết bạn đang merge, rebase, cherry-pick hay revert. Lệnh hoàn tất và ý nghĩa ours/theirs có thể khác theo thao tác.
Những việc không nên làm
Không dùng git reset --hard khi chưa hiểu dữ liệu nào sẽ bị bỏ.
Không xóa toàn bộ file chỉ để marker biến mất.
Không chọn “Accept Current” hoặc “Accept Incoming” cho tất cả file theo phản xạ.
Không tạo thêm thay đổi không liên quan trong lúc đang giải quyết conflict.
Không force push trước khi kiểm tra lịch sử.
Nếu muốn quay lại trước merge
Với merge đang diễn ra:
Lệnh này cố gắng khôi phục trạng thái trước khi merge bắt đầu.
Với rebase:
Với cherry-pick:
Bước 2 — Hiểu và giải quyết từng conflict
Đọc conflict marker
Một conflict nội dung thường có dạng:
Ý nghĩa trong merge thông thường:
Phần giữa <<<<<<< HEAD và ======= đến từ branch hiện tại.
Phần giữa ======= và >>>>>>> feature/login đến từ branch được merge.
Marker chỉ là ký hiệu tạm thời, không phải code hợp lệ cần giữ lại.
Kết quả cuối cùng có thể chọn một phía:
Hoặc kết hợp ý định của cả hai:
Điều quan trọng là kết quả đúng về nghiệp vụ, không chỉ hết marker.
Quy trình xử lý một file
Đọc code xung quanh conflict.
Xem commit và Pull Request của cả hai branch.
Xác định mục tiêu của mỗi thay đổi.
Chỉnh file thành phiên bản cuối cùng mong muốn.
Xóa toàn bộ marker.
Chạy formatter hoặc kiểm tra cú pháp.
Stage file để đánh dấu đã giải quyết.
git add trong lúc conflict có nghĩa: tôi đã xác nhận nội dung cuối cùng của file này.
Xem ba phiên bản của file
Git lưu base, ours và theirs trong index khi có conflict:
So sánh ba phiên bản giúp hiểu conflict phức tạp thay vì chỉ nhìn marker.
Chọn toàn bộ một phía
Với merge thông thường:
Hoặc dùng git restore:
Dùng công cụ merge trực quan
Bạn có thể mở mergetool đã cấu hình:
Các editor hiện đại thường hiển thị:
Current change.
Incoming change.
Kết quả merge.
Tùy chọn chọn hoặc kết hợp hai phía.
Dù dùng UI, vẫn cần hiểu ý định code. Nút “Accept Both” chỉ nối nội dung; nó không đảm bảo logic đúng hoặc không bị lặp.
Conflict kiểu modify/delete
Một branch sửa file, branch kia xóa file. git status sẽ mô tả tình huống.
Nếu muốn giữ file và nội dung đã chỉnh:
Nếu quyết định file nên bị xóa:
Hãy kiểm tra xem chức năng đã được chuyển sang file khác hay việc xóa có chủ đích trước khi quyết định.
Conflict do đổi tên
Git có thể nhận diện rename dựa trên độ giống nội dung, nhưng rename đồng thời với sửa lớn có thể gây conflict.
Kiểm tra:
Đảm bảo phiên bản cuối cùng có đúng đường dẫn, import và reference. Sau đó stage đường dẫn cuối:
File nhị phân
Git không thể merge từng dòng của ảnh, font hoặc file nhị phân. Bạn thường phải chọn một phiên bản hoặc tạo lại file cuối cùng.
Sau khi đặt file đúng vào vị trí:
Với asset quan trọng, trao đổi với người tạo hai phiên bản trước khi loại bỏ một phía.
Lockfile conflict
Với package-lock.json, pnpm-lock.yaml hoặc yarn.lock, tránh chỉnh hàng nghìn dòng thủ công nếu có thể.
Quy trình thường an toàn hơn:
Giải quyết package.json trước.
Chọn một base lockfile phù hợp hoặc xóa lockfile đang conflict theo quy ước team.
Chạy đúng package manager để tạo lại lockfile.
Kiểm tra diff và cài đặt sạch.
Stage lockfile mới.
Ví dụ:
Không trộn npm, pnpm và Yarn trong cùng quy trình.
Bước 3 — Kiểm tra, hoàn tất và xác minh
Sau khi xử lý các file, kiểm tra còn conflict không:
Nếu lệnh thứ hai không trả về file, mọi conflict đã được đánh dấu giải quyết.
Kiểm tra marker còn sót
Lưu ý ======= có thể xuất hiện hợp lệ trong một số file, nên hãy đọc kết quả thay vì xóa tự động.
Xem snapshot sắp hoàn tất
Tìm các dấu hiệu:
Logic bị lặp sau “Accept Both”.
Import trùng hoặc thiếu.
Một nhánh thay đổi API nhưng nơi gọi vẫn dùng API cũ.
File bị xóa hoặc rename ngoài ý muốn.
Secret hoặc file generated bị stage nhầm.
Chạy kiểm tra kỹ thuật
Tùy dự án:
Conflict có thể được giải quyết về mặt văn bản nhưng vẫn sai logic hoặc không compile.
Hoàn tất merge
Hoặc:
Git thường chuẩn bị sẵn merge commit message. Có thể bổ sung lý do hoặc quyết định quan trọng nếu conflict phức tạp.
Với rebase:
Với cherry-pick:
Xác minh lịch sử
Đảm bảo:
Merge/rebase đã hoàn tất.
Working tree sạch hoặc chỉ còn thay đổi có chủ đích.
Commit nằm trên đúng branch.
Test đã chạy thành công.
Sau đó mới push:
Quy trình 3 bước rút gọn
Ví dụ thực tế
main có:
Feature branch thêm discount:
Trong khi main thêm quantity:
Chọn “ours” sẽ mất discount. Chọn “theirs” sẽ mất quantity. Kết quả đúng cần kết hợp ý định:
Sau đó cần bổ sung test cho cả quantity và discount. Đây là lý do conflict resolution là công việc thiết kế code, không chỉ là chỉnh văn bản.
Lỗi thường gặp
Đã sửa file nhưng Git vẫn báo unmerged
Bạn chưa stage file:
commit is not possible because you have unmerged files
Liệt kê file còn conflict:
Giải quyết rồi stage từng file.
git merge --abort không khôi phục như mong đợi
Nếu có thay đổi chưa commit từ trước merge, trạng thái có thể phức tạp. Đây là lý do cần working tree sạch và backup branch trước thao tác lớn. Đọc git status, reflog và tránh tiếp tục bằng lệnh phá hủy.
Conflict lặp lại sau mỗi lần rebase
Rebase phát lại từng commit nên cùng vùng có thể conflict nhiều lần. Giải quyết, stage rồi:
Nếu chiến lược không còn hợp lý:
Đã push merge sai
Trên branch dùng chung, tránh reset và force push theo phản xạ. Thường an toàn hơn khi tạo một commit revert phù hợp sau khi kiểm tra merge commit:
-m 1 chọn mainline parent; cần xác minh parent đúng trước khi chạy.
Cách giảm conflict trong team
Pull hoặc fetch thường xuyên.
Giữ branch ngắn hạn.
Chia Pull Request thành thay đổi nhỏ.
Tránh format toàn repository trong cùng commit với thay đổi logic.
Thống nhất owner hoặc phạm vi khi nhiều người sửa file trung tâm.
Merge thay đổi cấu trúc trước rồi cập nhật feature branch.
Viết test để kiểm tra ý định sau khi merge.
Mô tả rõ thay đổi API trong Pull Request.
Checklist không làm mất code
Working tree sạch trước merge/rebase.
Có backup branch khi thao tác phức tạp.
Đã chạy git status trước mọi quyết định.
Hiểu cả current và incoming change.
Không chọn toàn bộ một phía theo phản xạ.
Không dùng reset --hard khi chưa biết dữ liệu bị ảnh hưởng.
Đã stage từng file sau khi giải quyết.
Không còn unmerged file.
Đã đọc git diff --staged.
Lint, test và build thành công.
Lịch sử và branch hiện tại đúng trước khi push.
Tổng kết
Quy trình giải quyết conflict an toàn gồm ba bước:
Quan sát và bảo toàn: đọc trạng thái, xác định thao tác, giữ đường lui.
Hiểu và giải quyết: kết hợp đúng ý định, xóa marker, stage từng file.
Kiểm tra và hoàn tất: tìm conflict còn sót, review staged diff, chạy test rồi hoàn tất merge.
Hướng dẫn Git Aliases và .gitconfig thực chiến: alias an toàn, log đẹp, cấu hình pull/push/rebase, includeIf cho tài khoản work/personal, bảo mật và chia sẻ dotfiles.
Phân tích Gitflow vs GitHub Flow vs Trunk-Based Development: cấu trúc branch, ưu nhược điểm, điều kiện áp dụng, ma trận quyết định và lộ trình chuyển đổi cho từng loại dự án.
Hướng dẫn git worktree từ cơ bản đến thực tế: tạo nhiều working tree, làm feature và hotfix song song, review PR, quản lý list/remove/prune/lock/repair và tránh lỗi phổ biến.