Version Control and Git From Zero to Hero : Part 6 (แนวคิดของ Branch)

บทความโดย ผศ.ดร.ณัฐโชติ พรหมฤทธิ์
ภาควิชาคอมพิวเตอร์
คณะวิทยาศาสตร์
มหาวิทยาลัยศิลปากร

Version Control System เกือบทุกตัวจะมี Branch Feature ให้ใช้งานในรูปหนึ่งรูปแบบใด แต่การแตก Branch ใน Version Control System เหล่านั้นค่อนข้างมีค่าใช้จ่ายที่สูงเหมือนกับการทำสำเนา Source Code ทั้ง Folder ยิ่ง Project มีขนาดใหญ่ยิ่งใช้เวลาในการสร้าง Branch หลายวินาที หรือเป็นนาที แต่ Branch ใน Git เป็นอะไรที่แตกต่างกัน การสร้าง Branch ของ Git นั้นรวดเร็วอย่างไม่น่าเชื่อ และใช้ทรัพยากรน้อยกว่า

Git สนับสนุนให้ Software Developers สร้าง Branch/สลับ Branch ไปมา และ Merge Branch บ่อยๆ เท่าที่จะทำได้ในแต่ละวัน บางคนบอกว่า Branch ของ Git คือ Killer Feature

ดังนั้นการใช้งาน Branch ได้คล่องแคล่วจะทำให้ Software Developers มีเครื่องมือที่ทรงพลังเปรียบเสมือนกับ Skywalker หนุ่มที่มีดาบ Lightsaber ซึ่งจะทำให้มีการเปลี่ยนแปลงวิธีการพัฒนา Software ไปจากเดิมอย่างสิ้นเชิงครับ

Spore Drive

ภาพจาก https://solarsystem.nasa.gov/resources/925/solar-system-and-beyond-poster-set/

เพื่อให้เห็นภาพการทำงานกับ Branch จะขอเปรียบเทียบ Branch เป็นดังจุดบนสุดของ Timeline ในจักรวาลคู่ขนานที่มี Timeline มากมาย เมื่อเราใช้คำสั่ง git log เราจะเห็น History หรือลำดับของ Commit หรือจุดต่างๆ บน Timeline ซึ่งเราสามารถเดินทางไปยังตามจุดเหล่านั้นได้เหมือนที่ยาน Discovery ใช้ Spore Drive เดินทางข้ามอวกาศอันไกลโพ้นที่มีโครงข่ายของราอวกาศ หรือ Mycelial Network กระจายอยู่ได้ในพริบตาเพียงแค่ใช้คำสั่ง git checkout  ซึ่ง ณ จุดที่เราไปถึงก็จะเป็นเวลาปัจจุบันที่เราจะพบเจอเหตุการณ์ ผู้คน และสิ่งต่างๆ ใน Version ตามที่เราเคย Commite ไว้

เราสามารถเดินทางสลับไปมายังจุดบนสุดของแต่ละ Timeline (สลับไปมายัง Branch ต่างๆ ที่สร้างไว้) แล้วดำเนินชีวิตในแบบที่เราอยากจะเป็น และบันทึกมันเก็บไว้เป็น Snapshots โดยการสร้าง Commit ใหม่เป็น Commit ล่าสุดบน Timeline

Three Type of Objects

สมมติเรามีไฟล์อยู่ 3 ไฟล์ คือ README test.rb และ LICENSE ใน Git Folder เมื่อเรา Check-In ทั้ง 3 ไฟล์ลง Database ด้วยคำสั่ง git add และ git commit แล้ว Git จะสร้าง Object ที่ชื่อว่า Blob ทั้งหมด 3 Blobs ซึ่งเก็บ Content ของไฟล์ 3 ไฟล์ และสร้าง Object ที่ชื่อว่า Tree 1 Tree เก็บรายการของ Content ทั้งหมด รวมทั้งสร้าง Object ชื่อว่า Commit 1 Commit เก็บข้อมูลการ Commit และ Pointer ที่ชี้ไปยัง Tree ดังกล่าว

git add README test.rb LICENSE
git commit -m 'The initial commit of my project'
ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

Companion

เมื่อเราแก้ไข Code แล้ว Check-In อีกครั้ง Commit ใหม่ที่เกิดขึ้นมาก็จะเก็บ Pointer ที่ชี้ไปยัง Commit ก่อนหน้า ดังภาพด้านล่าง

ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

Branch คือ Pointer ที่สามารถเคลื่อนที่ไปยัง Commit บนสุดของ Timeline โดย Git จะสร้าง Branch ชื่อ Master เป็น Branch Default เมื่อมีการ Commit ในครั้งแรก

ทุกครั้งที่เราสร้าง Commit ขึ้นมาใหม่ Master Branch Pointer จะเคลื่อนไปข้างหน้า (Move Forward) โดยอัตโนมัติ ซึ่งจะทำให้มันชี้ไปยัง Commit บนสุดของ Timeline เสมอ นอกจากนี้มันยังมี HEAD Pointer เป็นคู่เกลอที่ชี้ไปยัง Master Branch ที่เรากำลัง Check-Out ด้วย

ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

Creating a New Branch

สิ่งที่เกิดขึ้นเมื่อเราสร้าง Branch ใหม่ชื่อ Testing ก็คือ Git จะสร้าง Testing Pointer ที่ชี้ไปยัง Commit เดิมที่ Master Pointer ชี้อยู่ โดยคำสั่งด้านล่างคือคำสั่งในการสร้าง Branch

git branch testing
ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

ซึ่งขณะนี้แต่ละ Branch Pointer ยังคงอยู่บน Timeline เดียวกัน และ Branch ปัจจุบันยังคงเป็น Master Branch เพราะ HEAD Pointer ยังคงอยู่ที่นี่

ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

Switching Branches

เมื่อเราใช้คำสั่ง git checkout จะทำให้ HEAD pointer เคลื่อนตัวไปยัง Testing Branch ดังภาพด้านล่าง

git checkout testing
ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

สมมติเราแก้ไข Code ในไฟล์ test.rb แล้ว Check-In สิ่งที่เกิดขึ้นก็คือ Testing Pointer และ HEAD Pointer คู่เกลอจะเคลื่อนตัวไปข้างหน้ายัง Commit ใหม่ ขณะที่ Master Pointer ยังอยู่ที่เดิม

vi test.rb
git commit -a -m 'made a change'
ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

การสลับไปมาระหว่าง Branch มายัง Master Branch เป็นเรื่องที่ทำได้ง่ายๆ โดยใช้คำสั่ง git checkout ซึ่งจะทำให้ HEAD Pointer เคลื่อนตัวกลับมายัง Master Pointer

git checkout master
ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

การสลับมายัง Master Branch นอกจากจะทำให้ HEAD Pointer เคลื่อนที่แล้ว ไฟล์และ Folder ต่างๆ ใน Working Directory จะถูกเปลี่ยนกลับมาเป็น Version ที่เรา Commit ไว้ด้วย

New Timeline

ทีนี้ถ้าเราแก้ไข Code ในไฟล์ test.rb แล้ว Check-In ที่ Master Branch ทั้ง HEAD Pointer และ Master Pointer จะเคลื่อนตัวไปข้างหน้ายัง Commit ล่าสุด ซึ่งจะทำให้เกิดการแยกตัวออกเป็น 2 Timeline ดังภาพครับ

ภาพและตัวอย่างจาก https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell

ตอนนี้เรามี Source Code อยู่ 2 Timeline การ Merge Branch จึงเป็นสิ่งสำคัญเมื่อมีการทำงานร่วมกันเป็นทีมเพื่อส่ง Source Code ที่แก้ไขไปยัง Branch หลัก

การสร้าง Branch และลบ Branch นั้นมีค่าใช้จ่ายที่ถูกมากครับ เพราะความจริงแล้ว Branch จะเก็บข้อมูลอักขระเพียง 40 ตัวอักษร ที่เป็น SHA-1 Checksum ของ Commit ที่มันชี้อยู่นั่นเอง

ขอขอบคุณ Nipa.Cloud ที่ให้การสนับสนุน Environment ในการเรียนการสอน
รายวิชา Dev-Ops and Cloud Engineering 101