body { font-family: sans-serif; line-height: 1.6; margin: 0 auto; max-width: 800px; padding: 20px; color: #333; }
h2, h3 { color: #2c3e50; margin-top: 30px; }
pre { background-color: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; margin-bottom: 20px; }
code { font-family: ‘Courier New’, Courier, monospace; }
ul, ol { margin-bottom: 20px; }
strong { color: #2c3e50; }
a { color: #3498db; text-decoration: none; }
a:hover { text-decoration: underline; }
blockquote { border-left: 4px solid #6366f1; padding: 12px 20px; background: #f5f3ff; font-style: italic; margin: 20px 0; border-radius: 4px; }
.key-facts { background:#fffbeb;border-left:4px solid #f59e0b;padding:16px 20px;margin:20px 0;border-radius:6px;}
Git เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์ได้อย่างไร
Git stores your entire project in 41 bytes — ประโยคนี้อาจฟังดูเกินจริงไปมากสำหรับหลายคนที่เพิ่งเริ่มใช้ Git หรือแม้แต่คนที่ใช้มานานแล้วก็ตาม แต่เราขอบอกว่านี่คือความจริง โดยเฉพาะอย่างยิ่งถ้าคุณเข้าใจว่า Git ทำงานอย่างไรในระดับที่ลึกซึ้งจริงๆ บทความนี้จะพาคุณเจาะลึกเข้าไปในกลไกเบื้องหลังของ Git เพื่อเปิดเผยความลับว่าเครื่องมือควบคุมเวอร์ชัน (Version Control System) ที่ทรงพลังนี้ จัดเก็บข้อมูลโค้ดโปรเจกต์ทั้งหมดของคุณได้อย่างชาญฉลาดและมีประสิทธิภาพได้อย่างไร
- Git was created by Linus Torvalds in just 10 days during April 2005 after BitKeeper revoked free licenses
- Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier
- GitHub’s original codebase was written in Ruby on Rails by Tom Preston-Werner, Chris Wanstrath, and PJ Hyett in October 2007 with only $100,000 seed funding
ทำไมต้องเรียนรู้เรื่องนี้?
การเข้าใจการทำงานเบื้องหลังของ Git ไม่ใช่แค่การรู้ข้อเท็จจริงเท่ๆ เท่านั้น แต่มันคือรากฐานสำคัญที่จะช่วยให้คุณ:
- แก้ไขปัญหาได้ดีขึ้น: เมื่อคุณรู้ว่า Git เก็บข้อมูลอย่างไร คุณจะสามารถวินิจฉัยและแก้ไขปัญหา git ได้อย่างมีประสิทธิภาพมากขึ้น เช่น เมื่อเกิด Git conflicts หรือเมื่อต้องการกู้คืนเวอร์ชันเก่าๆ
- ใช้ Git ได้อย่างเต็มประสิทธิภาพ: คุณจะสามารถใช้คำสั่ง Git ขั้นสูงได้อย่างมั่นใจและเลือกใช้กลยุทธ์การทำงานร่วมกันที่เหมาะสมกับทีมของคุณ
- พัฒนาเป็นมืออาชีพ: ความรู้เชิงลึกนี้จะแยกคุณออกจากนักพัฒนาทั่วไป และทำให้คุณเป็นที่ปรึกษาด้าน Version Control ที่มีความเชี่ยวชาญ
- เข้าใจแนวคิดพื้นฐานด้านข้อมูล: Git เป็นตัวอย่างที่ยอดเยี่ยมของระบบที่ใช้การแฮช (hashing) และโครงสร้างข้อมูลแบบ Directed Acyclic Graph (DAG) ซึ่งเป็นแนวคิดสำคัญในวิทยาการคอมพิวเตอร์
Git ถูกใช้โดยนักพัฒนาซอฟต์แวร์ทั่วโลก ตั้งแต่โปรเจกต์เล็กๆ ไปจนถึงโปรเจกต์ขนาดใหญ่อย่าง Linux kernel ที่มีจำนวน commit มากกว่า 1.2 ล้าน commit (ณ ปี 2024) แต่ Git ก็ยังสามารถเดินทางย้อนกลับไปในประวัติศาสตร์ทั้งหมดได้ภายในเวลาไม่ถึง 3 วินาที ด้วยการเพิ่มประสิทธิภาพของ commit graph ซึ่งแสดงให้เห็นถึงความทนทานและประสิทธิภาพของมันอย่างแท้จริง การเรียนรู้กลไกที่อยู่เบื้องหลังจึงเป็นสิ่งที่ไม่ควรมองข้ามสำหรับใครที่ใช้ Git เป็นประจำ
สิ่งที่ต้องเตรียม
ก่อนที่เราจะเริ่มเจาะลึกในรายละเอียด สิ่งที่คุณจำเป็นต้องมีและควรรู้มีดังนี้:
- ความรู้พื้นฐานเกี่ยวกับ Git: คุณควรรู้จักคำสั่งพื้นฐานเช่น
git init,git add,git commit,git push,git pullและgit cloneบ้างแล้ว หากยังไม่คุ้นเคย ลองดูบทความอื่นๆ เกี่ยวกับ Coding บน AiDevThai.com เพื่อปูพื้นฐานได้เลย - ติดตั้ง Git: ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง Git ลงบนเครื่องของคุณแล้ว สามารถตรวจสอบได้โดยการเปิด Terminal หรือ Command Prompt แล้วพิมพ์
git --version - Terminal/Command Prompt: เราจะใช้คำสั่งต่างๆ ผ่านคอมมานด์ไลน์เป็นหลัก
- ความเข้าใจพื้นฐานเกี่ยวกับโครงสร้างไฟล์: คุณควรรู้จักโฟลเดอร์ ไฟล์ และการนำทางในระบบไฟล์
กลไกการทำงานของ Git ใน 8 ขั้นตอน
เราจะมาดูกันว่า Git เก็บข้อมูลได้อย่างไร โดยเริ่มจากขั้นตอนที่คุณคุ้นเคยกันดีอย่าง git add ไปจนถึงการ push โค้ดขึ้น GitHub
1. เมื่อ git add ทำงาน: การบีบอัดและสร้าง Blob Object
เมื่อคุณแก้ไขไฟล์ในโปรเจกต์ของคุณแล้วใช้คำสั่ง git add <filename>, Git จะไม่ได้แค่ “เพิ่ม” ไฟล์นั้นเข้าสู่ staging area แต่มันจะทำมากกว่านั้นเยอะเลย
- Git จะอ่านเนื้อหาของไฟล์ที่คุณระบุ
- Git จะบีบอัดเนื้อหาของไฟล์นั้นโดยใช้ Algorithm Zlib Deflate
- จากนั้น Git จะสร้างค่า SHA-1 hash จากข้อมูลที่ถูกบีบอัดนี้
- ผลลัพธ์ที่ได้คือ Blob Object ซึ่งเป็นวัตถุที่จัดเก็บเนื้อหาไฟล์ของคุณในรูปแบบที่บีบอัดและมีการแฮช
ตัวอย่าง: สมมติคุณมีไฟล์ hello.txt ที่มีข้อความ “Hello, Git!”
$ echo "Hello, Git!" > hello.txt
$ git add hello.txt
ตอนนี้ Git ได้สร้าง Blob Object สำหรับ hello.txt แล้ว แต่คุณยังไม่สามารถเห็นมันได้โดยตรงในโฟลเดอร์ .git/objects/ จนกว่าจะมีการ commit เกิดขึ้น (ในบางเวอร์ชัน Git อาจสร้าง Blob ทันทีเมื่อ add)
2. การจัดเก็บ Blob Object ใน .git/objects/
หลังจากที่ Git สร้าง SHA-1 hash ของ Blob Object แล้ว มันจะจัดเก็บ Blob นั้นไว้ในไดเรกทอรี .git/objects/
- Git จะนำ SHA-1 hash ที่เป็นค่าเริ่มต้น 40 ตัวอักษรมาแยก
- ตัวอักษร 2 ตัวแรกของ SHA-1 hash จะถูกใช้เป็นชื่อโฟลเดอร์
- ส่วนที่เหลือ 38 ตัวอักษรจะถูกใช้เป็นชื่อไฟล์ ภายในโฟลเดอร์นั้น
- โครงสร้างนี้ช่วยในการกระจายไฟล์ในระบบไฟล์เพื่อประสิทธิภาพที่ดีขึ้น เพราะ Git’s .git/objects directory uses the first 2 characters of SHA-1 hash as folder names, creating exactly 256 possible subdirectories to optimize filesystem performance
ตัวอย่าง: ถ้า SHA-1 ของ Blob คือ a0e8d022b7d4c8e7e1f2b3c4d5e6f7a8b9c0d1e2
Git จะสร้างไฟล์ที่ .git/objects/a0/e8d022b7d4c8e7e1f2b3c4d5e6f7a8b9c0d1e2 ซึ่งภายในไฟล์นี้คือเนื้อหาของ hello.txt ที่ถูกบีบอัดไว้
# ตัวอย่างการดูเนื้อหา Blob (ต้อง commit ก่อน)
# สมมติ SHA-1 ของ Blob ที่เราเพิ่ง add คือ 88d6b9...
$ git cat-file -p 88d6b9
# ผลลัพธ์:
# Hello, Git!
3. เมื่อ git commit ทำงาน: การสร้าง Tree Object
เมื่อคุณพอใจกับการเปลี่ยนแปลงและพร้อมที่จะบันทึกประวัติการทำงาน คุณจะใช้คำสั่ง git commit -m "Your commit message" ในขั้นตอนนี้ Git จะสร้าง Tree Object ขึ้นมา
- Tree Object ทำหน้าที่เป็น Snapshot ของไดเรกทอรีโปรเจกต์ของคุณ ณ เวลาที่ commit
- มันจะ “แมป” ชื่อไฟล์กับ SHA-1 hash ของ Blob Object ที่เกี่ยวข้อง
- หากมีไดเรกทอรีอื่นๆ อยู่ภายใน Tree Object ก็จะชี้ไปยัง Tree Object อื่นๆ เช่นกัน ทำให้เกิดโครงสร้างแบบลำดับชั้นคล้ายกับโครงสร้างไฟล์ปกติของเรา
- การสร้าง Tree Object นี้เกิดขึ้นจากการรวมไฟล์และโฟลเดอร์ทั้งหมดที่อยู่ใน staging area (index) เข้าด้วยกัน
ตัวอย่าง:
$ git commit -m "Add hello.txt"
Git จะสร้าง Tree Object ที่อาจมีลักษณะคล้ายนี้ (ในรูปแบบภายในของ Git):
# ตัวอย่างผลลัพธ์จาก git cat-file -p
# 100644 blob a0e8d022b7d4c8e7e1f2b3c4d5e6f7a8b9c0d1e2 hello.txt
บรรทัดนี้หมายถึง: โหมด 100644 (ไฟล์ปกติ), ประเภท blob, SHA-1 hash ของ Blob คือ a0e8d0..., ชื่อไฟล์คือ hello.txt
4. การสร้าง Commit Object: บันทึกข้อมูลการเปลี่ยนแปลง
หลังจาก Git สร้าง Tree Object แล้ว ขั้นตอนต่อไปคือการสร้าง Commit Object นี่คือหัวใจสำคัญของการบันทึกประวัติใน Git
- Commit Object จะเก็บข้อมูลสำคัญมากมายที่อธิบายถึง commit นั้นๆ ได้แก่:
- Tree hash: SHA-1 hash ของ Tree Object ที่ถูกสร้างในขั้นตอนที่แล้ว
- Parent commit hash: SHA-1 hash ของ Commit Object ก่อนหน้า (หากไม่ใช่ commit แรก) ทำให้เกิดการเชื่อมโยงเป็นลำดับ
- Author metadata: ชื่อและอีเมลของผู้เขียน
- Committer metadata: ชื่อและอีเมลของผู้ที่ commit (อาจเป็นคนเดียวกับผู้เขียนหรือต่างกันก็ได้ เช่น เมื่อใช้
git cherry-pick) - Timestamp: เวลาที่ commit ถูกสร้างขึ้น
- Commit message: ข้อความอธิบายการเปลี่ยนแปลงที่คุณใส่เข้ามา
Commit Object นี้คือสิ่งที่ทำให้เราสามารถย้อนกลับไปดูประวัติการเปลี่ยนแปลงทั้งหมดได้ โดยมันเป็นเหมือนจุดในประวัติศาสตร์ที่ชี้ไปยังสถานะของโปรเจกต์ในเวลานั้น
# ตัวอย่างผลลัพธ์จาก git cat-file -p
# tree 88d6b9d62d29f6de6640d249f3e430ae1ef6287c
# parent 30d2a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5
# author Jane Doe <jane.doe@example.com> 1678886400 +0700
# committer Jane Doe <jane.doe@example.com> 1678886400 +0700
#
# Add hello.txt
5. การสร้าง SHA-1 Hash ให้ Commit Object: ห่วงโซ่ที่ไม่มีวันเปลี่ยนแปลง
เมื่อ Commit Object ถูกสร้างเสร็จสมบูรณ์ Git จะดำเนินการสิ่งสำคัญที่สุดอย่างหนึ่งคือ:
- Git จะคำนวณ SHA-1 hash ของ Commit Object นั้นเองจากเนื้อหาทั้งหมด (รวมถึง tree hash, parent hash, author, timestamp และ commit message)
- Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier ซึ่งหมายความว่าทุก commit ที่คุณเห็นคือค่าแฮชขนาด 40 ตัวอักษร ที่บ่งชี้ถึงสถานะของโปรเจกต์ ณ เวลานั้นทั้งหมด รวมถึงประวัติที่นำมาถึงจุดนั้น
- จากนั้น Git จะจัดเก็บ Commit Object นี้ในโฟลเดอร์
.git/objects/ด้วยวิธีเดียวกับ Blob Object และ Tree Object (ใช้ 2 ตัวแรกของ SHA-1 เป็นชื่อโฟลเดอร์ และที่เหลือเป็นชื่อไฟล์)
สิ่งนี้สร้าง ห่วงโซ่การเข้ารหัสที่ไม่สามารถเปลี่ยนแปลงได้ (immutable cryptographic chain) เพราะถ้ามีข้อมูลใดๆ ใน Commit Object ถูกแก้ไข แม้เพียงเล็กน้อย SHA-1 hash ของ Commit นั้นก็จะเปลี่ยนไปทันที ซึ่งทำให้ Git มีความปลอดภัยและความน่าเชื่อถือสูงมากในการติดตามประวัติการเปลี่ยนแปลง คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับแนวคิดนี้ในบทความที่เกี่ยวข้องกับการทำงานของ โมเดล Deep Learning เรียนรู้จากข้อมูลได้อย่างไร ซึ่งมีหลักการบางอย่างที่คล้ายกันในการจัดการข้อมูลจำนวนมาก
Git was created by Linus Torvalds in just 10 days during April 2005 after BitKeeper revoked free licenses. นี่คือความเร็วในการพัฒนาที่น่าทึ่งสำหรับเครื่องมือที่มีอิทธิพลต่อโลกการเขียนโปรแกรมอย่างมาก!
6. การอัปเดต HEAD Reference: ชี้ไปยัง Commit ล่าสุด
หลังจากสร้าง Commit Object และ SHA-1 hash ของมันเสร็จเรียบร้อย Git จะอัปเดต HEAD reference pointer
- โดยปกติแล้ว
HEADจะชี้ไปยัง branch ที่คุณกำลังทำงานอยู่ (เช่นmasterหรือmain) - จากนั้น branch นั้นก็จะชี้ไปยัง SHA-1 hash ของ Commit Object ล่าสุดที่คุณเพิ่งสร้างไป
- ไฟล์
.git/refs/heads/[branch-name](เช่น.git/refs/heads/main) จะถูกอัปเดตด้วย SHA-1 hash ของ Commit Object ใหม่นี้
นี่คือเหตุผลว่าทำไมคุณถึงสามารถเห็น commit ล่าสุดของคุณเมื่อพิมพ์ git log การอัปเดตนี้ทำให้ Git รู้ว่าตอนนี้ repository ของคุณอยู่ที่ commit ใด
# ดูก่อน commit
$ cat .git/HEAD
# ผลลัพธ์: ref: refs/heads/main
$ cat .git/refs/heads/main
# ผลลัพธ์: 30d2a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5 (commit เก่า)
# หลัง commit และ HEAD ถูกอัปเดต
$ cat .git/refs/heads/main
# ผลลัพธ์: 88d6b9d62d29f6de6640d249f3e430ae1ef6287c (commit ใหม่)
7. เมื่อ git push ทำงาน: การส่งข้อมูลไป GitHub
เมื่อคุณทำงานเสร็จและต้องการแบ่งปันโค้ดของคุณกับคนอื่นบน GitHub หรือบริการ Git Hosting อื่นๆ คุณจะใช้คำสั่ง git push
- Git จะเปรียบเทียบ Object ต่างๆ ใน Local Repository ของคุณกับ Remote Repository บน GitHub
- Git จะคำนวณ Delta Compression: แทนที่จะส่งไฟล์ทั้งหมด Git จะส่งเฉพาะส่วนต่าง (delta) ของ Object ที่ยังไม่มีบน Remote Repository เท่านั้น
- ข้อมูลส่วนต่างเหล่านี้จะถูกจัดรวมกันเป็น Pack File เพื่อประสิทธิภาพในการส่งผ่านเครือข่าย ทั้งหมดนี้เกิดขึ้นผ่านโปรโตคอล HTTP หรือ SSH
การใช้ Delta Compression เป็นอีกหนึ่งเหตุผลหลักที่ทำให้ Git มีประสิทธิภาพสูงในการจัดการโปรเจกต์ขนาดใหญ่ เพราะมันช่วยลดปริมาณข้อมูลที่ส่งผ่านเครือข่ายได้อย่างมหาศาล และนี่คือหลักการที่ทำให้บางครั้งการ commit เพียงเล็กน้อยก็ส่งผลให้ Git เก็บโค้ดได้ทั้งโปรเจกต์โดยใช้พื้นที่ไม่มากเกินไป อย่างเช่นในบทความ <a href="https://aidevthai.com/git-%e0%b9%8
ปลั๊กอิน WordPress จากเรา: Exit Pop Pro
ป๊อปอัพ exit-intent ที่แจก PDF ฟรี แลกอีเมล — เก็บ subscriber เข้า WordPress ของคุณโดยตรง จ่ายครั้งเดียว $29 ไม่มีค่ารายเดือน ไม่ต้องง้อ SaaS