Git Rebase คอมมิทที่ push ขึ้นไปแล้ว
Tags: git, commandline, ไทย
Published: 2019-07-02 12:49:48

---
title: Git Rebase คอมมิทที่ push ขึ้นไปแล้ว
published: true
description: คอมมิทเยอะมาก แต่ละคอมมิทแก้ไขนิดๆ หน่อยๆ แต่เป็นเรื่องเดียวกัน อยากรวมหลายๆ คอมมิทที่ push ขึ้นไปแล้วให้เป็นคอมมิทเดียว จะได้สะอาดๆ และคนมาอ่าน commit เราจะได้อ่านได้ง่ายๆด้วย 
tags: git, commandline, ไทย
cover_image: https://thepracticaldev.s3.amazonaws.com/i/jpx60cfssx5pjggoiyhx.png
---

วิธีง่ายๆ ในการกรุ๊ปรวมคอมมิทหลายๆ ตัวให้เป็นตัวเดียว และยังสามารถทำได้แม้ในกรณีที่เรา push  คอมมิทเหล่านั้นขึ้นไปยัง git server เรียบร้อยแล้วด้วย

Git สามารถที่จะกรุ๊ปรวมคอมมิทให้กลายเป็นคอมมิทเดียวได้ด้วยคำสั่ง `git rebase --interactive HEAD~[N]` หรือสั้นๆ `git rebase -i HEAD~[N]` โดยที่ [N] คือจำนนวนคอมมิทก่อนหน้านี้ 

อธิบายเพิ่มเติมในส่วนของ `HEAD~[N]` ยกตัวอย่างง่ายๆ ในกรณีที่ตอนนี้เราอยู่ที่คอมมิทล่าสุด และถ้าหากเราต้องการกรุ๊ปรวมคอมมิทก่อนหน้านี้ 3 คอมมิท เราสามารถที่จะเพิ่มอาร์กิวเมนต์ต่อท้าย `git rebase -i` เพื่อที่จะนำคอมมิทก่อนหน้านี้มา 3 ตัวเพื่อนำมากรุ๊ปรวมให้เป็นคอมมิทเดียว ซึ่งเราสามารถเพิ่มอากิวเมนต์ได้โดยเพิ่มคำสั่ง `HEAD~4` ต่อท้าย แต่เมื่อนับรวมกับคอมมิทล่าสุดของเราด้วยแล้วก็จะกลายเป็นว่าเราจะมีคอมมิทที่จะนำไปแก้ไขทั้งหมด 4 ตัว เพื่อให้เข้าใจได้ง่ายขึ้นเดี๋ยวเรามาลองดูโค้ดตัวอย่างกัน

## ขั้นตอน 👩‍🏫

ก่อนที่เราจะทำ `rebase` เรามาดูคอมมิทที่เรามีกันก่อน เราสามารถเช็คคอมมิทได้จากหน้าต่างเครื่องมือช่วยอย่าง [Sourcetree](https://www.sourcetreeapp.com/) หรือจะใช้ command line อย่าง `git log` 

```text
commit 1e3399... (HEAD -> master, origin/master)
Author: Atthaphon Urairat <xxx@xxxxx.com>
Date:   Wed Jun 26 09:27:07 2019 +0700

    Completed B

commit 729dad...
Author: Atthaphon Urairat <xxx@xxxxx.com>
Date:   Wed Jun 26 09:21:11 2019 +0700

    add more option for header

commit f7375b...
Author: Atthaphon Urairat <xxx@xxxxx.com>
Date:   Wed Jun 26 09:06:29 2019 +0700

    disable cache

commit 256bbc...
Author: Atthaphon Urairat <xxx@xxxxx.com>
Date:   Wed Jun 26 08:54:46 2019 +0700

    corrected method

commit f62f5f...
Author: Atthaphon Urairat <xxx@xxxxx.com>
Date:   Tue Jun 25 18:42:33 2019 +0700

    Completed A

...
```

หรือถ้าหากว่าเราต้องการดู log แต่ละคอมมิทในบรรทัดเดียว เราก็สามารถเพิ่มอาร์กิวเมนต์ `git log --pretty=oneline`


```text
1e3399... (HEAD -> master, origin/master) Completed B    <<< คอมมิทล่าสุด
729dad... add more option for header
f7375b... disable cache
256bbc... corrected method
f62f5f... Completed A                                    <<< คอมมิทเก่ากว่า
...
```

จากตัวอย่างข้างต้น ตอนนี้เราอยู่ที่คอมมิทแรก `1e3399... (HEAD -> master, origin/master) Completed B
` และต้องการที่จะกรุ๊ปคอมมิทก่อนหน้านี้สามตัวถึงคอมมิทที่ชื่อ `256bbc... corrected method`

ผลลัพธ์ที่เราคาดหวังไว้คือการกรุ๊ปรวมคอมมิทให้เป็นดังนี้

```text
1e3399... (HEAD -> master, origin/master) Completed B
f62f5f... Completed A
...
```

นั่นคือการกรุ๊ปรวมคอมมิททั้งหมดที่อยู่ระหว่าง Completed B และ Completed A ให้เหลือเพียงคอมมิทดังตัวอย่างก่อนหน้านี้ ต่อไปเราก็มารันคำสั่งกันเลย

```text
git rebase -i HEAD~4
```

**คำเตือน** เมื่อเรารันคำสั่งไปแล้ว ต่อจากนั้นหน้าจอก็จะเปลี่ยนเป็นตัว editor เพื่อโชว์คอมมิทที่เราต้องการจะทำการกรุ๊ปรวม **แต่!!** มันจะถูกแสดงออกมาในลำดับการจัดเรียงกลับหลัง ซึ่งต่างจากการรันคำสั่ง `git log` ของเราก่อนหน้านี้

> TIP 💡 ในกรณีที่เรามีคอมมิทที่ต้องการจะกรุ๊ปรวมเยอะ และการนับคอมมิทเพื่อเอาเลขมาใส่ท้าย `HEAD~` มีความยุ่งยากหรืออาจเกิดข้อผิดพลาดได้ง่าย เราก็สามารถที่จะใช้เลขคอมมิทแทนการใช้ `HEAD~[N]` ได้ดังนี้ `git rebase -i [commit-number]`

```text
git rebase -i f62f5fd
```

ผลลัพธ์ของการรันทั้งสองคำสั่งก็จะได้ค่าออกมาเหมือนกันดังที่แสดงในตัวอย่างด้านล่างนี้

```bash
pick f62f5fd corrected method            <<< คอมมิทเก่ากว่า
pick f7375bf disable cache
pick 729dad4 add more option for header
pick 1e3399c Completed B                 <<< คอมมิทล่าสุด

# Rebase f62f5fd..1e3399c onto f62f5fd (3 commands)
```

จากนั้นเราก็ทำการ เปลี่ยน `pick` เป็น `squash` หรือสามารถเขียนสั้นๆ `s` ก็ได้เพื่อทำการกรุ๊ปรวมคอมมิทจากเก่าสุดเพื่อให้รวมกับคอมมมิทล่าสุด

```bash
pick f62f5fd corrected method            <<< คอมมิทเก่ากว่า
s f7375bf disable cache
s 729dad4 add more option for header
s 1e3399c Completed B                    <<< คอมมิทล่าสุด

# Rebase f62f5fd..1e3399c onto f62f5fd (4 commands)

```

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

```bash
# This is a combination of 3 commits.
# This is the 1st commit message:

corrected method

# This is the 1st commit message #2:

disable cache

# This is the 1st commit message #3:

add more option for header

# This is the 1st commit message #4:

Completed B

...
```
ผมจะทำการลบข้อความทั้งหมดให้เหลือเพียงคำว่า `Completed B`

```base 
Complete B
```

หลังจากทำการเซฟและออกจาก editor แล้วก็จะปรากฏข้อความแสดงความยินดี ซึ่งแสดงว่าเราทำการรวมคอมมิทให้กลายเป็นคอมมิทเดียวได้สำเร็จแล้ว 🥳🥳 ❤️🎉 (หรืออาจเป็นข้อความ ตอกย้ำก็ได้ในกรณีที่เราทำผิดพลาด 😫😫) 

```text
[detached HEAD 1bc71e4] Completed B
 Date: Wed Jun 26 08:54:46 2019 +0700
 4 files changed, 11 insertions(+), 21 deletions(-)
Successfully rebased and updated refs/heads/master
```

จากนั้นเราก็จะได้ คอมมิทใหม่มาซึ่งกรุ๊ปรวมคอมมิททั้งหมดที่เราได้ทำไปก่อนหน้านี้มาเป็นที่เรียบร้อยแล้ว 

สุดท้ายนี้ ก็ทำการ push ขึ้นไปยัง git server ของเราอีกครั้งแบบ force push ด้วยคำสี่ง `git push origin master --force` 

> **เตือน** ❗️ ตั้งสติก่อนสตาร์ท เอ้ย!! โทด โทด ตั้งสติก่อน push ครับ 🤣🤣 เพราะการทำ force push มันถือว่าเป็นความเสี่ยง ดังนั้นเราควรแน่ใจกับ commit ของเรา หรืออาจสร้าง branch ไว้เป็น backup ก่อน ทำการ force push ไว้ดีกว่าครับ 

วันนี้จบแล้วครับ ขอบคุณที่ติดตามอ่านจนจบครับ หวังว่าจะเป็นประโยชน์กับใครบ้างสักคนบ้างนะครับ