Merge — nó là gì, cách merge hoạt động và các chiến lược hợp nhất

Tác giả: IT Sectr Đã đăng: 2026-08-01 Thời gian đọc: 9 phút

Merge là một thao tác hợp nhất nhánh trong Git kết hợp các thay đổi từ hai dòng phát triển khác nhau vào một nhánh đích. Không giống như rebase, merge giữ nguyên toàn bộ lịch sử phân nhánh bằng cách tạo một commit merge đặc biệt với hai cha. Theo tài liệu chính thức của Git (2026), merge là cách an toàn nhất để hợp nhất các nhánh vì nó không ghi đè lịch sử và cho phép theo dõi thời điểm cũng như nhánh nào đã được hợp nhất. Đây là lựa chọn tiêu chuẩn để hợp nhất trong các nhánh công khai như main, develop và release.

Những điểm chính

  • Merge — hợp nhất nhánh bằng cách tạo commit merge giữ nguyên lịch sử của cả hai nhánh.
  • Commit merge — một commit đặc biệt với hai cha ghi lại sự kiện hợp nhất.
  • Chiến lược hợp nhất — recursive, octopus, ours, squash — mỗi loại phù hợp với các kịch bản khác nhau.
  • Xung đột — xảy ra khi cùng một dòng được thay đổi ở cả hai nhánh và cần giải quyết thủ công.
  • An toàn — merge không sửa đổi các commit hiện có, do đó an toàn cho các nhánh công khai.

Merge trong Git là gì

Merge là lệnh git merge kết hợp các thay đổi từ nhánh được chỉ định vào nhánh hiện tại. Git tìm tổ tiên chung (commit cơ sở), tính toán diff của mỗi nhánh so với tổ tiên và tạo một commit merge chứa tập hợp các thay đổi đã kết hợp. Kết quả là nhánh đích nhận được tất cả các thay đổi từ nhánh được hợp nhất.

Cú pháp: khi đang ở nhánh đích (ví dụ: main), thực hiện git merge feature. Git tự động tạo một commit merge nếu không có xung đột. Thông báo commit merge mặc định là: “Merge branch 'feature' into main”. Bạn có thể thay đổi thông báo bằng cờ -m hoặc chỉnh sửa trong trình soạn thảo đã mở.

Merge là một thao tác không phá hủy. Không giống như rebase, merge không chạm vào các commit hiện có: chúng giữ nguyên hash, tác giả và ngày tháng. Điều này làm cho merge trở thành cách duy nhất an toàn để hợp nhất các nhánh mà nhiều nhà phát triển đang làm việc đồng thời. Nếu có sự cố, merge có thể bị hủy bằng git merge --abort.

bash
# Chuyển sang nhánh đích
git checkout main

# Hợp nhất nhánh tính năng
git merge feature

# Kết quả — commit merge với hai cha
git log --oneline --graph

# Merge với thông báo tùy chỉnh
git merge feature -m "feat: integrate authentication module"

Các loại merge: regular, squash, fast-forward

Git hỗ trợ ba chế độ hợp nhất được chọn dựa trên kết quả mong muốn. Merge thông thường (mặc định) tạo một commit merge. Squash merge kết hợp tất cả các commit của nhánh tính năng thành một. Fast-forward di chuyển con trỏ nhánh mà không tạo commit, nếu có thể. Việc chọn chế độ phụ thuộc vào quy trình làm việc của nhóm và quy tắc lịch sử.

Merge thông thường (--no-ff) — tạo một commit merge ngay cả khi merge có thể được thực hiện dưới dạng fast-forward. Được khuyến nghị cho nhánh main: commit merge đánh dấu rõ ràng điểm tích hợp tính năng và cho phép dễ dàng hoàn tác tất cả các thay đổi của nhánh tính năng chỉ với một lần revert commit merge. GitHub sử dụng chế độ này theo mặc định khi hợp nhất PR qua nút Merge.

Squash merge (--squash) — thu thập tất cả các commit của nhánh tính năng thành một commit duy nhất trong nhánh đích. Hữu ích khi lịch sử nháp của nhánh tính năng không nên làm ô nhiễm main. Nhược điểm: mất kết nối với các commit gốc — không thể thấy tính năng đã được phát triển từng bước như thế nào. GitHub sử dụng chế độ này khi chọn “Squash and merge” trong PR.

Fast-forward (--ff) — nếu nhánh đích không có commit mới kể từ khi nhánh tính năng tách ra, Git chỉ đơn giản di chuyển con trỏ về phía trước mà không tạo commit merge. Lịch sử vẫn tuyến tính. Cờ --no-ff buộc tạo commit merge, trong khi --ff-only sẽ báo lỗi nếu fast-forward không khả thi.

bash
# Buộc tạo commit merge (khuyến nghị cho main)
git merge --no-ff feature

# Squash merge — tất cả commit thành một
git merge --squash feature
git commit -m "feat: add authentication"

# Fast-forward chỉ nếu có thể
git merge --ff-only feature

# Hủy bỏ merge xung đột
git merge --abort

Chiến lược hợp nhất Git

Chiến lược hợp nhất xác định thuật toán mà Git sử dụng để kết hợp các thay đổi. Mỗi chiến lược phù hợp với các kịch bản khác nhau. Git tự động chọn chiến lược thích hợp, nhưng nhà phát triển có thể chỉ định rõ ràng bằng cờ --strategy. Hiểu các chiến lược giúp dự đoán hành vi của Git trong các lần hợp nhất phức tạp.

Recursive — chiến lược mặc định để hợp nhất hai nhánh. Git tìm tổ tiên chung, tính toán các thay đổi trong mỗi nhánh và hợp nhất chúng. Nếu tìm thấy tổ tiên chung, recursive xử lý chính xác việc đổi tên và thêm tệp. Khi xung đột, recursive có thể sử dụng các tùy chọn bổ sung: ours (tự động chọn phiên bản của chúng ta) và theirs (chọn phiên bản của họ).

Octopus — để hợp nhất nhiều hơn hai nhánh cùng lúc: git merge feature1 feature2 feature3. Octopus không hỗ trợ giải quyết xung đột — tất cả các xung đột phải được giải quyết trước khi gọi lệnh. Nó hiếm khi được sử dụng, chủ yếu để hợp nhất nhiều nhánh độc lập được đảm bảo không xung đột (ví dụ: các mô-đun khác nhau).

Chiến lượcSố lượng nhánhGiải quyết xung đột
Recursive2Tự động + tùy chọn ours/theirs
Octopus3+Không — tất cả xung đột phải được giải quyết trước
OursBất kỳLuôn chọn phiên bản của chúng ta, bỏ qua thay đổi bên ngoài
Subtree2Dành cho hợp nhất cây con (subtree merge)

Ours — một chiến lược đặc biệt hoàn toàn bỏ qua các thay đổi từ nhánh được hợp nhất và giữ nguyên nội dung hiện tại của nhánh đích. Một commit merge được tạo ra, nhưng nội dung không thay đổi. Hữu ích khi bạn cần ghi lại sự kiện hợp nhất trong lịch sử nhưng thực tế từ chối tất cả các thay đổi từ nhánh khác.

Giải quyết xung đột merge

Xung đột merge xảy ra khi cùng một dòng của tệp đã được thay đổi khác nhau ở cả hai nhánh. Git không thể tự động xác định phiên bản nào đúng và tạm dừng merge. Xung đột cũng có thể phát sinh khi một tệp được đổi tên trong một nhánh và được sửa đổi trong nhánh khác, hoặc khi cùng một tệp bị xóa và sửa đổi đồng thời.

Quy trình giải quyết: Git đánh dấu các tệp xung đột bằng các điểm đánh dấu. Tệp hiển thị các phần có <<<<<<< HEAD (phiên bản của chúng ta), ======= (dấu phân cách) và >>>>>>> feature (phiên bản của họ). Nhà phát triển chỉnh sửa thủ công phần xung đột, chọn các dòng mong muốn từ cả hai phiên bản, xóa các điểm đánh dấu, lưu tệp và thêm nó vào chỉ mục bằng git add.

Để giải quyết xung đột trực quan, Git hỗ trợ mergetool — một công cụ so sánh bên ngoài. Các mergetool phổ biến: Meld, KDiff3, Beyond Compare, VS Code (trình soạn thảo xung đột tích hợp). Mergetool hiển thị ba bảng: phiên bản của chúng ta, phiên bản của họ và kết quả. Nhà phát triển trực quan chọn các khối mã để đưa vào tệp cuối cùng.

bash
# Bắt đầu merge và phát hiện xung đột
git merge feature
# XUNG ĐỘT (nội dung): Xung đột merge trong src/main.swift

# Kiểm tra tệp xung đột
git status

# Mở mergetool trực quan
git mergetool

# Sau khi giải quyết — add và commit
git add src/main.swift
git commit

# Hủy bỏ merge
git merge --abort

Khi nào chọn merge thay vì rebase

Merge được ưu tiên hơn rebase trong một số tình huống chính. Thứ nhất: khi làm việc với các nhánh công khai mà các nhà phát triển khác có thể truy cập. Merge không ghi đè lịch sử, vì vậy đồng nghiệp có thể đồng bộ hóa một cách an toàn. Rebase trên nhánh công khai tạo ra lịch sử phân kỳ và gây ra xung đột cho tất cả những người đã có các commit cũ.

Tình huống thứ hai: khi hoàn thành nhánh tính năng. Hầu hết các nhóm thích merge (với cờ --no-ff) vào main để ghi lại thời điểm tích hợp tính năng. Điều này đơn giản hóa việc điều hướng lịch sử và cho phép dễ dàng hoàn tác toàn bộ tính năng chỉ với một lần git revert commit merge. GitHub Flow theo mặc định cung cấp ba tùy chọn merge: merge đơn giản, squash merge và rebase merge.

Tình huống thứ ba: khi làm việc với pull request đã được xem xét. GitHub và GitLab cung cấp nút merge với các tùy chọn khác nhau. Merge (Create a merge commit) — lịch sử đầy đủ với commit merge. Squash and merge — lịch sử sạch sẽ không có chi tiết phát triển. Rebase and merge — lịch sử tuyến tính không có commit merge, nhưng có ghi đè commit. Lựa chọn phụ thuộc vào quy tắc của nhóm.

  • Nhánh công khai (main, develop) — chỉ merge, không bao giờ rebase.
  • Hoàn thành PR — merge với --no-ff để đánh dấu điểm tích hợp.
  • Nhánh có commit của người khác — merge không ghi đè công việc của người khác.
  • Trước khi phát hành — merge an toàn hơn vì ít rủi ro hơn.
  • Nhánh chia sẻ — nếu nhiều nhà phát triển làm việc trên một nhánh, merge là bắt buộc.

Thực hành tốt nhất cho hợp nhất nhánh

Quy tắc đầu tiên: luôn ở phiên bản mới nhất của nhánh đích trước khi hợp nhất. Chạy git checkout main && git pull trước khi hợp nhất nhánh tính năng. Điều này giảm thiểu xung đột và đảm bảo commit merge chứa tất cả các thay đổi mới nhất. Nếu nhánh đích đã tiến xa đáng kể, trước tiên hãy chạy git merge main bên trong nhánh tính năng để giải quyết xung đột trong ngữ cảnh của nó.

Quy tắc thứ hai: kiểm tra mã sau khi hợp nhất. Hợp nhất có thể thay đổi hành vi ngay cả khi không có xung đột. Đường ống CI/CD nên chạy kiểm tra trên commit merge trước khi gửi lên sản phẩm. Một số nhóm sử dụng cổng merge (merge gates) — các kiểm tra bắt buộc chặn merge cho đến khi chúng vượt qua.

Quy tắc thứ ba: ghi lại các commit merge. Thông báo tiêu chuẩn “Merge branch 'feature' into main” không hữu ích lắm. Nên thêm mô tả về những gì đã được hợp nhất: “Merge authentication module: login, registration, password recovery”. Điều này đơn giản hóa việc phân tích lịch sử và tìm kiếm hồi quy. Trong các dự án lớn, commit merge được tự động tạo từ tiêu đề PR.

  • Cập nhật — trước khi hợp nhất, đảm bảo nhánh đích đã được cập nhật (git pull).
  • Kiểm tra — CI/CD nên chạy kiểm tra trên commit merge kết quả.
  • Thông báo mô tả — chỉ rõ trong commit merge tính năng nào đã được hợp nhất.
  • Tần suất — hợp nhất các nhánh tính năng càng sớm và càng thường xuyên càng tốt (tối đa một tuần).
  • Hoàn tác — git revert của một commit merge sẽ hoàn tác toàn bộ tính năng.

Các câu hỏi thường gặp

Hợp nhất nhánh trong Git có nghĩa là gì?

Hợp nhất có nghĩa là thực hiện git merge để kết hợp các thay đổi từ một nhánh sang nhánh khác. Kết quả là một commit merge ghi lại sự kiện hợp nhất và chứa các thay đổi từ cả hai nhánh. Đây là cách chính để tích hợp các nhánh tính năng vào main, develop hoặc release trong Git Flow.

Squash merge khác gì so với merge thông thường?

Squash merge kết hợp tất cả các commit của nhánh tính năng thành một commit duy nhất trong nhánh đích, làm mất lịch sử phát triển trung gian. Merge thông thường tạo một commit merge trong khi vẫn giữ tất cả các commit của nhánh tính năng. Squash merge cho lịch sử sạch sẽ nhưng không cho phép theo dõi quá trình phát triển từng bước của tính năng.

Làm thế nào để giải quyết xung đột merge trong Git?

Mở tệp xung đột, tìm các phần có điểm đánh dấu <<<<<<< HEAD>>>>>>>. Chỉnh sửa nội dung, giữ lại các dòng cần thiết từ cả hai phiên bản, xóa các điểm đánh dấu. Lưu tệp, chạy git add và git commit. Bạn có thể sử dụng git mergetool để giải quyết trực quan.

Khi nào sử dụng merge thay vì rebase?

Merge luôn được sử dụng cho các nhánh công khai (main, develop, release) vì nó không ghi đè lịch sử. Rebase được áp dụng trong các nhánh tính năng cá nhân trước khi công bố. Một khi nhánh đã trở thành một phần của kho lưu trữ chung và đồng nghiệp đã truy cập vào nó, chỉ merge mới được phép.

Làm thế nào để hoàn tác merge trong Git?

Trước khi merge hoàn tất (trong khi xung đột) — git merge --abort hủy bỏ merge hoàn toàn. Sau khi hoàn tất — git revert <merge-commit-hash> -m 1 tạo một commit hoàn tác. Cờ -m 1 chỉ định nhánh cha nào cần giữ (nhánh đích). Git revert an toàn hơn git reset cho các nhánh đã công bố.

Tổng kết

  • Merge — hợp nhất nhánh an toàn giữ nguyên lịch sử và tạo commit merge với hai cha.
  • Chế độ hợp nhất — thông thường (--no-ff), squash (--squash) và fast-forward (--ff) cho các mục đích khác nhau.
  • Chiến lược — recursive (mặc định), octopus (3+ nhánh), ours (bỏ qua thay đổi bên ngoài).
  • Xung đột — được giải quyết thủ công bằng cách chỉnh sửa các phần được đánh dấu hoặc sử dụng mergetool.
  • An toàn — merge không sửa đổi các commit hiện có, do đó an toàn cho các nhánh công khai.
  • Squash merge — kết hợp tất cả các commit thành một, làm mất lịch sử phát triển trung gian.
  • Hoàn tác merge — git revert của commit merge với cờ -m 1 để rollback an toàn các thay đổi đã công bố.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm