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

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

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

Git เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์ได้อย่างไร: ไขปริศนา SHA-1 และระบบควบคุมเวอร์ชันที่อยู่เบื้องหลัง

Git stores your entire project in 41 bytes… ฟังดูเหลือเชื่อใช่ไหมครับ? ในฐานะนักพัฒนาซอฟต์แวร์และครูสอนโค้ดที่ AiDevThai.com ผมเข้าใจดีว่า Git เป็นเครื่องมือสำคัญที่นักพัฒนาทุกคนต้องรู้จัก แต่มีใครเคยสงสัยไหมว่ามันทำงานยังไงเบื้องลึก? ทำไมเราถึงบอกว่า Git สามารถ “เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์” ได้? บทความนี้จะพาทุกคนดำดิ่งไปในโลกของ Git ไขปริศนาของ SHA-1 และโครงสร้างลับที่ทำให้มันเป็นไปได้ รวมถึงกระบวนการตั้งแต่ 'git add' จนถึง 'git push' ที่คุณต้องรู้ เพื่อให้คุณเข้าใจ Git มากกว่าแค่คำสั่งที่ต้องพิมพ์

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 ไม่ใช่แค่เครื่องมือควบคุมเวอร์ชัน แต่เป็นกระดูกสันหลังของการพัฒนาซอฟต์แวร์สมัยใหม่ มันช่วยให้ทีมงานทำงานร่วมกันบนโค้ดเดียวกันได้อย่างราบรื่น ติดตามการเปลี่ยนแปลง ย้อนกลับไปเวอร์ชันก่อนหน้า และจัดการ Branch ต่างๆ ได้อย่างมีประสิทธิภาพ หากไม่มี Git การพัฒนาโปรเจกต์ขนาดใหญ่จะกลายเป็นความโกลาหลในทันที ลองจินตนาการว่าคุณต้องเขียนโค้ดกับเพื่อนร่วมงานอีก 5 คน โดยไม่มีวิธีติดตามว่าใครแก้ไฟล์ไหนไปแล้วบ้าง นั่นแหละคือฝันร้ายที่ Git เข้ามาช่วยแก้ปัญหาครับ

การเข้าใจการทำงานเบื้องหลังของ Git จะช่วยให้คุณแก้ไขปัญหาได้เมื่อเกิดข้อผิดพลาด และใช้งานมันได้อย่างมีประสิทธิภาพสูงสุด ไม่ว่าคุณจะเพิ่งเริ่มต้นเขียน Python ทำงานภายในอย่างไร หรือกำลังสร้าง SaaS ขายเอง ที่ซับซ้อน Git คือทักษะพื้นฐานที่ขาดไม่ได้

สิ่งที่ต้องเตรียม

  • ติดตั้ง Git: หากยังไม่มี สามารถดาวน์โหลดได้จาก git-scm.com
  • ความรู้พื้นฐาน Terminal/Command Line: การใช้งานคำสั่งพื้นฐาน
  • บัญชี GitHub (ทางเลือก): เพื่อทดลอง 'git push'
  • โปรเจกต์โค้ด (หรือสร้างใหม่): ไฟล์โค้ดง่ายๆ เพื่อใช้เป็นตัวอย่าง

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

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

  1. 'git add': การบีบอัดและสร้าง Blob Object

    เมื่อคุณใช้คำสั่ง git add <file> Git จะเริ่มทำงานโดยการ:

    • บีบอัดเนื้อหาไฟล์ของคุณ: Git ใช้ algorithms การบีบอัดข้อมูลแบบ zlib deflate เพื่อลดขนาดไฟล์ให้เล็กที่สุด นี่คือสาเหตุหนึ่งที่ Git มีประสิทธิภาพสูงในการจัดการพื้นที่เก็บข้อมูล
    • สร้าง SHA-1 Hash: จากนั้น Git จะทำการคำนวณ SHA-1 (Secure Hash Algorithm 1) hash จากเนื้อหาไฟล์ที่บีบอัดแล้วนี้
    • $ echo "Hello, world!" > hello.txt
      $ git init
      Initialized empty Git repository in /path/to/myrepo/.git/
      $ git add hello.txt
      $ find .git/objects -type f
      .git/objects/88/4a14ad6b71bf12d93e18a995e8424268e0d4c1

      คำอธิบายโค้ด:

      • echo "Hello, world!" > hello.txt: สร้างไฟล์ hello.txt พร้อมเนื้อหา
      • git init: เริ่มต้น Git repository ใหม่
      • git add hello.txt: เพิ่มไฟล์เข้าสู่ Staging Area ของ Git
      • find .git/objects -type f: ค้นหาไฟล์ object ที่ถูกสร้างขึ้นในไดเรกทอรี .git/objects. คุณจะเห็นไฟล์ที่มีชื่อเป็น SHA-1 hash 40 ตัวอักษร เช่น 88/4a14ad6b71bf12d93e18a995e8424268e0d4c1

      ผลลัพธ์: ไฟล์ที่ถูกบีบอัดนี้จะถูกเก็บเป็น "blob object" ภายในไดเรกทอรี .git/objects. ชื่อของไฟล์ object จะเป็น SHA-1 hash ของข้อมูลนั้นๆ โดย 2 ตัวแรกของ hash จะเป็นชื่อโฟลเดอร์ และอีก 38 ตัวที่เหลือเป็นชื่อไฟล์ สิ่งนี้ทำให้ Git สามารถจัดการไฟล์จำนวนมากได้อย่างรวดเร็ว เนื่องจาก 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

  2. 'git commit': การสร้าง Tree Object เพื่อเชื่อมโยงไฟล์

    หลังจากเพิ่มไฟล์เข้า Staging Area แล้ว เมื่อคุณใช้คำสั่ง git commit -m "Initial commit" Git จะสร้าง "tree object". Tree object เปรียบเสมือน Directory Listing ที่เก็บรายการของไฟล์และโฟลเดอร์ รวมถึง SHA-1 hash ของ blob objects (หรือ tree objects อื่นๆ ในกรณีที่เป็นโฟลเดอร์ย่อย) ที่อยู่ใน Commit นั้นๆ

    $ git commit -m "Add hello.txt"
    [master (root-commit) 63ea9e3] Add hello.txt
     1 file changed, 1 insertion(+)
     create mode 100644 hello.txt
    $ find .git/objects -type f
    .git/objects/63/ea9e30a213e4b779a5e4d2b27a854d9203673c
    .git/objects/88/4a14ad6b71bf12d93e18a995e8424268e0d4c1
    .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391c
    $ git cat-file -p 63ea9e30a213e4b779a5e4d2b27a854d9203673c
    tree 915234a66e6c1e5445218d6a8947b1968840742f
    author Your Name <your.email@example.com> 1678886400 +0700
    committer Your Name <your.email@example.com> 1678886400 +0700
    
    Add hello.txt
    

    คำอธิบายโค้ด:

    • git commit -m "Add hello.txt": สร้าง Commit ใหม่พร้อมข้อความ
    • find .git/objects -type f: ตอนนี้คุณจะเห็น object เพิ่มขึ้นมาอีก 2 ตัว (Tree Object และ Commit Object ที่เราจะพูดถึงในขั้นตอนถัดไป)
    • git cat-file -p <commit-hash>: ใช้ดูเนื้อหาของ Commit Object (ผลลัพธ์ย่อส่วน ไม่แสดง Tree Hash)

    ผลลัพธ์: Tree Object จะมี SHA-1 hash เป็นของตัวเอง และจะชี้ไปยัง blob hash ของ hello.txt Git จะสร้าง tree object that maps filenames to their blob SHA-1 hashes in a hierarchical directory structure

  3. 'git commit': การสร้าง Commit Object เชื่อมโยงทุกสิ่ง

    ทันทีที่คุณ Commit Git จะสร้าง "commit object" ซึ่งเป็นหัวใจสำคัญของ Commit นั้นๆ Commit object จะประกอบด้วย:

    • Tree Hash: SHA-1 hash ของ tree object ที่เกี่ยวข้องกับ Commit นี้
    • Parent Commit Hash: SHA-1 hash ของ Commit ก่อนหน้า (ถ้ามี) ซึ่งสร้างเป็นสายโซ่ประวัติการเปลี่ยนแปลง
    • Author Metadata: ชื่อผู้แต่ง, อีเมล, เวลาที่เขียนโค้ด
    • Committer Metadata: ชื่อผู้ Commit, อีเมล, เวลาที่ Commit
    • Commit Message: ข้อความอธิบายการเปลี่ยนแปลงของ Commit นั้นๆ
    $ git cat-file -p $(git rev-parse HEAD)
    tree 915234a66e6c1e5445218d6a8947b1968840742f
    author Your Name <your.email@example.com> 1678886400 +0700
    committer Your Name <your.email@example.com> 1678886400 +0700
    
    Add hello.txt
    

    คำอธิบายโค้ด:

    • git rev-parse HEAD: ใช้เพื่อหา SHA-1 hash ของ Commit ล่าสุด
    • git cat-file -p <commit-hash>: แสดงเนื้อหาของ Commit object มันจะแสดง Tree hash, ข้อมูลผู้แต่ง, ผู้ Commit และ Commit message

    ผลลัพธ์: Commit object จะมี SHA-1 hash เป็นของตัวเอง ซึ่งเป็นตัวระบุ Commit ที่ไม่ซ้ำกัน สี่สิบตัวอักษรของ SHA-1 hash นี้คือ "40 ไบต์" ที่เราพูดถึง (บวก 1 ไบต์สำหรับ newline ในทางเทคนิค)

  4. การคำนวณ SHA-1 Hash ของ Commit Object

    The commit object gets its own SHA-1 hash calculated from all its content, creating an immutable cryptographic chain นี่คือหัวใจสำคัญที่ทำให้ Git แข็งแกร่ง Hash นี้ไม่ได้คำนวณจากเนื้อหาไฟล์โดยตรง แต่คำนวณจากข้อมูลใน commit object ทั้งหมด (tree hash, parent hash, author, committer, message) หากมีการเปลี่ยนแปลงแม้แต่ตัวอักษรเดียวในข้อมูลเหล่านี้ SHA-1 hash ของ Commit จะเปลี่ยนไปทันที ทำให้ Commit ไม่สามารถเปลี่ยนแปลงได้ (immutable) และสามารถตรวจสอบความถูกต้องของประวัติการเปลี่ยนแปลงทั้งหมดได้

    Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier. เป็นเอกลักษณ์ที่ไม่ซ้ำกัน เปรียบเสมือนลายนิ้วมือของสถานะโปรเจกต์ทั้งหมด ณ เวลานั้น

  5. การอัปเดต HEAD Reference

    หลังจาก Commit สำเร็จ Git จะอัปเดต HEAD reference ในไฟล์ .git/refs/heads/[branch-name] (เช่น .git/refs/heads/master หรือ .git/refs/heads/main) ให้ชี้ไปยัง SHA-1 hash ของ Commit ใหม่ล่าสุด นี่คือวิธีที่ Git รู้ว่า Commit ไหนคือ "ปัจจุบัน" ของ Branch นั้นๆ

    $ cat .git/HEAD
    ref: refs/heads/master
    $ cat .git/refs/heads/master
    63ea9e30a213e4b779a5e4d2b27a854d9203673c
    

    คำอธิบายโค้ด:

    • cat .git/HEAD: แสดงว่า HEAD ชี้ไปที่ Branch ไหน
    • cat .git/refs/heads/master: แสดง SHA-1 hash ของ Commit ล่าสุดบน Branch master
  6. 'git push': การส่งข้อมูลไปยัง GitHub

    เมื่อคุณใช้คำสั่ง git push origin master หรือ git push origin main เพื่อส่งโค้ดไปยัง GitHub (หรือ Remote Repository อื่นๆ) Git จะทำการ:

    • Delta Compression: Git ไม่ได้ส่งไฟล์ทั้งหมดไปใหม่ทุกครั้ง แต่มันจะคำนวณ delta compression หรือส่วนต่างระหว่าง object ที่มีอยู่แล้วบน Remote กับ object ใหม่ใน Local ของคุณ และส่งไปเฉพาะส่วนที่เปลี่ยนแปลงเท่านั้น ทำให้การ Push ทำได้รวดเร็วและใช้แบนด์วิธน้อยลงมาก
    • Pack File: Delta compression objects จะถูกรวมอยู่ใน pack file ซึ่งเป็นรูปแบบไฟล์ที่ถูกบีบอัดอย่างมีประสิทธิภาพสูงสุด
    • การตรวจสอบบน GitHub: GitHubReceives the pack file, verifies SHA-1 integrity of all objects, then updates the remote branch reference atomically การตรวจสอบ SHA-1 integrity นี้สำคัญมากเพื่อให้มั่นใจว่าข้อมูลไม่เสียหายระหว่างการส่ง และไม่มีใครแก้ไขประวัติ Commit ได้โดยไม่ถูกตรวจจับ

    หากคุณอยากรู้ว่าแพลตฟอร์มอย่าง GitHub สร้างรายได้อย่างไร ลองดูบทความ หาเงินจาก Freelance บน Upwork/Fiverr สำหรับ Dev ไทย ซึ่งหลายงานมักจะเกี่ยวข้องกับการใช้ Git/GitHub ด้วย

สรุปภาพรวม: Git เก็บทั้งโปรเจกต์ใน 41 ไบต์ ได้อย่างไร

Git บรรลุ "การเก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์" ได้เนื่องจากหลักการที่เป็น Directed Acyclic Graph (DAG) และ Content-Addressable Storage:

📺 YouTube📘 Facebook