<!DOCTYPE html>
<br> body { font-family: sans-serif; line-height: 1.6; margin: 0 auto; max-width: 800px; padding: 20px; color: #333; }<br> h2, h3 { color: #2c3e50; margin-top: 30px; }<br> pre { background-color: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; margin-bottom: 20px; }<br> code { font-family: 'Courier New', Courier, monospace; }<br> ul, ol { margin-bottom: 20px; }<br> strong { color: #2c3e50; }<br> a { color: #3498db; text-decoration: none; }<br> a:hover { text-decoration: underline; }<br> blockquote { border-left: 4px solid #6366f1; padding: 12px 20px; background: #f5f3ff; font-style: italic; margin: 20px 0; border-radius: 4px; }<br> .key-facts { background:#fffbeb;border-left:4px solid #f59e0b;padding:16px 20px;margin:20px 0;border-radius:6px;}<br>
<h2>Git เก็บโค้ดทั้งโปรเจกต์ใน 41 ไบต์ได้อย่างไร</h2>
<p>Git stores your entire project in 41 bytes — ประโยคนี้อาจฟังดูเกินจริงไปมากสำหรับหลายคนที่เพิ่งเริ่มใช้ Git หรือแม้แต่คนที่ใช้มานานแล้วก็ตาม แต่เราขอบอกว่านี่คือความจริง โดยเฉพาะอย่างยิ่งถ้าคุณเข้าใจว่า Git ทำงานอย่างไรในระดับที่ลึกซึ้งจริงๆ บทความนี้จะพาคุณเจาะลึกเข้าไปในกลไกเบื้องหลังของ Git เพื่อเปิดเผยความลับว่าเครื่องมือควบคุมเวอร์ชัน (Version Control System) ที่ทรงพลังนี้ จัดเก็บข้อมูลโค้ดโปรเจกต์ทั้งหมดของคุณได้อย่างชาญฉลาดและมีประสิทธิภาพได้อย่างไร</p>
<div class="key-facts" style="background:#fffbeb;border-left:4px solid #f59e0b;padding:16px 20px;margin:20px 0;border-radius:6px;"><strong>Key Facts ที่คนส่วนใหญ่ไม่รู้</strong>
<ul>
<li>Git was created by Linus Torvalds in just 10 days during April 2005 after BitKeeper revoked free licenses</li>
<li>Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier</li>
<li>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</li>
</ul>
</div>
<h3>ทำไมต้องเรียนรู้เรื่องนี้?</h3>
<p>การเข้าใจการทำงานเบื้องหลังของ Git ไม่ใช่แค่การรู้ข้อเท็จจริงเท่ๆ เท่านั้น แต่มันคือรากฐานสำคัญที่จะช่วยให้คุณ:</p>
<ul>
<li><strong>แก้ไขปัญหาได้ดีขึ้น:</strong> เมื่อคุณรู้ว่า Git เก็บข้อมูลอย่างไร คุณจะสามารถวินิจฉัยและแก้ไขปัญหา git ได้อย่างมีประสิทธิภาพมากขึ้น เช่น เมื่อเกิด Git conflicts หรือเมื่อต้องการกู้คืนเวอร์ชันเก่าๆ</li>
<li><strong>ใช้ Git ได้อย่างเต็มประสิทธิภาพ:</strong> คุณจะสามารถใช้คำสั่ง Git ขั้นสูงได้อย่างมั่นใจและเลือกใช้กลยุทธ์การทำงานร่วมกันที่เหมาะสมกับทีมของคุณ</li>
<li><strong>พัฒนาเป็นมืออาชีพ:</strong> ความรู้เชิงลึกนี้จะแยกคุณออกจากนักพัฒนาทั่วไป และทำให้คุณเป็นที่ปรึกษาด้าน Version Control ที่มีความเชี่ยวชาญ</li>
<li><strong>เข้าใจแนวคิดพื้นฐานด้านข้อมูล:</strong> Git เป็นตัวอย่างที่ยอดเยี่ยมของระบบที่ใช้การแฮช (hashing) และโครงสร้างข้อมูลแบบ Directed Acyclic Graph (DAG) ซึ่งเป็นแนวคิดสำคัญในวิทยาการคอมพิวเตอร์</li>
</ul>
<p>Git ถูกใช้โดยนักพัฒนาซอฟต์แวร์ทั่วโลก ตั้งแต่โปรเจกต์เล็กๆ ไปจนถึงโปรเจกต์ขนาดใหญ่อย่าง Linux kernel ที่มีจำนวน commit มากกว่า 1.2 ล้าน commit (ณ ปี 2024) แต่ Git ก็ยังสามารถเดินทางย้อนกลับไปในประวัติศาสตร์ทั้งหมดได้ภายในเวลาไม่ถึง 3 วินาที ด้วยการเพิ่มประสิทธิภาพของ commit graph ซึ่งแสดงให้เห็นถึงความทนทานและประสิทธิภาพของมันอย่างแท้จริง การเรียนรู้กลไกที่อยู่เบื้องหลังจึงเป็นสิ่งที่ไม่ควรมองข้ามสำหรับใครที่ใช้ Git เป็นประจำ</p>
<h3>สิ่งที่ต้องเตรียม</h3>
<p>ก่อนที่เราจะเริ่มเจาะลึกในรายละเอียด สิ่งที่คุณจำเป็นต้องมีและควรรู้มีดังนี้:</p>
<ul>
<li><strong>ความรู้พื้นฐานเกี่ยวกับ Git:</strong> คุณควรรู้จักคำสั่งพื้นฐานเช่น <code>git init</code>, <code>git add</code>, <code>git commit</code>, <code>git push</code>, <code>git pull</code> และ <code>git clone</code> บ้างแล้ว หากยังไม่คุ้นเคย ลองดูบทความอื่นๆ เกี่ยวกับ <a href="https://aidevthai.com/category/coding/">Coding</a> บน AiDevThai.com เพื่อปูพื้นฐานได้เลย</li>
<li><strong>ติดตั้ง Git:</strong> ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง Git ลงบนเครื่องของคุณแล้ว สามารถตรวจสอบได้โดยการเปิด Terminal หรือ Command Prompt แล้วพิมพ์ <code>git --version</code></li>
<li><strong>Terminal/Command Prompt:</strong> เราจะใช้คำสั่งต่างๆ ผ่านคอมมานด์ไลน์เป็นหลัก</li>
<li><strong>ความเข้าใจพื้นฐานเกี่ยวกับโครงสร้างไฟล์:</strong> คุณควรรู้จักโฟลเดอร์ ไฟล์ และการนำทางในระบบไฟล์</li>
</ul>
<h3>กลไกการทำงานของ Git ใน 8 ขั้นตอน</h3>
<p>เราจะมาดูกันว่า Git เก็บข้อมูลได้อย่างไร โดยเริ่มจากขั้นตอนที่คุณคุ้นเคยกันดีอย่าง <code>git add</code> ไปจนถึงการ push โค้ดขึ้น GitHub</p>
<h4>1. เมื่อ <code>git add</code> ทำงาน: การบีบอัดและสร้าง Blob Object</h4>
<p>เมื่อคุณแก้ไขไฟล์ในโปรเจกต์ของคุณแล้วใช้คำสั่ง <code>git add <filename></code>, Git จะไม่ได้แค่ "เพิ่ม" ไฟล์นั้นเข้าสู่ staging area แต่มันจะทำมากกว่านั้นเยอะเลย</p>
<ol>
<li>Git จะอ่านเนื้อหาของไฟล์ที่คุณระบุ</li>
<li><strong>Git จะบีบอัดเนื้อหาของไฟล์นั้นโดยใช้ Algorithm <a href="https://th.wikipedia.org/wiki/Zlib" rel="noopener">Zlib Deflate</a></strong></li>
<li>จากนั้น Git จะสร้างค่า <strong>SHA-1 hash</strong> จากข้อมูลที่ถูกบีบอัดนี้</li>
<li>ผลลัพธ์ที่ได้คือ <strong>Blob Object</strong> ซึ่งเป็นวัตถุที่จัดเก็บเนื้อหาไฟล์ของคุณในรูปแบบที่บีบอัดและมีการแฮช</li>
</ol>
<p><strong>ตัวอย่าง:</strong> สมมติคุณมีไฟล์ <code>hello.txt</code> ที่มีข้อความ "Hello, Git!"</p>
<pre><code>
$ echo "Hello, Git!" > hello.txt
$ git add hello.txt
ตอนนี้ Git ได้สร้าง Blob Object สำหรับ hello.txt แล้ว แต่คุณยังไม่สามารถเห็นมันได้โดยตรงในโฟลเดอร์ .git/objects/ จนกว่าจะมีการ commit เกิดขึ้น (ในบางเวอร์ชัน Git อาจสร้าง Blob ทันทีเมื่อ add)
<h4>2. การจัดเก็บ Blob Object ใน <code>.git/objects/</code></h4>
<p>หลังจากที่ Git สร้าง SHA-1 hash ของ Blob Object แล้ว มันจะจัดเก็บ Blob นั้นไว้ในไดเรกทอรี <code>.git/objects/</code></p>
<ol>
<li>Git จะนำ SHA-1 hash ที่เป็นค่าเริ่มต้น 40 ตัวอักษรมาแยก</li>
<li><strong>ตัวอักษร 2 ตัวแรกของ SHA-1 hash จะถูกใช้เป็นชื่อโฟลเดอร์</strong></li>
<li><strong>ส่วนที่เหลือ 38 ตัวอักษรจะถูกใช้เป็นชื่อไฟล์</strong> ภายในโฟลเดอร์นั้น</li>
<li>โครงสร้างนี้ช่วยในการกระจายไฟล์ในระบบไฟล์เพื่อประสิทธิภาพที่ดีขึ้น เพราะ <strong>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</strong></li>
</ol>
<p><strong>ตัวอย่าง:</strong> ถ้า SHA-1 ของ Blob คือ <code>a0e8d022b7d4c8e7e1f2b3c4d5e6f7a8b9c0d1e2</code></p>
<p>Git จะสร้างไฟล์ที่ <code>.git/objects/a0/e8d022b7d4c8e7e1f2b3c4d5e6f7a8b9c0d1e2</code> ซึ่งภายในไฟล์นี้คือเนื้อหาของ <code>hello.txt</code> ที่ถูกบีบอัดไว้</p>
<pre><code>
ตัวอย่างการดูเนื้อหา Blob (ต้อง commit ก่อน)
สมมติ SHA-1 ของ Blob ที่เราเพิ่ง add คือ 88d6b9...
$ git cat-file -p 88d6b9
ผลลัพธ์:
Hello, Git!
<h4>3. เมื่อ <code>git commit</code> ทำงาน: การสร้าง Tree Object</h4>
<p>เมื่อคุณพอใจกับการเปลี่ยนแปลงและพร้อมที่จะบันทึกประวัติการทำงาน คุณจะใช้คำสั่ง <code>git commit -m "Your commit message"</code> ในขั้นตอนนี้ Git จะสร้าง <strong>Tree Object</strong> ขึ้นมา</p>
<ol>
<li>Tree Object ทำหน้าที่เป็น Snapshot ของไดเรกทอรีโปรเจกต์ของคุณ ณ เวลาที่ commit</li>
<li>มันจะ "แมป" ชื่อไฟล์กับ SHA-1 hash ของ Blob Object ที่เกี่ยวข้อง</li>
<li>หากมีไดเรกทอรีอื่นๆ อยู่ภายใน Tree Object ก็จะชี้ไปยัง Tree Object อื่นๆ เช่นกัน ทำให้เกิดโครงสร้างแบบลำดับชั้นคล้ายกับโครงสร้างไฟล์ปกติของเรา</li>
<li>การสร้าง Tree Object นี้เกิดขึ้นจากการรวมไฟล์และโฟลเดอร์ทั้งหมดที่อยู่ใน staging area (index) เข้าด้วยกัน</li>
</ol>
<p><strong>ตัวอย่าง:</strong></p>
<pre><code>
$ 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
<h4>4. การสร้าง Commit Object: บันทึกข้อมูลการเปลี่ยนแปลง</h4>
<p>หลังจาก Git สร้าง Tree Object แล้ว ขั้นตอนต่อไปคือการสร้าง <strong>Commit Object</strong> นี่คือหัวใจสำคัญของการบันทึกประวัติใน Git</p>
<ol>
<li>Commit Object จะเก็บข้อมูลสำคัญมากมายที่อธิบายถึง commit นั้นๆ ได้แก่:
<ul>
<li><strong>Tree hash:</strong> SHA-1 hash ของ Tree Object ที่ถูกสร้างในขั้นตอนที่แล้ว</li>
<li><strong>Parent commit hash:</strong> SHA-1 hash ของ Commit Object ก่อนหน้า (หากไม่ใช่ commit แรก) ทำให้เกิดการเชื่อมโยงเป็นลำดับ</li>
<li><strong>Author metadata:</strong> ชื่อและอีเมลของผู้เขียน</li>
<li><strong>Committer metadata:</strong> ชื่อและอีเมลของผู้ที่ commit (อาจเป็นคนเดียวกับผู้เขียนหรือต่างกันก็ได้ เช่น เมื่อใช้ <code>git cherry-pick</code>)</li>
<li><strong>Timestamp:</strong> เวลาที่ commit ถูกสร้างขึ้น</li>
<li><strong>Commit message:</strong> ข้อความอธิบายการเปลี่ยนแปลงที่คุณใส่เข้ามา</li>
</ul>
</li>
</ol>
<p>Commit Object นี้คือสิ่งที่ทำให้เราสามารถย้อนกลับไปดูประวัติการเปลี่ยนแปลงทั้งหมดได้ โดยมันเป็นเหมือนจุดในประวัติศาสตร์ที่ชี้ไปยังสถานะของโปรเจกต์ในเวลานั้น</p>
<pre><code>
ตัวอย่างผลลัพธ์จาก 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
<h4>5. การสร้าง SHA-1 Hash ให้ Commit Object: ห่วงโซ่ที่ไม่มีวันเปลี่ยนแปลง</h4>
<p>เมื่อ Commit Object ถูกสร้างเสร็จสมบูรณ์ Git จะดำเนินการสิ่งสำคัญที่สุดอย่างหนึ่งคือ:</p>
<ol>
<li><strong>Git จะคำนวณ SHA-1 hash ของ Commit Object นั้นเองจากเนื้อหาทั้งหมด</strong> (รวมถึง tree hash, parent hash, author, timestamp และ commit message)</li>
<li><strong>Every Git commit hash is a SHA-1 generating exactly 40 hexadecimal characters plus 1 newline, totaling 41 bytes of identifier</strong> ซึ่งหมายความว่าทุก commit ที่คุณเห็นคือค่าแฮชขนาด 40 ตัวอักษร ที่บ่งชี้ถึงสถานะของโปรเจกต์ ณ เวลานั้นทั้งหมด รวมถึงประวัติที่นำมาถึงจุดนั้น</li>
<li>จากนั้น Git จะจัดเก็บ Commit Object นี้ในโฟลเดอร์ <code>.git/objects/</code> ด้วยวิธีเดียวกับ Blob Object และ Tree Object (ใช้ 2 ตัวแรกของ SHA-1 เป็นชื่อโฟลเดอร์ และที่เหลือเป็นชื่อไฟล์)</li>
</ol>
<p>สิ่งนี้สร้าง <strong>ห่วงโซ่การเข้ารหัสที่ไม่สามารถเปลี่ยนแปลงได้ (immutable cryptographic chain)</strong> เพราะถ้ามีข้อมูลใดๆ ใน Commit Object ถูกแก้ไข แม้เพียงเล็กน้อย SHA-1 hash ของ Commit นั้นก็จะเปลี่ยนไปทันที ซึ่งทำให้ Git มีความปลอดภัยและความน่าเชื่อถือสูงมากในการติดตามประวัติการเปลี่ยนแปลง คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับแนวคิดนี้ในบทความที่เกี่ยวข้องกับการทำงานของ <a href="https://aidevthai.com/%e0%b9%82%e0%b8%a1%e0%b9%80%e0%b8%94%e0%b8%a5-deep-learning-%e0%b9%80%e0%b8%a3%e0%b8%b5%e0%b8%a2%e0%b8%99%e0%b8%a3%e0%b8%b9%e0%b9%89%e0%b8%88%e0%b8%b2%e0%b8%81%e0%b8%82%e0%b9%89%e0%b8%ad%e0%b8%a1/">โมเดล Deep Learning เรียนรู้จากข้อมูลได้อย่างไร</a> ซึ่งมีหลักการบางอย่างที่คล้ายกันในการจัดการข้อมูลจำนวนมาก</p>
<blockquote>Git was created by Linus Torvalds in just 10 days during April 2005 after BitKeeper revoked free licenses. นี่คือความเร็วในการพัฒนาที่น่าทึ่งสำหรับเครื่องมือที่มีอิทธิพลต่อโลกการเขียนโปรแกรมอย่างมาก!</blockquote>
<h4>6. การอัปเดต HEAD Reference: ชี้ไปยัง Commit ล่าสุด</h4>
<p>หลังจากสร้าง Commit Object และ SHA-1 hash ของมันเสร็จเรียบร้อย Git จะอัปเดต <strong>HEAD reference pointer</strong></p>
<ol>
<li>โดยปกติแล้ว <code>HEAD</code> จะชี้ไปยัง branch ที่คุณกำลังทำงานอยู่ (เช่น <code>master</code> หรือ <code>main</code>)</li>
<li>จากนั้น branch นั้นก็จะชี้ไปยัง SHA-1 hash ของ Commit Object ล่าสุดที่คุณเพิ่งสร้างไป</li>
<li>ไฟล์ <code>.git/refs/heads/[branch-name]</code> (เช่น <code>.git/refs/heads/main</code>) จะถูกอัปเดตด้วย SHA-1 hash ของ Commit Object ใหม่นี้</li>
</ol>
<p>นี่คือเหตุผลว่าทำไมคุณถึงสามารถเห็น commit ล่าสุดของคุณเมื่อพิมพ์ <code>git log</code> การอัปเดตนี้ทำให้ Git รู้ว่าตอนนี้ repository ของคุณอยู่ที่ commit ใด</p>
<pre><code>
ดูก่อน commit
$ cat .git/HEAD
ผลลัพธ์: ref: refs/heads/main
$ cat .git/refs/heads/main
ผลลัพธ์: 30d2a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5 (commit เก่า)
หลัง commit และ HEAD ถูกอัปเดต
$ cat .git/refs/heads/main
ผลลัพธ์: 88d6b9d62d29f6de6640d249f3e430ae1ef6287c (commit ใหม่)
<h4>7. เมื่อ <code>git push</code> ทำงาน: การส่งข้อมูลไป GitHub</h4>
<p>เมื่อคุณทำงานเสร็จและต้องการแบ่งปันโค้ดของคุณกับคนอื่นบน GitHub หรือบริการ Git Hosting อื่นๆ คุณจะใช้คำสั่ง <code>git push</code></p>
<ol>
<li>Git จะเปรียบเทียบ Object ต่างๆ ใน Local Repository ของคุณกับ Remote Repository บน GitHub</li>
<li><strong>Git จะคำนวณ Delta Compression:</strong> แทนที่จะส่งไฟล์ทั้งหมด Git จะส่งเฉพาะส่วนต่าง (delta) ของ Object ที่ยังไม่มีบน Remote Repository เท่านั้น</li>
<li>ข้อมูลส่วนต่างเหล่านี้จะถูกจัดรวมกันเป็น <strong>Pack File</strong> เพื่อประสิทธิภาพในการส่งผ่านเครือข่าย ทั้งหมดนี้เกิดขึ้นผ่านโปรโตคอล HTTP หรือ SSH</li>
</ol>
<p>การใช้ Delta Compression เป็นอีกหนึ่งเหตุผลหลักที่ทำให้ Git มีประสิทธิภาพสูงในการจัดการโปรเจกต์ขนาดใหญ่ เพราะมันช่วยลดปริมาณข้อมูลที่ส่งผ่านเครือข่ายได้อย่างมหาศาล และนี่คือหลักการที่ทำให้บางครั้งการ commit เพียงเล็กน้อยก็ส่งผลให้ Git เก็บโค้ดได้ทั้งโปรเจกต์โดยใช้พื้นที่ไม่มากเกินไป อย่างเช่นในบทความ <a href="https://aidevthai.com/git-%e0%b9%8
Originally published on AI Dev Thai. Daily AI tutorials, coding guides, and tech insights in Thai.
Top comments (0)