git merge
Xem thửVấn đề cần giải quyết
Tính năng giỏ hàng đã xong trên nhánh feature. Giờ cần đưa nó vào main. Có lúc Git chỉ việc trượt con trỏ, có lúc lại tạo thêm một commit hợp nhất. Bạn không chọn ngẫu nhiên: hình dạng lịch sử quyết định, và hiểu nó giúp bạn đọc đúng kết quả merge.
Sau bài này, bạn có thể
- Phân biệt fast-forward và three-way merge.
- Biết khi nào Git tạo commit hợp nhất có hai cha.
- Dùng
--no-ff, dọn nhánh sau merge và hủy một merge đang dở.
Tiên quyết: bài git switch.
Quy trình chuẩn
git switch main
git merge feature-login
git merge hợp nhất lịch sử của nhánh chỉ định vào nhánh hiện tại, nên bạn luôn chuyển về nhánh đích trước.
Git chọn kiểu merge thế nào
Đang tải sơ đồ…
Cách đọc hình. Git hỏi: main có đi tiếp kể từ lúc feature tách ra không? Nếu không, đây là fast-forward: chỉ trượt con trỏ main tới đỉnh feature, không có commit mới. Nếu có, đây là three-way merge: Git dùng tổ tiên chung để kết hợp và tạo commit hợp nhất có hai cha. Kiểu merge được quyết định bởi hình dạng lịch sử, không phải bạn.
Thử và quan sát
Hãy dự đoán: main không có commit mới kể từ lúc feature tách ra. git merge feature có tạo commit hợp nhất không? Chạy mô phỏng, rồi bấm biến thể để xem trường hợp main đã có commit mới.
Đang tải Animation…
Bảng bước (bản đọc tĩnh của mô phỏng)
| Bước | Lệnh | Điều xảy ra |
|---|---|---|
| 1 | git log --oneline main..feature | Xem trước những commit sẽ được đưa vào main: F1 và F2. |
| 2 | git merge feature | main không có commit mới kể từ lúc tách, nên Git chỉ cần trượt con trỏ main tới F2. Đây là fast-forward, không có commit hợp nhất. |
| 3 | git branch -d feature | Nhánh feature đã hợp nhất nên có thể xóa an toàn bằng -d. Chỉ con trỏ bị xóa. |
Biến thể: Main đã có commit mới (three-way)
| Bước | Lệnh | Điều xảy ra |
|---|---|---|
| 1 | git log --oneline main..feature | F1 và F2 sắp được đưa vào main. Nhưng lần này main đã có C4 mà feature chưa có. |
| 2 | git merge feature | Hai nhánh đều có commit mới nên Git dùng tổ tiên chung C3 để kết hợp, tạo commit hợp nhất M có hai cha là C4 và F2. |
| 3 | git branch -d feature | Xóa con trỏ feature sau khi đã hợp nhất. Các commit F1, F2 vẫn nằm trong lịch sử của M. |
Giải đáp. Không: đó là fast-forward, main chỉ trượt tới F2 và không có commit hợp nhất nào. Ở biến thể, main đã có C4 nên Git tạo commit hợp nhất M có hai cha là C4 và F2, dựa trên tổ tiên chung C3.
Ép tạo commit hợp nhất
git merge --no-ff feature-login
--no-ff luôn tạo commit hợp nhất dù có thể fast-forward, để giữ dấu vết rằng một nhóm commit đã làm trong một nhánh.
Dọn dẹp và hủy
git branch -d feature-login
git merge --abort
-d xóa nhánh đã merge. git merge --abort hủy một merge đang dở khi gặp xung đột và đưa bạn về đúng trạng thái trước merge (bài tiếp theo nói về xung đột).
Hiểu lầm thường gặp
- "Merge nào cũng tạo commit hợp nhất." Fast-forward thì không.
- "Merge xong là phải xóa nhánh." Xóa chỉ là dọn dẹp; commit vẫn nằm trong lịch sử.
- "Merge nhánh chính vào nhánh tính năng giống merge nhánh tính năng vào chính." Hướng merge quyết định ai là nhánh đích và hình dạng lịch sử kết quả.
Tự kiểm tra
- Khi nào Git thực hiện fast-forward?
- Commit hợp nhất khác commit thường ở điểm nào?
- Bạn muốn giữ dấu vết nhánh dù có thể fast-forward. Dùng tùy chọn nào?
Đáp án gợi ý. (1) Khi nhánh đích không có commit mới kể từ lúc tách. (2) Nó có hai cha. (3) --no-ff.
Điều cần nhớ
- Fast-forward chỉ trượt con trỏ; three-way tạo commit hợp nhất hai cha.
- Hình dạng lịch sử quyết định kiểu merge.
--no-ffgiữ dấu vết nhánh;--aborthủy merge dở.- Bài sau: xung đột merge.
Nguồn tham khảo
Pro Git, chương 3.2 "Basic Branching and Merging" (git-scm.com/book); tài liệu git-merge (git-scm.com/docs/git-merge).