Git เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์ได้อย่างไร

AI Dev Thai
AI Dev Thaiรีวิว AI · สอน Coding · หาเงินจาก Tech

Git เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์ได้อย่างไร

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) ที่ทรงพลังนี้ จัดเก็บข้อมูลโค้ดโปรเจกต์ทั้งหมดของคุณได้อย่างชาญฉลาดและมีประสิทธิภาพได้อย่างไร

Key Facts ที่คนส่วนใหญ่ไม่รู้

  • 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 แต่มันจะทำมากกว่านั้นเยอะเลย

  1. Git จะอ่านเนื้อหาของไฟล์ที่คุณระบุ
  2. Git จะบีบอัดเนื้อหาของไฟล์นั้นโดยใช้ Algorithm Zlib Deflate
  3. จากนั้น Git จะสร้างค่า SHA-1 hash จากข้อมูลที่ถูกบีบอัดนี้
  4. ผลลัพธ์ที่ได้คือ 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/

  1. Git จะนำ SHA-1 hash ที่เป็นค่าเริ่มต้น 40 ตัวอักษรมาแยก
  2. ตัวอักษร 2 ตัวแรกของ SHA-1 hash จะถูกใช้เป็นชื่อโฟลเดอร์
  3. ส่วนที่เหลือ 38 ตัวอักษรจะถูกใช้เป็นชื่อไฟล์ ภายในโฟลเดอร์นั้น
  4. โครงสร้างนี้ช่วยในการกระจายไฟล์ในระบบไฟล์เพื่อประสิทธิภาพที่ดีขึ้น เพราะ 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 ขึ้นมา

  1. Tree Object ทำหน้าที่เป็น Snapshot ของไดเรกทอรีโปรเจกต์ของคุณ ณ เวลาที่ commit
  2. มันจะ “แมป” ชื่อไฟล์กับ SHA-1 hash ของ Blob Object ที่เกี่ยวข้อง
  3. หากมีไดเรกทอรีอื่นๆ อยู่ภายใน Tree Object ก็จะชี้ไปยัง Tree Object อื่นๆ เช่นกัน ทำให้เกิดโครงสร้างแบบลำดับชั้นคล้ายกับโครงสร้างไฟล์ปกติของเรา
  4. การสร้าง 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

  1. 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 จะดำเนินการสิ่งสำคัญที่สุดอย่างหนึ่งคือ:

  1. Git จะคำนวณ SHA-1 hash ของ Commit Object นั้นเองจากเนื้อหาทั้งหมด (รวมถึง tree hash, parent hash, author, timestamp และ commit message)
  2. Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier ซึ่งหมายความว่าทุก commit ที่คุณเห็นคือค่าแฮชขนาด 40 ตัวอักษร ที่บ่งชี้ถึงสถานะของโปรเจกต์ ณ เวลานั้นทั้งหมด รวมถึงประวัติที่นำมาถึงจุดนั้น
  3. จากนั้น 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

  1. โดยปกติแล้ว HEAD จะชี้ไปยัง branch ที่คุณกำลังทำงานอยู่ (เช่น master หรือ main)
  2. จากนั้น branch นั้นก็จะชี้ไปยัง SHA-1 hash ของ Commit Object ล่าสุดที่คุณเพิ่งสร้างไป
  3. ไฟล์ .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

  1. Git จะเปรียบเทียบ Object ต่างๆ ใน Local Repository ของคุณกับ Remote Repository บน GitHub
  2. Git จะคำนวณ Delta Compression: แทนที่จะส่งไฟล์ทั้งหมด Git จะส่งเฉพาะส่วนต่าง (delta) ของ Object ที่ยังไม่มีบน Remote Repository เท่านั้น
  3. ข้อมูลส่วนต่างเหล่านี้จะถูกจัดรวมกันเป็น 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

ดูรายละเอียด →
📺 YouTube📘 Facebook