วันพฤหัสบดีที่ 7 กันยายน พ.ศ. 2560

Basic Git part 7

Git Branching

ลองดูผลของ git status ที่ผ่านมา สังเกตไหมว่า เราอยู่ที่ branch ชื่อ master เอ๋มันคืออะไรน้าาา?


"จากข้อความของ git status ข้างต้น branch ที่เราสนใจอยู่นี้มีชื่อว่า master คือต้องบอกเพื่อนๆว่า สมบัติอย่างหนึ่งของ git ก็คือการแตกสาขาการพัฒนาออกไปอย่างกว้างขวาง กล่าวคือ สมมติเพื่อนๆมี project ที่ต้องคนมากกว่าหนึ่งคนร่วมกันพัฒนา และพัฒนากันคนละส่วน (ไม้ในไฟล์เดียวกัน) เพื่อนๆสามารถแยก branch ของ project นี้ออกเป็นหลายแขนงได้ และให้แต่ละแขนงพัฒนาโค้ดในส่วนของตัวเองไปเรื่อยๆ โดยไม่ต้องห่วงว่ามันจะไปกระทบแขนงอื่น ทำให้เราพัฒนางานไฟล์เดียวกันได้ในหลายส่วนในเวลาเดียวกัน !!! ฮั่นเช้ สุดท้ายเจ้าแขนงก็จะประกอบรวมกลับเขามาใน branch เดิม นี่จึงเรียกว่าเป็นหนึ่งข้อดีที่ดีงามล้ำเลิศ"

"เรื่องนี้ก็คือการแตก branch หรือกิ่งสาขาออกไปเพื่อจัดการกับปัญหาที่เกิด หรือบางที่อาจใช้คำว่าแบ่งงานกันทำก็ได้ ในขณะที่เวลาของพวกเขาเดินไปพร้อมๆกัน"

ทบทวนกันก่อนนะ

เพื่อนๆจำกันได้ใช่ไหม git ไม่เก็บ ความแตกต่าง ของไฟล์ที่ถูกแก้ไขไปแล้ว (doesn't store data as a series of change-sets or differences) แต่มันเก็บไฟล์ที่ถูกแก้นั้นเป็น series of snapshots

การ commit ลงถังแต่ละครั้งเพื่อนๆก็ทราบแล้วว่าจะมีปมเกิดขึ้น (เห็นใน source tree) ปมเหล่านั้นก็คือ snapshot ของไฟล์ที่ถูกเปลี่ยนแปลงในสถานะ staged

พูดกันให้ละเอียดคือ git จะสร้าง object ขึ้นมาตัวหนึ่งเพื่อเก็บ meta data สำคัญเพื่อใช้อ้างอิงไปยัง snapshot ต่างๆ ซึ่ง object ดังกล่าวนี้จะเก็บชื่อผู้ทำ (author's name) แล้วก็ email ของเขา เราจะได้รู้ไงว่าใครเป็นคน committed


นอกจากนี้ยังเก็บ message ที่เราเคยพิมพ์ไปว่า -m ลงไปด้วย เพื่อใช้อธิบายว่าการ commiit ครั้งนี้เกี่ยวกับอะไร หรือทำอะไรก็ว่าไป

ขออธิบายด้วยภาพนะครับ สมมตินี่เป็นการ commit ครั้งเดียว โดยคุณที่ชื่อ Scott และเขาเขียน description ว่า The initial commit of my project


ส่วนตัวเลขสมมติที่เขียนว่า 92ec2 นั้นเป็น pointer เพื่อชี้ไปว่ามันกำลังให้ความสำคัญกับสิ่งอื่นและ 98ca9 ด้านบนสุดนั้นคือตัวมันบนหน่วยความจำหลัก (RAM)

ในตัวอย่างเขามีไฟล์อยู่สามไฟล์ ได้แก่
- README
- test.rb
- LICENSE

จากนั้นเพื่อนๆก็ส่งมันเข้าไปใน staging area การณ์นี้ git จะสร้าง checksum หรือก็คืออัลกอริทึม SHA-1 ขึ้นคำนวณในแต่ละ sub directory (folder ย่อยต่างๆ) ซึ่งไม่มีทางซ้ำกัน เท่ากับว่าได้สร้าง version ถัดไปเกิดขึ้น ด้วยทั้งหมดนี้เก็บใน git repository

ง่ายๆคือ เราสร้างไฟล์ขึ้นมาสามไฟล์แล้ว commit มันลงถัง ไฟล์เหล่านี้จะมีชนิดเป็น blob ให้หน้าตาของทั้งสามไฟล์ที่ถูกจัดการเป็น blob แล้วในถังดังนี้


ส่วนใน staging area ก็มี snapshot เกิดขึ้น (ไม่แน่ใจว่าเกือบจะพร้อมกัน) มันก็จะสร้าง root project tree ด้วย ดังนี้


เจ้า snapshot ที่เกิดก็จะมี pointer อ้างอิงไปยัง blob ทั้งสาม ส่วนตัวเองนั้นก็ถูก pointer อ้างอิงมาจาก commit object รวมกันเป็นภาพใหญ่อย่างนี้


สรุปว่าภาพนี้คือการ commit หนึ่งครั้งกับไฟล์สามไฟล์
- เกิด commit object 1 object สีขาว
- เกิด root project tree  ซึ่งจะถูกทำเป็น snapshot เก็บเป็น version ไว้ สีเขียว
- ไฟล์ทั้งสามถูกจัดเก็บแบบ blob สีส้มๆ

***เพิ่มเติม
เราพูดถึง checksum ถูกต้องไหม ซึ่งจะกระทำทุกครั้งเมื่อมีไฟล์ถูกเลือกให้ staged ใน staging area และโดยหลักการทั่วไปแล้วไฟล์เหล่านั้นก็มีแต่จะเพิ่มขึ้นเรื่อยๆ ส่วนตัวก็ยังไม่รู้ว่าการ re-create สร้าง snapshot เกี่ยวข้องอย่างไรกับ root project tree แต่เอาเป็นว่า git จะสร้าง snapshot ขึ้นตรงนี้แหละครับ

สมมติว่าเพื่อนอ้อย ยังคงทำงานกับตัวอย่างนี้ต่อไปแล้ว commit เป็นครั้งที่สอง ก็จะเกิดภาพลักษณะแบบนี้ (ซ้ายสุดคือครั้งแรกที่ commit)


เห็นไหม commit ในครั้งที่สองจะชี้ไปที่ commit ในครั้งแรก สักเกตที่ matadata ชื่อ parent จะเป็นตัวบอกว่า commit ก่อนหน้าคือใคร

และหากเพื่อน commit เป็นครั้งที่สามล่ะ ?


ทีนี้ก็มาถึงเรื่อง branch กันบ้าง จำได้ไหมทุกครั้งที่เราเรียก git status มันจะบอกว่าเรากำลังทำงานอยู่ที่ branch อะไร อะดู

อะแต่เดี๋ยวกัน (ถ้าท่านโทรมาในสิบสายนี้) อะ ผมจะลองเล่น gi gui หน่อย ดุว่าหน้าตามันเป็นอย่างไร แต่พอดูแล้ว ผมก็อยากดูหน้าตาของ git bash





เห็นไหม มันบอกว่าเราอยู่ที่ branch ชื่อ master และเมื่อเราย่อภาพจำลอง commit object ลงให้เป็นแบบนี้ เพื่อนๆดูนะ ว่า master branch เราอยู่ตรงไหน


ตำราบอกว่า master branch นั้นจะ move forward ไปเรื่อยๆกับ commit ล่าสุด ดังนั้นตัวมันจะชี้ไปที่ commit ชื่อ f30ab นะครับ โดยตรงนี้เมื่อทำ snapshot ก็มีหมายเลขเวอร์ชันเกิดขึ้นด้วยอยู่แล้ว


ใครที่เคยเขียน data structrue (โครงสร้างข้อมูล) อารมณ์มันก็คือ LinkedList ตัวหนึ่งที่ถูก desgin ต่างออกไป

ทีนี้การจะแบ่ง branch นั้นเราจะดูว่า pointer ที่ชื่อ header นั้นกำลังชี้ที่ branch อะไร โดยธรรมดาแล้ว header pointer นั้นจะชี้ master branch ไว้เสมอ (เพราะเรายังไม่เคยสั่งให้มันไปชี้ที่ branch อื่น)


ฉะนั้นการสร้าง branch ใหม่ก็คือการสร้าง pointer ชื่อใหม่ขึ้นมาชี้ยัง commit ล่าสุดเท่านั้นเอง

สั่ง commit profile.html ให้เรียบร้อยก่อน



จากนั้นผมจะสร้าง pointer ตัวใหม่ชื่อ testing เพื่อแตกเป็น branch ใหม่

พิมพ์ git branch testing



คำสั่งนี้เป็นการสร้าง branch ใหม่เท่านั้น มีชื่อว่า testing แต่ยังไม่ได้ย้ายการทำงานไปยัง branch ใหม่ เราทำงานที่ branch อะไรให้ดู header pointer ว่ากำลังชี้อยู่ที่ branch ไหน


จากตัวอย่างนี้ header pointer ยังคงอยู่กับ master branch ครับ


ถ้าเราดูในรูปนี้ของ source tree เราจะเห็นว่า header pointer ชี้ที่ master ส่วน branch ใหม่ก็คือ testing

ให้เพื่อนๆลองพิมพ์

git log 

ก็จะเห็นรายละเอียดของ branch และจุดเชื่อมโยงต่างๆ


ต่อไปเราจะ switch branch จากที่เคยอยู่ master มาเป็น testing มันก็คือการย้ายที่ชี้ดีๆนี่เอง
พิมพ์

git checkout testing




ตอนนี้ header pointer ชี้ที่ testing branch เรียบร้อยแล้ว ไม่ว่าจะแก้ไขไฟล์หรือเพิ่มไฟล์ใหม่ การ commit ก็จะไปเป็นของ testing branch โดยปริยาย

ผมจะแก้ไขไฟล์ index.html เพิ่มโค้ดเข้าไปเล็กน้อย จากนั้นจะใช้ git add และ git commit ตามที่เรียนรู้มา






เจ้า source tree ทำงานกับ IO นะครับ ดังนั้นเพื่อนๆอาจไม่เห็นผลการเปลี่ยนแปลง UI ในทันที ให้เพื่อนๆกดที่ drop-down ที่เขียนว่า all branches ด้านบนมุมซ้ายในภาพสลับไปมา

เราจะได้ภาพแบบนี้


ต่อไปให้ลอง switch กลับไปที่ master branch อีกครั้ง การทำแบบนี้เท่ากับเพื่อนๆได้กลับไปใช้ version เก่านั่นเอง

นี่ไง version control system คือทำงาน version ใหม่ไปเรื่อยๆเพื่อแตกขยายงาน หรือแก้ issue ต่างๆ หรือจะกลับไปยัง version ก่อนหน้าก็ได้ เพื่อแตกขยายงานใหม่ หรือยกเลิกงานที่เคยแตกสาขาไปแล้ว

การกลับมายัง master branch เท่ากับได้ reverted ประดาไฟล์ทั้งหลายที่อยู่ใน working directory กล่าวคือได้กลับมายัง snapshot เดิมที่เคยทำไว้แล้ว ดังนั้นให้เพื่อนๆแน่ใจว่าจะทำงานที่ branch เก่าจริงๆนะ เพราะสิ่งที่ git จะเห็นใน working directory ของเพื่อนๆจะเป็นภาพตาม snapshot ที่ถูกย้อนกลับมานั่นเองครับ

ผมสั่งกลับมาที่ mater branch 

git checkout master



จากนั้นผมแก้ไข index.html อีกครั้งแบบนี้

อ่อ เห็นไหม we are strong หายไปแล้ว เพราะผม reverted กลับมาหาของเก่า version เก่ากว่า





ภาพที่ได้จะเป็นแบบนี้


และนี่คือสิ่งที่ current branch เห็น คือเห็นตาม header pointer ที่ชี้ไปยัง master branch ครับ


อะพอแล้ว โอกาสต่อไปเราจะมาเรียนรู้การรวม branch ที่แตกย่อยออกมานี้เข้าด้วยกัน สายการพัฒนาจะได้รวมมาบรรจบกัน สวัสดี

ไม่มีความคิดเห็น:

แสดงความคิดเห็น