Thách thức khi Xử lý Merge Conflict trong Dự án Enterprise

Trong các hệ thống phần mềm quy mô lớn với hàng chục Developer cùng làm việc song song trên nhiều nhánh tính năng, việc gặp xung đột mã nguồn là điều khó tránh khỏi. Tình huống trở nên phức tạp khi các kỹ sư phải liên tục rebase nhánh tính năng của mình với nhánh chính để cập nhật thay đổi mới nhất. Mỗi lần rebase qua nhiều commit, họ thường phải giải quyết lặp đi lặp lại đúng những đoạn xung đột đã từng sửa trước đó. Điều này không chỉ gây lãng phí thời gian mà còn gia tăng nguy cơ rủi ro do thao tác thủ công sai sót.

Ngoài ra, đối với các tệp tin cấu hình đặc thù như tệp khóa thư viện lockfile hay các dữ liệu dạng cấu trúc JSON, thuật toán hợp nhất mặc định của Git thường không đủ thông minh để tự động xử lý. Bài viết này sẽ đi sâu vào hai kỹ thuật nâng cao trong Git giúp tự động hóa quá trình giải quyết xung đột mã nguồn: cơ chế Git Rerere và việc xây dựng Custom Merge Drivers.

Git Rerere: Cơ chế Tự động hóa Ghi nhớ và Giải quyết Xung đột

Git Rerere là viết tắt của Reuse Recorded Resolution. Đây là một tính năng ẩn cực kỳ mạnh mẽ trong Git, cho phép hệ thống ghi nhớ cách bạn đã giải quyết một đoạn xung đột mã nguồn trong quá khứ. Khi đoạn xung đột tương tự xuất hiện lại trong tương lai, Git Rerere sẽ tự động áp dụng lại phương án giải quyết đó mà không cần sự can thiệp thủ công từ Developer.

Cách Thức Hoạt động của Git Rerere

Khi tính năng này được kích hoạt, Git sẽ thực hiện hai bước tự động mỗi khi xảy ra xung đột trong quá trình merge hoặc rebase:

  • Ghi lại hình ảnh xung đột: Git chụp lại trạng thái của đoạn mã trước khi giải quyết xung đột và lưu trữ trong thư mục ẩn của kho chứa.
  • Ghi lại kết quả giải quyết: Sau khi bạn hoàn tất việc sửa xung đột và tạo commit, Git lưu lại phiên bản mã nguồn đã được sửa thành công.

Khi gặp lại đúng đoạn xung đột đó trong một thao tác rebase hoặc merge khác, Git Rerere sẽ so sánh và tự động chèn kết quả đã ghi nhớ vào tệp tin.

Kích hoạt và Cấu hình Git Rerere

Bạn có thể bật tính năng này trên toàn hệ thống hoặc chỉ áp dụng riêng cho một kho chứa cụ thể bằng các câu lệnh trong Terminal.

# Kich hoat Git Rerere tren toan he thong
git config --global rerere.enabled true

# Khai bao them cau hinh tu dong add cac tep tin da duoc Rerere xu ly xong
git config --global rerere.autoupdate true

Kịch bản Thực tế Sử dụng Git Rerere trong Quá trình Rebase

Hãy xét kịch bản một nhánh tính năng kéo dài nhiều ngày và cần rebase liên tục vào nhánh develop. Giả sử quá trình rebase gặp xung đột tại một commit cũ. Dưới đây là luồng xử lý thực tế với Git Rerere:

# Thuc hien rebase nhanh tinh nang vao develop
git checkout feature/payment-v2
git rebase develop

# Git thong bao xung doat tai file src/config/payment.js
# Rerere ghi nhan trang thai xung doat: Recorded preimage for 'src/config/payment.js'

# Developer chinh sua file va giai quyet xung doat thu cong
vim src/config/payment.js

# Danh dau file da xu ly va tiep tuc rebase
git add src/config/payment.js
# Rerere ghi nhan ket qua giai quyet: Recorded resolution for 'src/config/payment.js'
git rebase --continue

Nếu về sau bạn cần hủy bỏ đợt rebase này và thực hiện lại, hoặc thực hiện gộp nhánh vào một môi trường khác có cùng tập hợp commit, Git Rerere sẽ tự động can thiệp:

# Ngay khi xung doat xuat hien lai, Git Rerere se tu dong kich hoat
# Thong bao hien thi: Resolved 'src/config/payment.js' using previous resolution.

# Kiem tra trang thai tep tin
git status

Nhờ cơ chế này, Developer không còn phải căng thẳng nhớ lại cách mình đã giải quyết xung đột ở những lần rebase trước đó.

Xây dựng Custom Merge Driver cho các Tệp tin Cấu hình Đặc thù

Mặc dù Git xử lý rất tốt các tệp tin mã nguồn văn bản thông thường bằng thuật toán hợp nhất ba bên, nó lại gặp khó khăn lớn đối với các tệp tin chứa dữ liệu có cấu trúc như JSON hay các tệp tin khóa thư viện như package-lock.json và yarn.lock. Các tệp tin này thường xuyên bị xung đột khi nhiều Developer cùng cài đặt thêm thư viện mới.

Để giải quyết triệt để vấn đề này, Git cho phép chúng ta định nghĩa các bộ xử lý hợp nhất tùy chỉnh cho từng loại tệp tin cụ thể thông qua Custom Merge Drivers.

Cấu trúc Cần thiết cho Một Custom Merge Driver

Một bộ xử lý hợp nhất tùy chỉnh cần nhận vào năm tham số từ Git thông qua các biến vị trí:

  • %O: Phiên bản gốc của tệp tin trước khi phân nhánh.
  • %A: Phiên bản tệp tin ở nhánh hiện tại.
  • %B: Phiên bản tệp tin ở nhánh đang được gộp vào.
  • %L: Giới hạn đánh dấu xung đột.
  • %P: Đường dẫn thực tế của tệp tin trong kho chứa.

Thực hành Xây dựng Driver Hợp nhất Tự động cho Tệp tin JSON

Chúng ta sẽ viết một script đơn giản bằng Node.js để tự động hợp nhất hai tệp tin JSON bằng cách ưu tiên giữ lại các khóa dữ liệu từ cả hai nhánh thay vì báo lỗi xung đột.

Tạo tệp tin script có tên json-merge-driver.js với nội dung như sau:

const fs = require('fs');

// Lay duong dan tep tin tu tham so truyen vao cua Git
const ancestorPath = process.argv[2];
const currentPath = process.argv[3];
const otherPath = process.argv[4];

try {
  const currentData = JSON.parse(fs.readFileSync(currentPath, 'utf8'));
  const otherData = JSON.parse(fs.readFileSync(otherPath, 'utf8'));

  // Thuc hien hop nhat hai doi tuong JSON
  const mergedData = { ...currentData, ...otherData };

  // Ghi ket qua hoan tat tro lai tep tin o nhanh hien tai
  fs.writeFileSync(currentPath, JSON.stringify(mergedData, null, 2), 'utf8');
  
  // Tra ve ma loi 0 de bao cho Git biet hop nhat thanh cong
  process.exit(0);
} catch (error) {
  console.error('Loi khi hop nhat JSON tu dong:', error.message);
  // Tra ve ma loi khac 0 de Git chuyen sang cơ che bao xung doat thu cong
  process.exit(1);
}

Cấu hình Git để Sử dụng Custom Merge Driver

Sau khi chuẩn bị script xử lý, bạn cần đăng ký driver này vào hệ thống thông qua tệp tin .gitconfig hoặc tệp cấu hình của kho chứa .git/config:

# Đang ky merge driver trong cau hinh Git
git config merge.json-driver.name "Custom Automatic JSON Merge Driver"
git config merge.json-driver.driver "node ./scripts/json-merge-driver.js %O %A %B"

Bước tiếp theo là liên kết driver vừa tạo với các loại tệp tin mong muốn thông qua tệp tin .gitattributes nằm ở thư mục gốc của dự án:

# Them quy tac dinh dang trong .gitattributes
*.json merge=json-driver
app-settings.json merge=json-driver

Từ thời điểm này, mỗi khi xảy ra thao tác gộp nhánh có liên quan đến các tệp tin có đuôi .json, Git sẽ tự động gọi script Node.js của bạn để xử lý thay vì đưa ra các ký tự đánh dấu xung đột tiêu chuẩn.

Chiến lược Tích hợp và Best Practices cho Đội ngũ Developer

Để áp dụng thành công các kỹ thuật xử lý xung đột nâng cao trong môi trường làm việc thực tế, đội ngũ phát triển nên tuân thủ các nguyên tắc sau:

Kết hợp Git Rerere với Quy trình Git Flow Chuẩn mực

Git Rerere phát huy tác dụng tối đa khi dự án duy trì các nhánh có thời gian tồn tại dài như release hoặc hotfix. Khi cần đưa các bản sửa lỗi từ nhánh hotfix về lại nhánh develop và main đồng thời, các đoạn xung đột lặp lại sẽ được giải quyết tức thì.

Quản lý Bộ nhớ Đệm của Rerere

Dữ liệu ghi nhớ của Git Rerere được lưu tại thư mục .git/rr-cache. Nếu bạn lỡ giải quyết sai một đoạn xung đột và Git Rerere liên tục áp dụng lại kết quả sai đó, bạn có thể dễ dàng xóa bản ghi lỗi bằng lệnh sau:

# Kiem tra cac ban ghi xung doat hien co
git rerere status

# Xoa ban ghi giai quyet xung doat cua mot tep tin cu the
git rerere forget path/to/file.js

Chia sẻ Custom Merge Drivers giữa các Thành viên trong Đội ngũ

Do tệp tin .git/config mang tính chất cục bộ trên máy cá nhân, bạn nên đóng gói các script driver vào dự án và chia sẻ tệp tin .gitattributes lên kho chứa chung. Đồng thời, có thể viết các đoạn script tự động hóa khởi tạo môi trường để mọi Developer trong đội ngũ đều sử dụng chung một tập hợp cấu hình nhất quán.

Kết luận

Thành thạo các kỹ thuật quản lý nâng cao như Git Rerere và Custom Merge Drivers giúp đội ngũ kỹ sư tiết kiệm hàng giờ đồng hồ xử lý thủ công, loại bỏ các sai sót do yếu tố con người và đảm bảo lịch sử mã nguồn luôn trong trạng thái ổn định. Việc chủ động xây dựng quy trình quản lý mã nguồn chuyên nghiệp là bước đệm quan trọng đối với bất kỳ Developer nào muốn phát triển lên các vị trí quản lý kỹ thuật hoặc Tech Lead trong tương lai. Tham khảo khóa học "Khóa học Git & Git Flow thực chiến" tại đây.