Series Git CLI Thực chiến #5: "Ác mộng" Merge Conflict và Tuyệt kỹ Cấp cứu git stash
1. Merge Conflict sinh ra như thế nào?
Hãy đưa vào một kịch bản thực tế khi phát triển hệ thống AFC.
Anh em đang làm việc trên nhánh feature/vitess-sync. Anh em mở file transaction.go ra và sửa lại dòng struct định nghĩa dữ liệu để tối ưu hóa việc lưu xuống Database. Cùng lúc đó, một đồng nghiệp làm tính năng đẩy message qua broker lại làm việc trên nhánh feature/kafka-producer. Người này cũng mở đúng file transaction.go và sửa lại chính cái struct đó để thêm trường dữ liệu cho Kafka.
Đồng nghiệp merge nhánh của họ vào main trước (thành công). Khi anh em gõ lệnh git merge feature/vitess-sync vào main (hoặc git pull), Git lập tức dội một gáo nước lạnh:
Auto-merging transaction.go
CONFLICT (content): Merge conflict in transaction.go
Automatic merge failed; fix conflicts and then commit the result.
Đừng hoảng loạn! Git chỉ đang nói: "Tôi thấy hai người cùng sửa một chỗ. Tôi không dám tự ý quyết định. Anh hãy vào file đó xem và chọn đi!"
2. Đọc hiểu "Mật ngữ" của Xung đột
Anh em mở file transaction.go lên, lúc này anh em sẽ thấy Git đã tự động chèn thêm những ký tự rất kỳ lạ vào đoạn code bị tranh chấp. Nó trông như thế này:
type Transaction struct {
ID string
<<<<<<< HEAD
// Code hiện tại trên nhánh main (của người đồng nghiệp đã merge trước)
KafkaTopic string
MessageKey string
=======
// Code của anh em mang từ nhánh feature/vitess-sync vào
VitessShardID string
IsSynced bool
>>>>>>> feature/vitess-sync
}
Cách giải mã:
- <<<<<<< HEAD: Bắt đầu đoạn code đang tồn tại sẵn ở nhánh nhận (thường là main).
- =======: Đường ranh giới phân chia giữa code cũ và code mới.
-
feature/vitess-sync: Kết thúc đoạn code mà anh em đang cố gắng gộp vào.
3. Hóa giải Xung đột (Resolve Conflict)
Để sửa lỗi, anh em chỉ cần xóa bỏ các dòng ký tự đánh dấu của Git (<<<<, ====, >>>>) và tự tay chỉnh sửa lại đoạn code sao cho logic đúng nhất.
Trong trường hợp hệ thống AFC này, struct Transaction cần cả thông tin của Kafka lẫn Vitess, nên anh em sẽ gom code của cả hai người lại:
type Transaction struct {
ID string
KafkaTopic string
MessageKey string
VitessShardID string
IsSynced bool
}
Sau khi đã sửa xong và lưu file, anh em phải báo cho Git biết là "Tôi đã giải quyết xong cuộc chiến này rồi". Quá trình này y hệt như việc commit một tính năng mới:
# 1. Đưa file đã gỡ rối vào Staging Area
git add transaction.go
# 2. Niêm phong lại bằng một Merge Commit
git commit -m "Merge nhánh feature/vitess-sync, giải quyết xung đột struct Transaction"
Bùm! Anh em đã hóa giải thành công ác mộng lớn nhất của dân lập trình.
4. Tuyệt kỹ git stash: Phanh gấp trên đường ray
Bây giờ là một kịch bản đau tim khác. Anh em đang code dở tay tính năng chuẩn hóa địa chỉ, file code đang dang dở, chưa chạy được, lỗi đỏ lòm. Bất ngờ Leader chạy tới báo: "Bug nghiêm trọng trên Production! Em phải đổi sang nhánh main để hotfix ngay lập tức!"
Anh em gõ git checkout main. Git chặn lại ngay:
error: Your local changes to the following files would be overwritten by checkout...
Anh em không thể chuyển nhánh vì code đang làm dở sẽ bị ghi đè. Nhưng anh em cũng tuyệt đối không được commit một đống code lỗi mớ ba mớ bảy vào lịch sử. Phải làm sao?
Hãy dùng cái túi thần kỳ: git stash (Cất giấu tạm thời).
# Nhét toàn bộ code đang làm dở vào túi, trả lại Xưởng mộc sạch sẽ như cũ
git stash
Ngay lập tức, file code dang dở biến mất, Xưởng mộc sạch bong. Anh em thoải mái git checkout main, tạo nhánh hotfix, sửa bug, gộp vào main, sau đó deploy.
Sau khi thế giới đã bình yên, anh em quay lại nhánh tính năng của mình:
git checkout feature/normalize-address
Và lấy đoạn code làm dở trong túi ra để code tiếp:
git stash pop
(Lệnh pop vừa lôi code ra khỏi túi, vừa xóa luôn cái túi đó cho sạch bộ nhớ).
Mọi thứ lại hiện ra y nguyên như lúc anh em bị gián đoạn. Đây là lệnh mà bất kỳ Kỹ sư hệ thống nào cũng phải dùng hằng tuần!
Tổng kết Bài 5
Xử lý Conflict bằng tay rèn luyện cho anh em sự cẩn thận và khả năng đọc hiểu logic của đồng nghiệp. Còn git stash giúp anh em giữ được sự linh hoạt, xoay sở nhanh chóng giữa các tác vụ khẩn cấp mà không làm bẩn lịch sử commit.
Tới đây, anh em đã sở hữu 90% bộ kỹ năng Git CLI cần thiết cho công việc hàng ngày rồi. Ở Bài 6 — trạm cuối của Series Git, anh em muốn chúng ta đi sâu vào kỹ năng bới móc lịch sử với git log nâng cao và git bisect (Tìm thủ phạm gây bug), hay muốn tìm hiểu về git rebase (Nghệ thuật viết lại lịch sử)?
All rights reserved