</>Học Dev
Bài học

Tuần 1 - Ngày 3: Branching — Làm Việc Song Song

Tuần 1 – Ngày 3

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"

Repositorystate:HEADmainABCD(commits)

Khi bạn tạo branch mới và switch sang:

ABCDmainfeature/authHEAD

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 switchgit 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 branch
  • git restore — khôi phục file

Khuyến nghị dùng switchrestore 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.

Trưcmerge:mainABCDEfeature/loginHEADSau:gitswitchmain&&gitmergefeature/loginmaintiếnlênthngDvàE(fast-forward)ABCDEmain=feature/login
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.

Trưcmerge:mainABCFDEfeature/loginHEADSau:gitmergefeature/loginABCFMmergecommit(2parents:FvàE)DE
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

main(protected)feature/user-authdevAfeature/paymentdevBfix/navbar-mobiledevCWorkflow:1.gitswitch-cfeature/my-task(tobranchtmainminht)2.Làmvic,commitnhiuln3.gitswitchmain&&gitpull(syncmain)4.gitswitchfeature/my-task&&gitmergemain(updatebranch)5.gitswitchmain&&gitmergefeature/my-task(mergevàomain)6.gitbranch-dfeature/my-task(dndp)

Câu hỏi ôn tập

  1. 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.

  2. 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.

  3. Tại sao git branch -d an toàn hơn git branch -D?

    Xem đáp án

    git branch -d kiể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 -D force delete không kiểm tra, có thể mất commits nếu branch có work chưa merge. Luôn dùng -d trước; dùng -D chỉ khi chắc chắn muốn bỏ hẳn branch đó.

  4. 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ạn git fetch.

  5. "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ặc git 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