Bài 2, mỗi lần git commit chúng ta chỉ nói chung chung "HEAD cập nhật". Bài này mở đúng chỗ đó ra: branchHEAD thực chất chỉ là những file văn bản bé xíu trỏ tới hash commit — và hiểu rõ cơ chế con trỏ này giải thích được vì sao Git khuyến khích tạo hàng chục nhánh mỗi ngày mà không lo tốn kém gì.

1. Branch Chỉ Là Một Con Trỏ 41 Byte

Một branch trong Git, ví dụ main, thực chất là 1 file tại .git/refs/heads/main chứa đúng 1 dòng: hash 40 ký tự hex của commit mà nhánh đó đang trỏ tới (cộng 1 ký tự xuống dòng = 41 byte). Không có gì khác. Tạo 1 branch mới nghĩa là tạo 1 file bé xíu như vậy — cực rẻ, bất kể repo có bao nhiêu file hay lịch sử dài tới đâu:

terminal
$ cat .git/refs/heads/main
a1b2c3d4e5f6789012345678901234567890abcd

$ git branch feature       # tạo file .git/refs/heads/feature với CÙNG hash trên
$ cat .git/refs/heads/feature
a1b2c3d4e5f6789012345678901234567890abcd

2. HEAD: Con Trỏ Của Con Trỏ

HEAD trả lời câu hỏi "tôi đang đứng ở đâu?" — nhưng nó thường không trỏ thẳng vào 1 commit. Nó trỏ vào tên của 1 branch, và branch đó mới trỏ vào commit. Đây gọi là symbolic ref:

terminal
$ cat .git/HEAD
ref: refs/heads/main       # HEAD trỏ tới TÊN branch, không phải hash trực tiếp

Vì HEAD trỏ gián tiếp qua tên branch, khi bạn git commit, Git chỉ cần cập nhật file refs/heads/main để trỏ tới commit mới — HEAD không cần đổi gì cả, nó tự động "theo" branch main tới vị trí mới vì vẫn trỏ vào đúng cái tên đó.

3. git checkout / git switch — Di Chuyển HEAD

Chuyển nhánh nghĩa là ghi đè nội dung file .git/HEAD để nó trỏ sang tên branch khác, rồi cập nhật Working Directory + Staging Index (từ Bài 2) cho khớp với tree của commit mà branch mới đang trỏ tới:

terminal
$ git checkout feature     # .git/HEAD giờ chứa: ref: refs/heads/feature
$ git switch feature       # lệnh mới hơn (Git 2.23+), làm đúng việc tương tự cho branch
$ git switch -c hotfix     # tắt: tạo branch "hotfix" RỒI chuyển sang luôn

4. Detached HEAD: Khi HEAD Trỏ Thẳng Vào Commit

Nếu bạn checkout thẳng vào 1 hash commit (thay vì tên branch), .git/HEAD sẽ chứa chính hash đó thay vì ref: refs/heads/... — trạng thái này gọi là detached HEAD. Bạn vẫn commit được bình thường, nhưng không branch nào trỏ tới những commit mới này:

🕳️ Cạm bẫy thường gặp: Mất commit vì quên đang ở detached HEAD
Nếu bạn tạo vài commit trong lúc detached HEAD rồi checkout sang 1 branch khác, những commit đó không còn nằm trên nhánh nào — chúng vẫn tồn tại trong .git/objects (bất biến, không tự xoá ngay) nhưng không có con trỏ nào dẫn tới. Nếu không tạo branch mới trỏ vào chúng trước khi rời đi, chúng sẽ dần bị garbage-collect. Luôn git branch <tên> ngay khi nhận ra mình cần giữ lại các commit lỡ tạo ở trạng thái detached.

5. Fast-Forward: Khi Không Cần Tạo Commit Mới

Xem trước một khái niệm mà Bài 4 sẽ đào sâu: nếu branch main chưa có commit nào mới kể từ khi bạn tách nhánh feature ra, thì "merge" feature vào main không cần tạo commit hợp nhất nào cả — Git chỉ đơn giản di chuyển con trỏ main tới thẳng vị trí commit mới nhất của feature. Đây gọi là fast-forward, và nó chỉ khả thi chính xác vì branch chỉ là 1 con trỏ có thể di chuyển tự do dọc theo 1 đường thẳng lịch sử.

6. So Sánh Các Lệnh Di Chuyển Nhánh

Lệnh Tạo branch mới? Di chuyển HEAD?
git branch <tên> Không
git checkout <branch> / git switch <branch> Không Có — trỏ sang branch đó
git checkout -b <tên> / git switch -c <tên> Có — trỏ sang branch vừa tạo
git checkout <hash-commit> Không Có — detached, trỏ thẳng vào commit

Sân chơi tương tác: Interactive Git Graph Simulator

Gõ lệnh Git giả lập vào ô bên dưới và xem đồ thị commit, con trỏ branch, và HEAD cập nhật ngay lập tức. Thử: tạo 1 branch mới, chuyển qua lại, commit trên từng nhánh, rồi thử checkout thẳng vào 1 hash commit để xem detached HEAD trông như thế nào.

🌿 Sân chơi tương tác: Interactive Git Graph Simulator

Terminal giả lập

  • git commit -m "..."
  • git branch <tên>
  • git checkout <tên|hash>
  • git checkout -b <tên>
  • git switch <tên>
  • git log

Nhật ký

git-graph-live.js

Trắc nghiệm ôn tập

Câu 1: Khi bạn git commit trên branch main, vì sao HEAD "tự động đi theo" tới commit mới mà không cần cập nhật gì thêm?

Trắc nghiệm ôn tập

Câu 2: Bạn git checkout thẳng vào 1 hash commit rồi tạo 3 commit mới. Sau đó bạn git checkout main. Chuyện gì xảy ra với 3 commit vừa tạo?

Trắc nghiệm ôn tập

Câu 3: Điều kiện nào khiến một merge trở thành fast-forward (không tạo commit hợp nhất)?

📖 Tài liệu tham khảo / References

Bài viết liên quan trong series

Bài 4: Merge & Conflict Bài 2: Three Trees & Staging Quay lại Lộ trình Series Git