มาทำ Git Squash Commits ด้วย Git Rebase กัน

Sakul Montha
4 min readOct 26, 2021
GIT SQUASH COMMITS WITH GIT REBASE

ผมค่อนข้างมั่นใจว่า หลายคนที่หลงเข้ามาอ่าน บ้างก็รู้จัก บ้างก็ไม่รู้จัก Git Squash Commits เอาเป็นว่า ไม่เป็นไรครับ ไหน ๆ ก็หลงเข้ามาอ่านแล้ว ผมขอถือโอกาส เล่าไปเลยแล้วกันนะครับ

คำเตือน: บทความนี้เหมาะกับผู้ที่มีประสบการณ์ การใช้งาน Git มาบ้าง อาจมีศัพท์, ภาพ, ตัวอย่าง Source, หรือเนื้อหาที่เข้าไม่ถึง ผู้อ่านควรมีประสบการณ์มาแล้วอย่างน้อย วัน สองวัน เอ้า…

Git Squash Commits

Git Commit อันนี้ขออนุญาตไม่อธิบายเนอะ ที่อยากจะรู้น่าจะเป็น Squash มากกว่า ว่ามันคืออะไร

โลกนี้มีสิ่งที่เรียกว่า git squash อยู่ด้วยนะเฟร้ย

Squash ที่เป็น Verb คือการบีบ, เบียด, รัด, อัดแน่น

ดังนั้นแล้ว Git Squash Commits ก็คือ การควบแน่น Commits ของเราต่าง ๆ ให้เหลืออันเดียวนั่นเอง

Why

คำถามก็คือ แล้วจะทำไปทำไม ทำเพื่ออะไร? เพื่อที่จะคลายข้อสงสัย ต้องบอกงี้ เวลาที่เราเขียนโปรแกรมใช่มะ เราก็จะมีความ อะ Commit แปะไว้ก่อนกันพลาด กันหายอะไรก็ว่าไป ทีนี้ บางทีสิ่งที่เราเขียนก็อาจจะไม่ได้ Change logic อะไรมาก ปรับนั่นนิด Commit ที ปรับนู่นหน่อย Commit ที (คำว่าใหญ่เล็กเรา ไม่เท่ากัน) ทีนี้ เวลาเราจะ Push upstream ใช่มะ มันก็จะติด Commit ต่าง ๆ ของเราไปหมดเลยอ้ะ นึกภาพออกมะ นึกออกแหละ เพราะเตือนไปตั้งแต่ข้างบนแล้ว ว่าควรมีประสบการณ์ การใช้ Git มา อะต่อ ๆ

เวลาที่เรา Push ขึ้นไปใช่ปะ มันก็จะติด Commit ของเราไปลึ่มลั่มเลยแหละแก ทีนี้มันไม่ Coooool เว้ย เค้าก็เลยแบบมี Git Squash Commits มานี่แหละ อะก่อนจะไปต่อ เอาอีกสักตัวอย่างนึง

อย่างเวลาเรา Fork git มาใช่มะ เราก็ Fork ไม่มีใครว่าไร แต่… ทีนี้ถ้าเราแบบ เกิดอยากมีความ Contribute project ที่เรา Fork มาอะ ทำไงนะ? เปิด PR ไง.. ใช่แล้ว เปิด PR แล้ว เอางานที่เรา Contribute ไม่ว่าจะไปสร้าง Feature ใหม่, แก้ไขคำผิด, ไปสร้างบัคใหม่ให้ Project เค้า ไรงี้ เราก็ Push ขึ้นไปโล้ดดดด แต่ปัญหาคือแบบ ถ้าเรา Push ขึ้นไปใช่มะ Commit มันก็ติดตามไปไรงี้ ทีนี้ถ้ามันมีปรับแก้ นู่นนี่นั่น มันก็ต้อง Push ไปอีก Commit ก็ติดขึ้นไปอีก ไอเจ้า Git Squash Commits นี่แหละมันก็จะมาช่วยเหลือเราอะ

How

ก่อนที่เราจะไปดูว่า เอ้อ น่าสนใจ แล้วมันทำยังไงกันนะ ขออธิบายมาแบบ มีตัวอย่างให้เห็นภาพตามกันไปเลยแล้วกันนะ ผมสร้างโปรเจกต์ขึ้นมาอันนึง ชื่อว่า squash-project แล้วก็ทำ git init เรียบร้อย จากนั้นสร้างไฟล์ readme.md ขึ้นมา แล้วก็ทำการ พิมพ์ Initial project ลงไป จากนั้นก็ git add . แล้วก็ git commit -m 'Initial Project' สุดท้ายก็ git push origin main ก็จบ… เดี๋ยว… ยังก่อน

จากนั้นเราก็จะมี Commit แรกของ Project ของเรากันแล้ว Commit แรกของผมได้ f0f16b7 ทดเอาไว้ในใจก่อนนะ ตรงนี้สำคัญ

เราก็มาเริ่มกัน ผมทำการลบคำว่า Initial project ในไฟล์ readme.md ออกไปแล้วพิมพ์ First จากนั้นผม git add . แล้วก็ตามด้วย git commit -m 'add first' ทำวนแบบนี้ไปเรื่อย 5 รอบ ก็คือมี first, second, third, fourth และ fifth จากนั้น ผมใช้คำสั่ง git log --pretty=oneline เพื่อดู Log ผมก็จะได้ประมาณนี้

c5de7a5 * (HEAD -> main) add fifth
f1e922e * add fourth
3e2e429 * add third
c3041a4 * add second
4877bba * add first
f0f16b7 * Initial Project

จะเห็นว่า เรามีอยู่ทั้งหมด 6 Commits โดยที่เรามี f0f16b7 เป็น Commit ที่เก่าสุด ทีนี้ก็ถึงการ Squash มันด้วยพระเอกของเรา นั่นคือ git rebase นั่นเอง (เอาจริง ๆ นะสมัยก่อนผมไม่ชอบ Rebase เลยแหละ)

git rebase -i HEAD~<n> // n คือตัวเลขของ commits ที่ต้องการจะ squashหรือgit rebase -i <sha> // sha คือ sha code ของ commit ไปจนถึง squash

ในกรณีนี้ n คือ 5 ถ้าเราต้องการจะ Squash ทั้งหมดอะจากนั้น เราก็จะเห็นภาพประมาณนี้

pick 4877bba add first
pick c3041a4 add second
pick 3e2e429 add third
pick f1e922e add fourth
pick c5de7a5 add fifth
# Rebase f0f16b7..c5de7a5 onto f1e922e (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

จะเห็นว่าตรง # Rebase f0f16b7..c5de7a5 onto f1e922e (5 commands) เค้าก็จะมีบอกว่าจะทำการ Rebase f0f16b7..c5de7a5 ไปสู่ f1e922e

ตัว git rebase เอง เค้าก็จะมีคำอธิบาย Option ต่าง ๆ ให้ใช้งาน แต่สิ่งที่เราจะทำ วันนี้ก็คือ การยุบรวมก็คือ s หรือ squash นั่นเอง ทีนี้ เราก็จะเปลี่ยน 4 บรรทัดบน

pick 4877bba add first
squash c3041a4 add second
squash 3e2e429 add third
squash f1e922e add fourth
squash c5de7a5 add fifth
# Rebase f0f16b7..c5de7a5 onto f1e922e (5 commands)
...
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

โค้ดด้านบนเป็นการ squash สาม commits บน แล้วเลือก pick commit บนสุดเอาไว้ จะใช้ squash หรือ s ก็ได้ ส่วน pick ก็สามารถใส่ p ได้เช่นกัน อย่าลืม wq และ q! ด้วยหละคำสั่ง vi พื้นฐาน เมื่อเราทำการ Save เสร็จแล้ว เค้าก็จะพาเรามาอีกหน้านึง

# This is a combination of 5 commits.
# This is the 1st commit message:
add first# This is the commit message #2:add second# This is the commit message #3:add third# This is the commit message #4:add fourth# This is the commit message #5:add fifth# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Oct 26 23:11:49 2021 +0700
#
# interactive rebase in progress; onto f0f16b7
# Last commands done (5 commands done):
# squash f1e922e add fourth
# squash c5de7a5 add fifth
# No commands remaining.
# You are currently rebasing branch 'main' on 'f0f16b7'.
#
# Changes to be committed:
# modified: readme.md
#

ทีนี้ถ้าเราอยากจะ Modify commit message ก็ละเลงในนี้ได้เลย อย่างผมก็แก้เป็น

Try to use git squash commits

อย่าลืม save หละ ต่อไปเมื่อทำเสร็จเรียบร้อย ไร้ปัญหาใด ๆ ก็ทำการ Push ได้เลย

git push

The Result

หากทุกท่านทำตามขั้นตอน แล้วทำได้อย่างไม่มีปัญหาใด ๆ แล้วหละก็ เพียงเท่านี้ ท่านก็จะไม่ต้องเจอ Commit เยอะ ๆ รกหูรกตาบน main branch อีกต่อไป

ทั้งหมดที่กล่าวมา มันดูมันสวยงามไปหมดเลยเนอะ ตอนทำจริงมันต้องมีปัญหาบ้างแหละ แต่ว่า ทุกปัญหาย่อมมีทางแก้ครับ เรื่องของ Git ถ้ามีปัญหา แนะนำให้ อ่าน Log ฮ่า ๆ ใช่แล้วครับ อ่าน Log จะช่วยท่านได้

คำสั่งแก้ไขปัญหาเบื่องต้นเวลามีปัญหากับ git rebase ก็จะประมาณพวก git rebase —-continue หรือ git rebase --edit-todo หรือถ้ารู้สึกไม่ชอบมาพากลละ ไม่ไหวแล้ว ยังมี git rebase —-abort

หวังว่าทุกท่านจะได้รับสาระ ความรู้เพิ่มเติม แล้วก็จะดีใจอย่างมาก ถ้าบทความนี้มีคนอ่าน แล้วนำไปทดลองใช้ ใช้จริง… แล้วก็เหมือนเดิมครับ ผิดพลาดประการใด ตรงไหนไม่ถูก อยากให้แก้ตรงไหน ส่งข้อความมาบอกกล่าวกันได้นะครับ ^^

References

--

--

Sakul Montha

Chief Product Officer, a man who’s falling in love with the galaxy.