Dùng git merge-tree: Check nhanh conflict chỉ trong 1 giây không cần chuyển branch hay stash

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Thử nghiệm nhanh: Bắt conflict trong 30 giây

Tưởng tượng bạn đang sửa dở 10 file ở nhánh feature/login, code chưa xong nên chưa thể commit. Bất ngờ, team lead báo vừa merge một PR lớn vào main và bảo bạn rebase kiểm tra xem có đụng độ không.

Thói quen cũ của nhiều người là git stash, switch sang main, pull về rồi thử merge. Cách này vừa tốn thao tác, vừa dễ mất code nếu stash pop lỗi. Với Git 2.36 trở lên, bạn có thể kiểm tra trực tiếp ngay trên bộ nhớ đệm mà không đụng đến một file nào trên ổ đĩa:

# Lấy commit mới nhất từ remote về database cục bộ
git fetch origin

# Kiểm tra xung đột giữa nhánh hiện tại và origin/main
git merge-tree --write-tree HEAD origin/main

Git sẽ xử lý trên RAM và trả kết quả sau khoảng 30–50 mili-giây:

  • Trường hợp 1 – Merge sạch sẽ: Git trả về mã thoát (exit code) 0 kèm duy nhất một mã băm Tree OID 40 ký tự:
4b825dc642cb6eb9a060e54bf8d69288fbee4904
  • Trường hợp 2 – Có xung đột: Git in ra mã cây tạm thời, danh sách file lỗi và kết thúc với exit code 1:
Auto-merging src/auth.js
CONFLICT (content): Merge conflict in src/auth.js

Nếu dự án có hàng nghìn file và bạn chỉ muốn lọc nhanh tên các file xung đột, hãy thêm cờ --name-only:

git merge-tree --write-tree --name-only HEAD origin/main

Bản chất kỹ thuật: Tại sao cách này tối ưu hơn?

Cái giá của quy trình merge thử truyền thống

Lệnh git merge thông thường bắt buộc phải cập nhật cả Staging Area (Index) lẫn Working Tree. Nếu thư mục đang có file sửa dở, Git sẽ lập tức chặn lại để tránh ghi đè dữ liệu. Để lách qua, lập trình viên thường làm một vòng:

git stash
git merge --no-commit --no-ff origin/main
# Xem conflict...
git merge --abort
git stash pop

Chuỗi lệnh này kéo theo 3 phiền toái lớn:

  1. Ghi đè timestamp file (mtime): Các công cụ build như Vite, Next.js hay Webpack tưởng file thay đổi nên sẽ trigger rebuild toàn bộ từ đầu. Với dự án lớn 3.000–5.000 module, bạn mất toi 15–30 giây chỉ để chờ compile lại.
  2. Kích hoạt Git hooks ngoài ý muốn: Các script pre-merge hay post-checkout nặng nề sẽ tự động chạy ngầm.
  3. Rủi ro đè dữ liệu: Quá trình hủy merge nếu sót file sẽ khiến bước git stash pop bị conflict chéo, rất dễ mất các đoạn code nháp chưa lưu.

Sức mạnh từ tầng lệnh Plumbing

Trong kiến trúc Git:

  • Porcelain: Là các lệnh bậc cao thân thiện như checkout, commit, merge. Chúng luôn can thiệp trực tiếp vào file hệ thống.
  • Plumbing: Là các lệnh bậc thấp phục vụ lõi hệ thống như cat-file, commit-tree, merge-tree.

Lệnh git merge-tree chạy ở tầng plumbing. Thuật toán 3-way merge được tính toán trực tiếp giữa các commit tree object nằm trong thư mục .git/objects. Mọi dữ liệu chỉ nằm trên RAM và object database của Git, ổ đĩa không phải ghi thêm bất kỳ file làm việc nào.

Cú pháp mới (Git 2.36+) khác gì cú pháp cũ?

Trước bản 2.36 ra mắt năm 2022, git merge-tree khá bất tiện vì bắt lập trình viên tự tìm commit tổ tiên chung (merge base):

# Cú pháp cũ (rườm rà, format khó đọc):
git merge-tree $(git merge-base branchA branchB) branchA branchB

# Cú pháp hiện đại từ Git 2.36 (khuyên dùng):
git merge-tree --write-tree branchA branchB

Cờ --write-tree biến lệnh này thành bản sao hoàn hảo của git merge về mặt logic, tự động xác định base và xử lý đổi tên file (rename detection) chính xác 100%.

Ứng dụng thực tế trong quy trình phát triển

1. Script kiểm tra trước khi bấm tạo Pull Request

Bạn có thể nhúng đoạn bash script này vào terminal để cảnh báo sớm trước khi mở PR lên GitHub/GitLab:

#!/usr/bin/env bash
TARGET="origin/main"
CURRENT=$(git rev-parse --abbrev-ref HEAD)

echo "Đang quét conflict giữa $CURRENT và $TARGET..."

OUTPUT=$(git merge-tree --write-tree HEAD "$TARGET" 2>&1)
STATUS=$?

if [ $STATUS -eq 0 ]; then
    echo "✅ An toàn: Nhánh sạch sẽ, có thể merge thẳng!"
else
    echo "❌ Cảnh báo: Phát hiện xung đột tại các file:"
    echo "$OUTPUT" | grep -E "(CONFLICT|Auto-merging)"
    exit 1
fi

2. Tối ưu bot tự động trong CI/CD

Trên các hệ thống CI/CD như GitHub Actions hay GitLab CI, việc kiểm tra mergeability của hàng chục PR cùng lúc rất tốn tài nguyên nếu phải clone toàn bộ working tree. Sử dụng git merge-tree trên một bare repository giúp server kiểm tra trạng thái của PR chỉ mất vài chục mili-giây, từ đó tự động gán nhãn needs-rebase cho tác giả mà không cần checkout code.

Mẹo sử dụng hàng ngày

Đặt Git Alias cho ngắn gọn

Chỉ cần cấu hình một lần trong ~/.gitconfig:

git config --global alias.dry-merge 'merge-tree --write-tree'

Từ nay bạn chỉ cần gõ ngắn gọn:

git dry-merge HEAD origin/main

Hoạt động offline mượt mà

Chỉ cần bạn đã git fetch trước đó, lệnh sẽ chạy hoàn toàn offline. Tốc độ kiểm tra gần như tức thì kể cả trên các repo khổng lồ như Chromium hay Linux kernel.

Quy ước mã trả về (Exit Codes) khi viết script

  • 0: Merge sạch, không có bất kỳ đụng độ nào.
  • 1: Có conflict nội dung hoặc conflict đổi tên file.
  • Khác 0 và 1: Lỗi cú pháp hoặc tên nhánh không tồn tại trong repository.
Share: