Tuần 1 - Ngày 3: Branching — Làm Việc Song Song
Mục tiêu học tập
- Hiểu branch là gì trong Git object model (con trỏ)
- Thao tác tạo, chuyển, xoá branch với
git branch,git switch - Phân biệt fast-forward merge và merge commit
- Nắm quy ước đặt tên branch
- Xoá branch local và remote an toàn
1. Branch là gì trong Git?
Không giống SVN, branch trong Git cực kỳ nhẹ — chỉ là một file văn bản chứa SHA-1 hash của commit mà nó đang trỏ vào.
.git/refs/heads/main → abc1234...
.git/refs/heads/feature/auth → def5678...
HEAD — Con trỏ "bạn đang ở đâu"
Khi bạn tạo branch mới và switch sang:
HEAD là symbolic reference: thường trỏ vào một branch, branch đó trỏ vào commit. Khi commit mới, branch hiện tại tự động tiến lên commit mới.
"Detached HEAD" state
# Checkout một commit hash trực tiếp → detached HEAD
git checkout abc1234
# HEAD → abc1234 (không qua branch)
# Nguy hiểm: commit trong detached HEAD sẽ bị garbage collect
# nếu không tạo branch để giữ
git switch -c save-my-work # tạo branch để lưu
2. Tạo và chuyển branch
Cú pháp hiện đại (Git 2.23+)
# Xem tất cả branches local
git branch
# Xem cả remote branches
git branch -a
# Tạo branch mới (chưa switch sang)
git branch feature/user-login
# Tạo và switch ngay
git switch -c feature/user-login
# hoặc cú pháp cũ (vẫn hợp lệ)
git checkout -b feature/user-login
# Switch sang branch đã tồn tại
git switch main
git switch feature/user-login
# Switch về branch trước đó (như cd -)
git switch -
# Xem branch hiện tại
git branch --show-current
Sự khác biệt giữa git switch và git checkout
git checkout làm quá nhiều việc (switch branch, restore files, checkout commit). Git 2.23 tách thành:
git switch— thay đổi branchgit restore— khôi phục file
Khuyến nghị dùng switch và restore cho code mới vì rõ ràng hơn.
3. Merge — Hợp nhất branches
Fast-forward merge
Fast-forward xảy ra khi branch cần merge không có commit nào tách ra khỏi branch đích. Git chỉ đơn giản tiến con trỏ branch lên.
git switch main
git merge feature/login
# Output: Fast-forward
# Không tạo commit mới
Merge commit (3-way merge)
Khi cả hai branches đều có commits riêng, Git tạo một "merge commit" mới với 2 parents.
git switch main
git merge feature/login
# Output: Merge made by the 'ort' strategy
# Git tạo merge commit M với message "Merge branch 'feature/login'"
Tắt fast-forward (--no-ff)
# Luôn tạo merge commit, ngay cả khi có thể fast-forward
git merge --no-ff feature/login
# Lợi ích: lịch sử thể hiện rõ feature được merge ở đâu
# Dùng trong Git Flow (merge feature vào develop)
4. Quy ước đặt tên branch
Tên branch tốt giúp team nhận ra mục đích ngay lập tức.
Pattern phổ biến
feature/<mô-tả-ngắn> feat/user-auth
fix/<mô-tả-ngắn> fix/login-500-error
hotfix/<mô-tả> hotfix/payment-null-ptr
release/<version> release/1.4.0
chore/<mô-tả> chore/upgrade-eslint
docs/<mô-tả> docs/api-reference
refactor/<mô-tả> refactor/db-connection-pool
Quy tắc đặt tên
# TRÁNH
feature/thêm đăng nhập # khoảng trắng
Feature/UserAuth # chữ hoa (git case-sensitive trên Linux)
my-fix # không có prefix
fix_login_bug # dùng underscore thay gạch ngang
f/lg # quá tối nghĩa
# NÊN
feature/user-login # lowercase, gạch ngang
fix/AUTH-42-session-expiry # có ticket ID
hotfix/v1.4.1-null-deref # cho hotfix
5. Xoá branch
Xoá branch local
# Xoá branch đã merge (an toàn — Git kiểm tra)
git branch -d feature/user-login
# Force delete — kể cả chưa merge (cẩn thận)
git branch -D feature/abandoned-experiment
# Xem branches đã merge vào main (an toàn xoá)
git branch --merged main
# Xem branches chưa merge (cẩn thận trước khi xoá)
git branch --no-merged main
Xoá branch remote
# Xoá branch trên remote (GitHub/GitLab)
git push origin --delete feature/user-login
# hoặc cú pháp cũ
git push origin :feature/user-login
# Dọn dẹp remote-tracking references bị stale
git remote prune origin
# hoặc kết hợp khi fetch
git fetch --prune origin
6. Conflict khi merge — Xử lý cơ bản
Conflict xảy ra khi hai branches sửa cùng một dòng trong cùng file.
# Tình huống: main và feature/login đều sửa src/app.js dòng 5
git switch main
git merge feature/login
# CONFLICT (content): Merge conflict in src/app.js
# Automatic merge failed; fix conflicts and then commit the result.
# Xem file conflict
git status
# both modified: src/app.js
# Nội dung file sau conflict:
<<<<<<< HEAD
const timeout = 30 * 60 * 1000; // 30 phút (main branch)
=======
const timeout = 60 * 60 * 1000; // 60 phút (feature/login)
>>>>>>> feature/login
# Chỉnh sửa file manually → giữ version muốn:
const timeout = 60 * 60 * 1000; // 60 phút (giữ feature)
# Sau khi resolve tất cả conflicts
git add src/app.js
git commit # tạo merge commit
# Nếu muốn bỏ merge giữa chừng
git merge --abort
7. Tổng quan workflow branches
Câu hỏi ôn tập
-
Branch trong Git thực sự là gì ở level storage (không phải khái niệm)?
Xem đáp án
Branch là một file văn bản nhỏ trong
.git/refs/heads/<tên-branch>chứa SHA-1 hash của commit mà nó đang trỏ vào. Đó là lý do tạo branch trong Git cực kỳ nhanh (chỉ tạo một file nhỏ) và không tốn dung lượng — khác hẳn với SVN branch phải copy toàn bộ codebase. -
Fast-forward merge khác 3-way merge ở điểm nào? Khi nào không thể fast-forward?
Xem đáp án
Fast-forward: branch đích không có commit mới kể từ khi feature branch tách ra → Git chỉ tiến con trỏ branch lên commit mới nhất, không tạo merge commit. 3-way merge: cả hai branches đều có commits riêng sau khi phân kỳ → Git cần tạo merge commit mới với 2 parents.
Không thể fast-forward khi branch đích (
main) đã có thêm commits sau khi feature branch được tạo. -
Tại sao
git branch -dan toàn hơngit branch -D?Xem đáp án
git branch -dkiểm tra branch đã được merge vào branch hiện tại hay upstream chưa. Nếu chưa merge, Git từ chối xoá và báo lỗi — bảo vệ bạn khỏi mất commits chưa được integrate.git branch -Dforce delete không kiểm tra, có thể mất commits nếu branch có work chưa merge. Luôn dùng-dtrước; dùng-Dchỉ khi chắc chắn muốn bỏ hẳn branch đó. -
Lệnh nào xem tất cả branches (local + remote)?
Xem đáp án
git branch -a(hoặc--all). Hiện local branches và remote-tracking branches (remotes/origin/main,remotes/origin/feature/...). Để chỉ xem remote branches:git branch -r. Remote-tracking branches được cập nhật khi bạngit fetch. -
"Detached HEAD" nghĩa là gì và cách thoát an toàn?
Xem đáp án
Detached HEAD xảy ra khi HEAD trỏ thẳng vào một commit hash thay vì qua một branch. Xảy ra khi checkout commit cụ thể (
git checkout abc1234). Nguy hiểm: nếu bạn commit trong trạng thái này, commit đó không được theo dõi bởi branch nào và sẽ bị garbage collect.Cách thoát an toàn:
git switch -c new-branch-nameđể tạo branch mới giữ lại commit đó, hoặcgit switch mainđể bỏ qua và quay về branch.
Bài tập thực hành
# Setup
mkdir git-branch-lab && cd git-branch-lab
git init
git config user.name "Your Name"
git config user.email "you@example.com"
# 1. Tạo base trên main
echo "version 1" > app.js
git add app.js
git commit -m "feat: initial version"
# 2. Tạo feature branch
git switch -c feature/v2
echo "version 2 feature" >> app.js
git add app.js
git commit -m "feat: add v2 feature"
# 3. Fast-forward merge
git switch main
git merge feature/v2
git log --oneline --graph
# → linear history, no merge commit
# 4. Tạo tình huống 3-way merge
git switch -c feature/v3
echo "version 3 on feature" >> app.js
git add app.js && git commit -m "feat: v3 on feature"
git switch main
echo "hotfix on main" >> app.js
git add app.js && git commit -m "fix: hotfix on main"
git merge feature/v3
git log --oneline --graph
# → thấy merge commit
# 5. Tạo và resolve conflict
git switch -c conflict-branch
echo "line A" > conflict.txt
git add conflict.txt && git commit -m "add conflict.txt A"
git switch main
echo "line B" > conflict.txt
git add conflict.txt && git commit -m "add conflict.txt B"
git merge conflict-branch
# → CONFLICT! Resolve manually, then git add + git commit
# 6. Dọn dẹp
git branch -d feature/v2 feature/v3 conflict-branch
git branch
Tài liệu tham khảo chính thức
Tiếp theo: Ngày 4 — Remote Repository