Skip to content

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 Name

Mọ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ần

TẠI SAO CONTENT-ADDRESSABLE?

  1. Deduplication tự động: Cùng file = cùng SHA-1 = lưu 1 lần
  2. Integrity verification: Thay đổi 1 byte → SHA-1 thay đổi hoàn toàn
  3. 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

PropertyGiải thích
Không chứa filenameFilename được lưu trong Tree, không phải Blob
Không chứa permissionsPermissions cũng trong Tree
Content-onlyHai files khác tên, cùng nội dung = cùng Blob
CompressedLư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... utils

Mode Values

ModeLoạiGiải thích
100644Regular fileFile bình thường
100755ExecutableFile có quyền thực thi
120000SymlinkSymbolic link
040000DirectorySubdirectory (trỏ đến Tree khác)
160000SubmoduleGit 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 authentication

Commit Fields Explained

FieldGiải thích
treeSHA-1 của root tree (snapshot)
parentSHA-1 của commit cha (có thể 0, 1, hoặc nhiều)
authorNgười viết code gốc
committerNgười tạo commit (có thể khác author khi cherry-pick/rebase)
messageCommit 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.py không đổi qua 3 commits → Cùng 1 blob B3 đượ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

ObjectChứa gìPoints toSHA-1 dựa trên
BlobFile contentNothingContent bytes
TreeDirectory listingBlobs, other TreesMode + name + SHA-1 entries
CommitMetadata + pointerOne Tree, parent CommitsAll 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."

  1. Blob = Content: Chỉ lưu nội dung, không biết tên file
  2. Tree = Structure: Map filenames → blobs/subtrees
  3. Commit = Snapshot: Metadata + pointer đến root tree
  4. Immutable: Objects không bao giờ thay đổi sau khi tạo
  5. Deduplication: Cùng content = cùng SHA-1 = lưu 1 lần