Giao diện
Git Data Model: Blob, Tree, Commit 🧬
Mục tiêu: Hiểu ba object types cốt lõi tạo nên toàn bộ Git.
Git không lưu trữ diffs - Git lưu trữ snapshots. Mọi thứ trong Git đều là một trong bốn loại objects: Blob, Tree, Commit, và Tag. Module này tập trung vào ba loại chính.
🎯 The Core Concept: Content-Addressable Storage
Trước khi đi vào chi tiết, hãy hiểu nguyên tắc nền tảng:
Content → SHA-1 Hash → Object NameMọi object trong Git được đặt tên bằng SHA-1 hash của nội dung của nó.
bash
# Tính SHA-1 của một string
echo "Hello Git" | git hash-object --stdin
# Output: 9f4d96d5b00d98959ea9960f069585ce42b1349a
# Content giống nhau = SHA-1 giống nhau = Chỉ lưu 1 lầnTẠI SAO CONTENT-ADDRESSABLE?
- Deduplication tự động: Cùng file = cùng SHA-1 = lưu 1 lần
- Integrity verification: Thay đổi 1 byte → SHA-1 thay đổi hoàn toàn
- Immutability: Objects không bao giờ bị sửa, chỉ tạo mới
🔵 Blob - File Content
Blob (Binary Large Object) lưu trữ nội dung file - không có filename, không có metadata, chỉ có raw bytes.
Cấu trúc
blob <size>\0<content>Ví dụ thực tế
bash
# Tạo file
echo "Hello, Git Internals!" > hello.txt
# Xem blob sẽ có SHA-1 gì
git hash-object hello.txt
# Output: 8ab686eafeb1f44702738c8b0f24f2567c36da6d
# Stage file (tạo blob trong .git/objects/)
git add hello.txt
# Xem nội dung blob
git cat-file -p 8ab686e
# Output: Hello, Git Internals!
# Xem loại object
git cat-file -t 8ab686e
# Output: blobĐặc điểm quan trọng
| Property | Giải thích |
|---|---|
| Không chứa filename | Filename được lưu trong Tree, không phải Blob |
| Không chứa permissions | Permissions cũng trong Tree |
| Content-only | Hai files khác tên, cùng nội dung = cùng Blob |
| Compressed | Lưu trữ dạng zlib-compressed |
BLOB KHÔNG BIẾT TÊN FILE
Đây là điều nhiều người hiểu sai. Blob chỉ là content. Nếu bạn có 10 files với cùng nội dung, Git chỉ lưu 1 blob duy nhất.
🟢 Tree - Directory Structure
Tree object lưu trữ directory structure - mapping giữa filenames và blobs/subtrees.
Cấu trúc
tree <size>\0
<mode> <filename>\0<sha1-binary>
<mode> <filename>\0<sha1-binary>
...Ví dụ thực tế
bash
# Cấu trúc thư mục
# src/
# ├── main.py
# └── utils/
# └── helper.py
# Xem tree của commit hiện tại
git cat-file -p HEAD^{tree}
# Output:
# 100644 blob a1b2c3... main.py
# 040000 tree d4e5f6... utilsMode Values
| Mode | Loại | Giải thích |
|---|---|---|
100644 | Regular file | File bình thường |
100755 | Executable | File có quyền thực thi |
120000 | Symlink | Symbolic link |
040000 | Directory | Subdirectory (trỏ đến Tree khác) |
160000 | Submodule | Git submodule |
Visual Example
🔴 Commit - The Snapshot Wrapper
Commit object là wrapper chứa metadata và trỏ đến một Tree (snapshot của entire project).
Cấu trúc
commit <size>\0
tree <tree-sha1>
parent <parent-commit-sha1> # Optional, có thể nhiều parents
author <name> <email> <timestamp>
committer <name> <email> <timestamp>
<commit message>Ví dụ thực tế
bash
# Xem commit object
git cat-file -p HEAD
# Output:
# tree a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
# parent u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0
# author HPN <hpn@example.com> 1703548800 +0700
# committer HPN <hpn@example.com> 1703548800 +0700
#
# feat: add user authenticationCommit Fields Explained
| Field | Giải thích |
|---|---|
tree | SHA-1 của root tree (snapshot) |
parent | SHA-1 của commit cha (có thể 0, 1, hoặc nhiều) |
author | Người viết code gốc |
committer | Người tạo commit (có thể khác author khi cherry-pick/rebase) |
message | Commit message |
PARENT COMMITS
- 0 parents: Initial commit (root commit)
- 1 parent: Regular commit
- 2+ parents: Merge commit
🔗 Connecting the Pieces
Bây giờ hãy xem cách ba object types liên kết với nhau:
Quan sát quan trọng:
config.pykhông đổi qua 3 commits → Cùng 1 blobB3được reuse- Mỗi commit trỏ đến một tree khác nhau (snapshot khác nhau)
- Commits link ngược về parent (history chain)
🔬 Deep Dive: Complete Object Hierarchy
🛠️ Hands-on Lab
Exercise: Tạo Objects thủ công
bash
# 1. Tạo blob thủ công
echo "Hello from raw Git!" | git hash-object -w --stdin
# Output: <sha1> - blob đã được lưu vào .git/objects/
# 2. Tạo tree từ index
git update-index --add --cacheinfo 100644 <blob-sha1> test.txt
git write-tree
# Output: <tree-sha1>
# 3. Tạo commit từ tree
echo "Manual commit" | git commit-tree <tree-sha1>
# Output: <commit-sha1>
# 4. Cập nhật branch để trỏ đến commit mới
git update-ref refs/heads/manual-branch <commit-sha1>Exercise: Trace Object Graph
bash
# Từ HEAD, trace toàn bộ object graph
COMMIT=$(git rev-parse HEAD)
echo "Commit: $COMMIT"
git cat-file -p $COMMIT
TREE=$(git rev-parse HEAD^{tree})
echo "Tree: $TREE"
git cat-file -p $TREE
# List all blobs
git cat-file -p $TREE | while read mode type sha name; do
echo "$type $sha $name"
done📊 Object Type Summary
| Object | Chứa gì | Points to | SHA-1 dựa trên |
|---|---|---|---|
| Blob | File content | Nothing | Content bytes |
| Tree | Directory listing | Blobs, other Trees | Mode + name + SHA-1 entries |
| Commit | Metadata + pointer | One Tree, parent Commits | All metadata + tree SHA |
💡 Key Takeaways
HPN'S INSIGHT
"Git có đúng 3 loại data objects. Nắm vững chúng, bạn nắm vững Git."
- Blob = Content: Chỉ lưu nội dung, không biết tên file
- Tree = Structure: Map filenames → blobs/subtrees
- Commit = Snapshot: Metadata + pointer đến root tree
- Immutable: Objects không bao giờ thay đổi sau khi tạo
- Deduplication: Cùng content = cùng SHA-1 = lưu 1 lần