เรามาลองใช้ Git Command ระดับกลาง (หรือสูง) กันมั้ยครับ: stash, squash, rebase

kaninkearpimy

Kanin James Kearpimy

Posted on March 2, 2022

เรามาลองใช้ Git Command ระดับกลาง (หรือสูง) กันมั้ยครับ: stash, squash, rebase

หากว่าเราพูดถึง git สำหรับคนเริ่มต้น คงจะหนีไม่พ้นคำสั่งต่างๆ เหล่านี้

  • git add . // เพิ่ม files ที่ถูกแก้เข้า staged change
  • git commit -m "message" // เพิ่ม staged change files เข้า commit history
  • git push & git pull _// syncing ระหว่าง local (เครื่องที่บ้าน) กับ remote (เครื่องบน server ของผู้ให้บริการ เช่น github)
    _
    วันนี้เราจะลองดูอีก 3 คำสั่งที่ใช้กันค่อนข้างบ่อย เมื่อเริ่มคุ้นชินกับการทำงานของ git มากขึ้น

  • git stash

  • git squash

  • git rebase

git stash

ลองนึกถึงสถานการณ์ที่พวกเรากำลังแก้ไฟล์อยู่ และทำไปได้ระดับหนึ่งแล้วแต่บังเอิญว่ามีงานด่วนเข้ามา และเราต้องหันไปทำงานนั้นทันที ปัญหาจะเกิดดังนี้ครับ
1) ยังมี change files ที่ยังไม่เสร็จ และยัง commit ไม่ได้ เพราะอาจจะเกิดผลเสียมากกว่าข้อดี
2) เราสามารถสร้าง branch ใหม่ให้เก็บ change ของเราได้ แต่ก็เปลืองอยู่ดี

git stash example 1

ในกรณีแบบนี้ git stash จะมีประโยชน์มาก เพราะสิ่งที่ git stash ทำจะเป็นการ save ตัว change files ของเราเอาไว้ใน local แต่จะไม่ถือว่าเป็น commit ทำให้สามารถสลับไปทำงานอื่นและ syncing ข้อมูลกับ remote ได้อย่างอิสระ (เพราะอย่างไร change ก็ไม่ปนขึ้นไปด้วยอยู่ดี)

โดยเมื่อต้องการทำ git stash ให้ทำการเพิ่มทุก files ที่ต้องการเข้าสู่ staged change (git add) ก่อน จากนั้นให้พิมพ์คำสั่ง git stash เพื่อ save เก็บไว้ในเครื่อง (ตามภาพด้านล่าง)

git stash example 2

จากนั้นเมื่อทำการ git status (หรือ gst) อีกครั้งจะเห็นได้ว่า change file ได้หายไป (ถูกเก็บเข้า stash) เรียบร้อยแล้ว ซึ่งเราสามารถสลับไปทำ features อื่นได้โดยไม่ต้องกังวลถึง change files อีก โดยสามารถเช็คได้ว่าเรามี change files ที่ stash ไว้กี่ครั้ง สามารถทำได้โดยคำสั่ง

git stash list

git stash example 3

และเมื่อต้องการนำสิ่งที่ stash ไปกลับมาเพื่อแก้ไข พัฒนาต่อเราสามารถใช้คำสั่ง

git stash apply stash@{i} // โดย i คือตัวเลขของ stash order ซึ่ง stash ล่าสุดจะไล่จากน้อยไปมาก เช่น stash@{0} คือ stash ที่ถูกเพิ่มล่าสุด

git stash example 4

เพียงเท่านี้ก็จะสามารถจัดการกับ change ที่เราต้องการ แต่ยังไม่อยาก commit ได้แล้ว

git squash

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

git squash history example 1

เราจะสังเกตุได้ว่า มี commits 3 ครั้งคือ

  • init squash
  • set up init config in squash.txt
  • modify config in squash.txt

ซึ่ง messages ทั้ง 3 ครั้งนี้ รวมถึงตัว source code เองมีความใกล้เคียงกันมาก หากเราทำงานในทีมขนาดใหญ่ การทำให้ commit history มีความกระชับและง่ายต่อการติดตาม เป็นเรื่องที่สำคัญอย่างหลีกเลี่ยงไม่ได้

และ git squash จะเข้ามาแก้ปัญหาข้างต้นครับ โดยปกติการทำกิจ squash ทักจะใช้คู่กับ git rebase หรือ git merge โดยเราจะใช้ git rebase ในตัวอย่างนี้ เพื่อ rebase squash นั้นวิธีที่ง่ายที่สุดคือใช้ interactive mode ของ git rebase โดยใช้งานคำสั่ง

git rebase [commit hash] -i // โดย hash คือตัว commit ที่เราต้องการ rebase กลับไป

git squash history example 2

จากรูปด้านบน เราจะ squash 3 commits เข้าด้วยกัน

git squash history example 6

หลังพิมพ์คำสั่ง terminal จะเปิดหน้าจอให้เราเลือกว่าจะ squash ตัวใด และตัวใดจะเป็น hash ที่รอรับการ squash ซึ่งเราเลือก hash bdfaf72 สำหรับรองรับ commit ที่กำลังจะถูก squash

git squash history example 4

  • s, squash คือการเลือก commit นั้นๆ ให้ถูกมัดรวม
  • p, pick คือการเลือก commit นั้นๆ ให้เป็นที่รองรับ squash commit

จากนั้นตัว terminal (git) จะเปิดหน้าต่างให้เราเลือก commit message ของการ squash

git squash history example 5

หลังเสร็จสิ้นการ squash เราจะสังเกตุได้ว่า commits ทั้ง 3 ตัวนั้นหายไปและมี commit ใหม่ที่เกิดจากการ squash ขึ้นมาแทนเรียบร้อยแล้ว

git squash history example 5

git rebase

เมื่อคำสั่งที่ผ่านมา เราได้ใช้ git rebase ไปบ้างแล้ว แต่จริงๆ คำสั่ง git rebase เขาเอาไว้ทำอะไรกันแน่ละ

ลองนึกถึงกรณีที่ระหว่างการพัฒนา ทีมของเรา commit code บางอย่างเข้ามาใน branch main และไม่มีใครสังเกตุ จนกระทั่งเวลาผ่านไป พึ่งรู้ว่ามีปัญหาอยู่ใน source code และต้องการแก้อย่างเร่งด่วน ประเด็นคือ เราไม่สามารถอยู่ๆ ไปไล่ลบ commit ออกได้เลย เพราะ commit ดังกล่าวก็มีคำสั่งอื่นๆ ที่จำเป็นอยู่ด้วย

git rebase example 1

โดยเราสามารถเลือกแก้ได้หลายแบบ โดยวิธีที่กำลังจะทำก็คือ

  • checkout กลับไปยัง commit ที่ต้องการแก้
  • แตก branch ใหม่ และแก้ปัญหา

git rebase example 2

เมื่อทราบ commit ที่ต้องการแก้แล้ว ให้ทำการ checkout กลับไปที่ hash ดังกล่าว

git checkout d0ec37e

git rebase example 3

จากนั้นให้ทำการแก้สิ่งที่ต้องการและแตก branch แยกออกมา

git rebase example 4

ซึ่งเมื่อสังเกตุจะเห็นได้ว่า history ของ git นั้นมีบางส่วนหายไป (อิงจากรูปด้านบน) คือ bd3b066 และ eebae51 ซึ่งกรณีนี้นั้น

git rebase example 5

หากเรา merge main branch ทันที สิ่งที่เกิดขึ้นคือ ตัว history ของเราใน branch นี้จะหายไป (ซึ่งนำไปสู่การตาม track ที่ยากขึ้น)

git rebase example 6

แต่หากเราใช้ git rebase สิ่งที่เกิดขึ้นคือ git จะนำ history ของ change มาต่อส่วนหัวของ branch ที่เราต้องการ rebase ทำให้ history ไม่หายไป (และตาม track ง่ายขึ้น)

git rebase example 7

โดยเราสามารถพิมพ์คำสั่ง

git rebase [target branch name] [current branch]

git rebase main fixed-critical-001

git rebase example 8

และหากเรา git log --oneline อีกครั้ง เราจะพบว่า history ที่หายไปถูกนำมารวมกลับใน branch ใหม่แล้ว

git rebase example 9

💖 💪 🙅 🚩
kaninkearpimy
Kanin James Kearpimy

Posted on March 2, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related