Git แมว ๆ
ผมเคยสอน Git ให้ครั้งหนึ่ง ซึ่งผมก็สอนไปวาดรูปอธิบายประกอบไปตามที่เคยสอน ๆ มา จนพอจบคอร์ส นักเรียนท่านหนึ่งก็แบ่งปันคนที่อธิบายเรื่อง Git ด้วยรูปแมว ซึ่งผมเห็นว่ารูปที่เค้าใช้ยกตัวอย่างเหมือนผมเลย แค่รูปแมวมันเข้าใจง่ายกว่ามาก ตั้งแต่นั้นก็ตั้งใจว่าตั้งแต่การสอนครั้งต่อไป จะใช้รูปพวกนี้อธิบายตลอด
git pull
git pull คือการยุบสองคำสั่งเข้าด้วยกัน จริง ๆ แล้ว git pull คือ git fetch (ใช้ internet) และ git merge (ไม่ต้องใช้ internet)
สมมติสถานการณ์ที่ repository มี 2 branch คือ master (เดี๋ยวนี้เค้าเรียก main แล้ว แต่ช่างมันเถอะ) กับ tabby ซึ่งบน server (remote) มีคน push ของเพิ่มขึ้นไป คือ บน master มีคนเติมหูกระต่าย และบน tabby มีคนเติมลายบนตัว
ขณะที่เครื่องผมยังไม่ได้ fetch ความเปลี่ยนแปลงเหล่านี้มา ล่าสุดที่เคย fetch มาคือ ที่ master มีจมูกชมพู ขณะที่บน branch tabby ผมเติมลายที่หางเข้าไป
ถ้าผมสั่ง git pull origin master
ที่ branch master ก็จะ update เป็นล่าสุดนั่นคือมีหูกระต่ายเพิ่มขึ้นมา
ถ้าผมสั่ง git pull origin tabby
ที่ branch tabby ก็จะเห็นมีทั้งลายที่ตัว (ที่คนอื่นแก้) เพิ่มขึ้นมา และมีลายที่หางที่ผมแก้เอง (จริง ๆ มันควรจะเห็นเป็น commit แยกกันด้วยนะ แต่ช่างมันเถอะ)
สรุปแล้ว git pull คือ git fetch + git merge
git commit
ก่อนจะไปทำความเข้าใจ ความต่างระหว่าง merge กับ rebase เรามาปูพื้นสักนิดก่อนว่าในแต่ละ commit ใน git เก็บอะไรบ้าง
git commit เก็บ change ที่เกิดขึ้นใน commit นั้น, ใครเป็นคน change, commit เมื่อไหร่ และมี message ว่าอะไร รวมถึงจำด้วยว่า commit ก่อนหน้าเป็นเลขอะไร เมื่อเราคุยถึง git log น่าจะเห็นภาพมากขึ้น
git cherry-pick และ git log
cherry-pick คือการ apply change commit นั้นลงมาบน branch ที่เราอยู่ เช่น cherry-pick 2e46cd
มาบน branch tabby ก็จะได้สีเทาที่แขนมาดังรูป
ส่วน git log จะแสดงรายละเอียดของ history ว่าที่ file ต่าง ๆ มีหน้าตาเหมือนปัจจุบัน ผ่านการเปลี่ยนแปลงอะไรมาบ้าง ใครเพิ่มอะไร ลดอะไร เป็นต้น
git branch & git tag
branch เป็นเหมือน pointer หรือ bookmark ที่ชี้ไปยัง commit ล่าสุดที่ branch นั้นอยู่ เมื่อมี commit ใหม่เกิดขึ้นบน branch นั้น pointer นี้ก็จะเลื่อนไปยัง commit ล่าสุด
tag เป็น pointer ที่เป็น constant หมายถึงเปลี่ยนค่าไม่ได้ ถ้าชี้ไปยัง commit ไหน ก็จะเป็น commit นั้นตลอดไปจนกว่าจะโดนลบทิ้ง
git merge และ git rebase
การ merge เหมือนการที่มีพ่อและแม่ 2 branch เกิดลูกมาที่เหมือนทั้งพ่อและแม่ผสมกัน เช่น เวลา merge master เข้า branch tabby ก็จะได้หูกระต่ายเหมือน master และมีลายเหมือน tabby
การ merge เป็นการเท change ของ 2 branch มาผสมกัน ถ้ามี conflict เกิดขึ้น ก็จะเกิดเป็น conflict ใหญ่ ๆ ทีเดียวที่ให้คน merge แก้ conflict ทั้งหมดของ 2 branch นี้แล้ว commit ไว้ใน merge commit ที่จะเก็บวิธี resolve conflict ไว้ใน commit นั้น
การ rebase หรือ ปรับฐานนั้น คือ การเอา change ของ branch เราทั้งหมดทดไว้ในใจ แล้วปรับฐานของ branch เราให้เป็น master ล่าสุดที่มีหูกระต่ายสีเขียวแล้ว แล้วค่อย ๆ apply change ที่ทดในใจลงไปทีละ commit ถ้ามี conflict เกิดขึ้น ก็จะหยุดให้ resolve conflict เล็ก ๆ อันนึงก่อน แล้วค่อย apply change ถัดไปตอนเราสั่ง rebase --continue
ถ้ามี conflict อีกก็หยุดแล้ว resolve อีก เรียกว่าเจ็บนิด ๆ แต่เจ็บหลาย ๆ ที ต่างกันกับ merge ที่เจ็บหนักทีเดียวจบ
การ rebase จะไม่มี merge commit เกิดขึ้น เพราะเรา resolve conflict เข้าไปในแต่ละ commit ที่เรา apply แล้ว history ก็จะเรียงเป็นเส้นเดียวสวย ๆ
ถ้าเวลาเราสั่ง git pull แล้วเราอยากให้มัน rebase แทนการ merge ที่เป็น default ก็ใส่ option ตอน pull ได้ง่า git pull --rebase
git push
ในรูปอธิบาย จริง ๆ มีคำสั่ง git push
ด้วย แต่ผมอ่านไม่เข้าใจ เลยขอข้ามมันไปละกัน :P
Credit
Tomomi Imura for sharing this doodle under a Creative Commons Attribution-ShareAlike 4.0 International License.