LEVEL 4 · ระดับเทพ
กลไกภายในของ Git
บทนี้คือเส้นแบ่งระหว่าง "ใช้ Git เป็น" กับ "เข้าใจ Git" เมื่อเห็นว่าข้างในมันเก็บข้อมูลอย่างไร คำสั่งทุกบทก่อนหน้าจะกระจ่างขึ้นพร้อมกัน และคำถามกวนใจอย่าง "ทำไม commit ถึงแก้ไม่ได้" หรือ "ทำไม branch ถึงสร้างเร็วจัง" จะมีคำตอบที่ชัดเจน
12.1 เปิดดูข้างใน .git/
โฟลเดอร์ .git/ ที่ init สร้างขึ้น ไม่ใช่กล่องดำ — มันคือฐานข้อมูลที่เปิดดูได้ ข้างในมี objects/ (ที่เก็บข้อมูลจริงทั้งหมด), refs/ (ป้าย branch และ tag), และไฟล์ HEAD หัวใจของทั้งหมดคือประโยคเดียว:
Git คือฐานข้อมูลที่ค้นด้วยเนื้อหา (content-addressable)
หมายความว่า Git เก็บทุกชิ้นข้อมูลโดยใช้ SHA ที่คำนวณจากเนื้อหานั้นเอง เป็นกุญแจ ให้เนื้อหา → ได้กุญแจ → เก็บ/หยิบด้วยกุญแจนั้น เนื้อหาเดียวกันได้กุญแจเดียวกันเสมอ จึงไม่มีวันเก็บซ้ำ
12.2 วัตถุสี่ชนิดที่ประกอบเป็น Git ทั้งหมด
ลองพิสูจน์ด้วยตาเอง — แกะ commit ออกมาดู:
$ git cat-file -p HEAD
tree a1b2c3... ← ภาพถ่ายโปรเจกต์ ณ commit นี้
parent 3b7d8c1... ← commit ก่อนหน้า
author Khaofang <...> 1718...
เพิ่มหน้า login12.3 ไขปริศนาที่ค้างคามาทั้งเล่ม
- ทำไม commit แก้ไม่ได้? เพราะ SHA ของมันคำนวณจากเนื้อหา (รวมถึง tree และ parent) แก้อะไรนิดเดียว SHA เปลี่ยน กลายเป็น commit คนละดวงทันที ของเดิมยังอยู่ — "แก้ประวัติ" จึงคือสร้างของใหม่มาแทน เสมอ
- ทำไม branch ถึงเบาและเร็ว? เพราะมันเป็นแค่ไฟล์ข้อความใน
refs/heads/ที่เก็บ SHA หนึ่งบรรทัด สร้าง branch = เขียนไฟล์ 40 ตัวอักษร ไม่ได้ก๊อปอะไรเลย - ทำไมไฟล์ที่ไม่เปลี่ยนถึงไม่กินที่เพิ่ม? เพราะ blob เดิมมี SHA เดิม commit ใหม่แค่ชี้ blob เดิมซ้ำ ไม่เก็บใหม่
- reflog/reset กู้ของได้เพราะอะไร? commit ที่ "หาย" แค่ไม่มีป้ายชี้ แต่ object ยังอยู่ใน
objects/จนกว่าจะถูกเก็บกวาด — รู้ SHA ก็ดึงกลับได้
12.4 packfiles — ทำไม repo ใหญ่ ๆ ถึงไม่บวม
ถ้าเก็บทุก blob แยกไฟล์จริง ๆ repo ที่มีประวัติยาวคงโตมหาศาล Git จึงบีบอัด object จำนวนมากเข้า packfile เดียวเป็นระยะ ๆ (ตอน gc หรือ push) โดยเก็บเฉพาะส่วนต่างระหว่าง object ที่คล้ายกัน — ได้ประโยชน์ของ snapshot ในการใช้งาน แต่ประหยัดที่แบบ diff ในการจัดเก็บ
✅ สรุปบทที่ 12 — Git = ฐานข้อมูลค้นด้วยเนื้อหา เก็บทุกอย่างด้วย SHA ของเนื้อหานั้น · วัตถุสี่ชนิด: blob (เนื้อไฟล์), tree (สารบบ), commit (tree + ผู้เขียน + parent), tag · commit แก้ไม่ได้เพราะ SHA ผูกกับเนื้อหา · branch เบาเพราะเป็นแค่ไฟล์เก็บ SHA · ของที่ "หาย" ยังอยู่จนถูกเก็บกวาด · packfile บีบอัดเพื่อประหยัดที่