Git Object Model: Blob, Tree, Commit, Tag อธิบายให้เข้าใจง่าย

บทนำเกี่ยวกับ Git Object Model

Git Object Model ประกอบด้วย 4 ประเภท Object ที่พื้นฐาน: Blob, Tree, Commit และ Tag แต่ละตัวมีบทบาทสำคัญในการทำงานของระบบ Git และการจัดเก็บข้อมูล ความเข้าใจลึกลับเกี่ยวกับ Object Model จะช่วยให้คุณใช้ Git ได้อย่างมีประสิทธิภาพและเข้าใจวิธีการทำงานภายในของระบบควบคุมเวอร์ชัน ระบบ Git ถูกออกแบบให้ใช้ประสิทธิภาพของการจัดเก็บข้อมูลแบบ Content-addressable ซึ่งช่วยให้ Repository สามารถทำงานได้อย่างมีประสิทธิภาพ แม้ว่าจะมี Commit นับล้านตัวก็ตาม

4 Object Types ในระบบ Git และบทบาทของแต่ละตัว

Git ถูกออกแบบให้ใช้ระบบ Content-addressable storage ซึ่งหมายความว่าแต่ละ Object จะถูกระบุด้วย SHA-1 hash ของเนื้อหา Object นี้มีความสำคัญต่อความปลอดภัยและความสมบูรณ์ของ Repository การเข้าใจประเภท Object แต่ละตัวเป็นพื้นฐานของการเข้าใจว่า Git ทำงานอย่างไรในระดับที่ลึกที่สุด

1. Blob (Binary Large Object) – เก็บเนื้อหาไฟล์

Blob เป็นการเก็บเนื้อหา File โดยไม่เก็บชื่อ Filename หรือ Path ไว้ในตัว Object เอง ถ้า File สองไฟล์มีเนื้อหาเหมือนกันทุกประการ Git จะสร้าง Blob เพียงหนึ่งตัวสำหรับทั้งสอง ไฟล์ ซึ่งช่วยประหยัดพื้นที่เก็บข้อมูลได้อย่างมีนัยสำคัญ Blob Object ไม่มีการอ้างอิงถึง Type ของไฟล์หรือ File Permissions เพียงแค่เนื้อหาข้อมูลเท่านั้น

ตัวอย่างเช่น ถ้าคุณสร้างไฟล์ README.md ด้วยข้อความ “Hello Git” Git จะสร้าง Blob ที่มี SHA-1 hash ที่คำนวณจากเนื้อหา “Hello Git” และเก็บไว้ใน .git/objects directory นี่เป็นการออกแบบที่ฉลาดเพราะไม่ว่าไฟล์ชื่อไรหรืออยู่ในโฟลเดอร์ไหน ถ้าเนื้อหาเหมือนกันก็จะแชร์ Blob เดียวกัน ความจำเป็นของการดีดุปลิเคชั่นนี้เป็นสิ่งสำคัญเมื่อคุณมี Project ขนาดใหญ่ที่มีไฟล์ที่เหมือนกันหลายตัว

# ตัวอย่างการสร้าง Blob
echo "Hello Git" > myfile.txt
git add myfile.txt

# Git จะสร้าง Blob ด้วย hash เช่น:
# 4e1243bd22c66e76c2ba9eddc1f91394e57f0731

# ตรวจสอบ Blob
git cat-file -t 4e1243bd22c66e76c2ba9eddc1f91394e57f0731
# Output: blob

# ดูเนื้อหา Blob
git cat-file -p 4e1243bd22c66e76c2ba9eddc1f91394e57f0731
# Output: Hello Git

# ตรวจสอบขนาด
git cat-file -s 4e1243bd22c66e76c2ba9eddc1f91394e57f0731
# Output: 10 (bytes)

# ใช้ Abbreviated Hash ได้เช่นกัน
git cat-file -p 4e124

2. Tree (Directory Structure) – เก็บโครงสร้างไดเรกทอรี่

Tree เก็บโครงสร้าง Directory และชี้ไปยัง Blobs และ Trees อื่นๆ Tree Object มีลักษณะเหมือนกับ Directory ที่ประกอบด้วยรายการของ File (Blobs) และ Subdirectories (Trees) ซึ่งช่วยให้ Git สามารถสร้างแบบ Hierarchical structure ของ Project ได้

Tree ต้องเก็บข้อมูลของไฟล์ เช่น File Mode (executable หรือ regular file), Filename, และ Reference ไปยัง Blob หรือ Tree ที่เกี่ยวข้อง บทบาทของ Tree ในโครงสร้าง Git เมื่อมี Commit เกิดขึ้น Commit จะชี้ไปยัง Tree Root หนึ่งตัว ซึ่งแทนถึงสถานะของ Project ณ เวลา Commit นั้น Tree Object ยังมีข้อมูล File Mode ที่บ่งชี้ว่า File นั้นเป็น Regular File (100644), Executable (100755) หรือ Symlink (120000)

# ตัวอย่างโครงสร้าง Tree
# Tree Root ชี้ไปยัง:
# - Blob: README.md (hash: abc123)
# - Blob: app.js (hash: def456)
# - Tree: src/ (hash: ghi789)
#   - Blob: utils.js (hash: jkl012)
#   - Blob: config.js (hash: mno345)

# ดู Tree Object
git cat-file -p 
# Output:
# 100644 blob abc123    README.md
# 100755 blob def456    app.js (executable)
# 040000 tree ghi789    src

# ดูข้อมูล Tree แบบ Raw
git ls-tree 

# ดูข้อมูล Tree แบบ Recursive
git ls-tree -r 

# ดูข้อมูล Tree ของ Specific Commit
git ls-tree -r HEAD

3. Commit (Snapshot) – บันทึกสถานะของ Project

Commit ชี้ไปยัง Tree หนึ่งตัว ระบุ Author, Date, Commit Message และ Reference ไปยัง Parent Commit (หรือ Commits ถ้าเป็น Merge Commit) Commit Object ถือเป็น Snapshot ของ Project ณ เวลาที่ Commit เกิดขึ้น และมี Metadata ที่เก็บบริบทสำคัญเกี่ยวกับการเปลี่ยนแปลง

Commit hash (SHA-1 ID) ถูกสร้างจากเนื้อหาของ Commit Object ซึ่งรวมถึง Tree Reference, Parent Commit Reference, Author Information, Timestamp, และ Commit Message ด้วย หมายความว่าถ้ามีการเปลี่ยนแปลงใดๆ ในข้อมูลเหล่านี้ Commit Hash จะเปลี่ยนไปด้วย นี่คือการป้องกันความสมบูรณ์ของข้อมูล (Data Integrity) ที่มีพื้นฐานแล้วในระบบ Git Commit ยังมีข้อมูล Committer ซึ่งอาจแตกต่างจาก Author ในบางกรณี (เช่น เมื่อ Maintainer ทำการ Rebase)

# ดูเนื้อหา Commit
git cat-file -p abc123

# Output:
# tree xyz789
# parent def456
# author John Doe  1711612800 +0700
# committer John Doe  1711612800 +0700
#
# Add new features to the project

# ดู Commit ID
git log --oneline
# Output: abc123 Add new features to the project

# ดูข้อมูล Commit แบบละเอียด
git show abc123

# ดูข้อมูล Commit ของ Merge
git cat-file -p 
# Output จะมี 2 parent lines

# ดูจำนวน Parent
git rev-list --parents abc123 | head -1

4. Tag (Label) – ทำเครื่องหมายจุดสำคัญ

Tag ชี้ไปยัง Commit เพื่อทำเครื่องหมาย Release หรือ Milestone สำคัญ มี 2 ประเภท Lightweight Tag ซึ่งเป็น Reference ธรรมดา และ Annotated Tag ซึ่งเป็น Object ที่มี Metadata เช่น Tagger, Date, และ Message ต่างจากการใช้ Commit Hash ที่ยาวและหายากต่อการจำ Tag ช่วยให้ Developer สามารถอ้างอิง Commit ที่สำคัญได้อย่างง่าย เช่น v1.0, v2.0 เป็นต้น

Lightweight Tag เป็น Reference ธรรมดา (ชี้ไปยัง Commit) ในขณะที่ Annotated Tag เป็น Object ที่มีข้อมูลเพิ่มเติม เช่น Tagger Name, Email, Date, และ Message ซึ่งมีประโยชน์สำหรับการทำเครื่องหมาย Release ที่สำคัญ ทั้งสองประเภทสามารถใช้สำหรับ Branching และ Merging ได้

# สร้าง Lightweight Tag
git tag v1.0

# สร้าง Annotated Tag
git tag -a v1.0 -m "Release version 1.0"

# สร้าง Signed Tag (ต้องมี GPG Key)
git tag -s v1.0 -m "Release version 1.0"

# ดู Tag
git tag
# Output: v1.0

# ดูข้อมูล Tag
git show v1.0

# ดูขนาด Tag Object
git cat-file -s v1.0

# ลบ Tag
git tag -d v1.0

# Push Tag ไปยัง Remote
git push origin v1.0

# Push ทั้งหมด
git push origin --tags

SHA-1 Hashing และ Content-Addressable Storage – ฟาวนเดชั่นของ Git

Git ใช้ SHA-1 Hash เพื่อสร้าง ID เฉพาะสำหรับ Object แต่ละตัว ID ยาว 40 ตัวอักษร (Hexadecimal) ซึ่งคำนวณจากเนื้อหาของ Object ความสำคัญของ SHA-1 Hash คือมันทำให้ Git สามารถตรวจสอบความสมบูรณ์ของข้อมูลได้ หากมีการเปลี่ยนแปลงใดๆ ต่อ Object Hash ก็จะเปลี่ยนไปด้วย

นี่คือวิธีที่ Git สามารถตรวจจับการทำลายหรือการเปลี่ยนแปลงข้อมูลลับ (Data Corruption) ได้โดยอัตโนมัติ เมื่อ Git บันทึก Object แต่ละตัว มันจะคำนวณ SHA-1 Hash และใช้มันเป็น Filename ใน .git/objects directory ระบบนี้เรียกว่า Content-addressable storage เพราะ Address (ที่อยู่) ของ Object คำนวณมาจาก Content (เนื้อหา) ของมัน

# ตัวอย่างการคำนวณ SHA-1 Hash
echo "Hello Git" | git hash-object --stdin
# Output: 4e1243bd22c66e76c2ba9eddc1f91394e57f0731

# Hash เดียวกันกับการเก็บไฟล์
echo "Hello Git" > test.txt
git hash-object test.txt
# Output: 4e1243bd22c66e76c2ba9eddc1f91394e57f0731

# Hash จะเปลี่ยนถ้าเนื้อหาเปลี่ยน
echo "Hello Git!" | git hash-object --stdin
# Output: 5d41402abc4b2a76b9719d911017c592

# ดูไฟล์ Object ที่บันทึก
ls -la .git/objects/4e/
# Output: 4e1243bd22c66e76c2ba9eddc1f91394e57f0731

# คำนวณ Object Type
git hash-object --stdin -t blob
git hash-object --stdin -t commit
git hash-object --stdin -t tree

Object Relationship และการเชื่อมต่อระหว่าง Objects

ความสัมพันธ์ระหว่าง Blob, Tree, Commit และ Tag สร้างเป็นโครงสร้างแบบ DAG (Directed Acyclic Graph) ที่ช่วยให้ Git สามารถจัดเก็บและติดตามประวัติของ Project ได้อย่างมีประสิทธิภาพ ความเข้าใจเกี่ยวกับความสัมพันธ์เหล่านี้จะช่วยให้คุณเห็นภาพรวมของวิธีการทำงานของ Git ได้ชัดเจนยิ่งขึ้น

Commit (abc123) - "Add new features"
  |
  +-- Author: John Doe
  +-- Date: 2026-03-28
  +-- Parent: def456 (previous commit)
  |
  +-- Tree (xyz789) - root directory
       |
       +-- Blob (file1.txt) - hash: 111
       +-- Blob (file2.js) - hash: 222  
       +-- Tree (src/) - subdirectory
            |
            +-- Blob (app.js) - hash: 333
            +-- Blob (utils.js) - hash: 444

Tag (v1.0) -----> points to Commit (abc123)

# Visualization ของ DAG
Commit Graph:
C1 (root)
 |
C2 <-- main branch
 |
C3 <-- feature branch
 |
C4 (merge commit)
 |
C5 (HEAD -> main)

ความเข้าใจความสัมพันธ์ระหว่าง Object เหล่านี้จะช่วยให้คุณเข้าใจวิธีการทำงานของ Git Snapshot Model ได้ลึกลับยิ่งขึ้น เมื่อคุณ Clone Repository จาก Remote ก็คือการดาวน์โหลด Objects ทั้งหมดเหล่านี้ และสร้างโครงสร้างเหล่านี้ขึ้นใหม่ในเครื่องของคุณ

วิธีตรวจสอบ Objects ด้วย git cat-file – เครื่องมือสำรวจ

คำสั่ง git cat-file เป็นเครื่องมือพื้นฐานในการสำรวจ Git Objects ซึ่งมีประโยชน์มากเมื่อคุณต้องการเข้าใจว่ามี Object อะไรบ้างในระบบ ลองใช้คำสั่งต่างๆ ดังนี้:

# ดูประเภท Object
git cat-file -t abc123
# Output: commit

# ดูขนาด (ไบต์)
git cat-file -s abc123
# Output: 234

# ดูเนื้อหา Object แบบละเอียด
git cat-file -p abc123

# ดูข้อมูลหลายอย่างพร้อมกัน
git cat-file abc123

# ใช้ Hash ย่าย (Abbreviated Hash)
git cat-file -p abc12

# ดูทั้งหมดในครั้งเดียว
git cat-file -t -s -p abc123

# ดู Object History
git log --all --oneline

# ดู Object Reference
git show-ref

โดยที่ abc123 คือ Commit Hash หรือ Object Hash ที่คุณต้องการตรวจสอบ คุณสามารถใช้ Hash ย่าย (Abbreviated Hash) ได้เช่นกัน นี่คือวิธีที่ Developer มืออาชีพใช้เพื่อเข้าใจว่า Git Repository มีอะไรบ้างภายใน

ตัวอย่างการติดตามข้อมูล Object จริง – Hands-On Experience

สมมติว่าคุณมี Git Repository และต้องการดูว่า Object แต่ละตัวมีลักษณะอย่างไร สามารถทำได้ดังนี้:

# ดู Commit ล่าสุด
git log --oneline
# Output: abc123 Add new features

# ตรวจสอบ Commit Object
git cat-file -p abc123
# Output:
# tree xyz123
# parent def456  
# author John Doe  1711612800 +0700
# committer John Doe  1711612800 +0700
#
# Add new features

# ตรวจสอบ Tree Object
git cat-file -p xyz123
# Output:
# 100644 blob e69de29 README.md
# 100644 blob f1e4a23 app.js
# 040000 tree a3c15d1 src

# ตรวจสอบ Blob
git cat-file -p e69de29
# (เนื้อหา File)

# ตรวจสอบประเภท
git cat-file -t xyz123
# Output: tree

# ดูขนาด
git cat-file -s xyz123
# Output: 128

# ใช้ verify-pack เพื่อตรวจสอบ Packfile
git verify-pack .git/objects/pack/*.idx

# ดู Object Store
du -sh .git/objects/

ความสำคัญของ Object Model ต่อ Git Workflow และ Advanced Operations

ความเข้าใจเกี่ยวกับ Object Model ช่วยให้เข้าใจ Git ในระดับลึกมากขึ้น ตัวอย่างเช่น:

  • เข้าใจว่าเหตุใด Commit Hash มีความสำคัญและเหตุใดจึงไม่สามารถแก้ไข Commit ที่ยังไม่ได้ Push ได้โดยอัตโนมัติ
  • ทำความเข้าใจว่า Branch และ Tag ทำงานอย่างไร – พวกมันเป็น References ไปยัง Commits ที่อยู่ภายใน Object Database
  • เข้าใจการ Merge และ Rebase ทำงานอย่างไร – การสร้าง Commit ใหม่ที่ชี้ไปยัง Tree ใหม่
  • สามารถแก้ไข Advanced Issues ได้เช่น Detached HEAD – ซึ่งเป็นการชี้โดยตรงไปยัง Commit แทน Branch
  • สามารถกู้คืน Commits ที่ “หายไป” ได้โดยใช้ git reflog – เพราะ Objects ยังคงอยู่ใน Repository
  • เข้าใจวิธีการบีบอัด Repository ด้วย git gc – ซึ่งบรรจุ Loose Objects เข้ามาในไฟล์ Packfile
  • เข้าใจการป้องกันการ Corruption ของ Objects – เพราะแต่ละ Object มี SHA-1 Hash ที่คำนวณจากเนื้อหา
  • สามารถใช้ git filter-branch หรือ BFG เพื่อทำการ Rewrite History ได้อย่างเข้าใจ

Object Model คือรากฐานของทุกอย่างใน Git ดังนั้นการใช้เวลาทำความเข้าใจมันจึงเป็นการลงทุนที่สมควร แม้ว่าจะมีเครื่องมือ GUI ที่สะดวก แต่การเข้าใจพื้นฐานเหล่านี้จะช่วยให้คุณสามารถแก้ไขปัญหาที่ซับซ้อนได้และใช้ Git ได้อย่างเต็มศักยภาพ

ตัวอย่างขั้นสูง: Manual Object Inspection

สำหรับผู้ที่ต้องการทำความเข้าใจลึกลับมากขึ้น เราสามารถตรวจสอบไฟล์ Object โดยตรงในเครื่อง:

# ดูไฟล์ Loose Object ที่บันทึก
find .git/objects -type f

# ตัวอย่างเส้นทาง:
# .git/objects/4e/1243bd22c66e76c2ba9eddc1f91394e57f0731
#              ^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#            prefix (2 chars) + remainder

# ดู Packfile Object
ls .git/objects/pack/

# Extract Object จาก Packfile
git verify-pack -v .git/objects/pack/*.idx | head -20

# ดูข้อมูล Packfile
file .git/objects/pack/*.pack

# Unpack Objects
git unpack-objects < .git/objects/pack/pack-*.pack

# ดู Object Index
ls -la .git/objects/

สรุป

Git Object Model ประกอบด้วย Blob, Tree, Commit และ Tag ที่ทำงานร่วมกันเพื่อสร้างระบบจัดเก็บข้อมูลที่มีประสิทธิภาพและปลอดภัย การใช้ SHA-1 Hash ในการระบุ Objects เป็นพื้นฐานของความปลอดภัยและความสมบูรณ์ของข้อมูล ความเข้าใจลึกลับเกี่ยวกับ Object Model จะช่วยให้คุณใช้ Git ได้อย่างเต็มศักยภาพและสามารถแก้ไขปัญหาที่ซับซ้อนได้ การรู้จัก git cat-file และเครื่องมืออื่นๆ เป็นหนทางสู่การปรึกษาปัญหา Git ในระดับเชี่ยวชาญ