การ Commit ผิดพลาดเป็นเรื่องที่เกิดขึ้นได้กับทุกคนที่ใช้ Git ไม่ว่าจะเป็นนักพัฒนาใหม่หรือผู้มีประสบการณ์ Git มีวิธีการแก้ไขและย้อนกลับที่หลากหลาย การเลือกใช้คำสั่งที่ถูกจะขึ้นอยู่กับสถานการณ์และว่าคุณได้ Push ไปยัง Remote Repository แล้วหรือไม่ บทความนี้จะช่วยให้คุณเข้าใจความแตกต่างระหว่าง git reset และ git revert เพื่อให้คุณสามารถเลือกใช้วิธีที่ถูกต้องในแต่ละสถานการณ์
ทำไมต้องเข้าใจความแตกต่างระหว่าง Reset กับ Revert
ก่อนที่จะเริ่มใช้คำสั่ง คุณต้องเข้าใจความแตกต่างพื้นฐาน: git reset ใช้สำหรับการยกเลิก Commit ในประวัติศาสตร์ (rewriting history) ส่วน git revert ใช้สำหรับการสร้าง Commit ใหม่เพื่อยกเลิกการเปลี่ยนแปลง (creating new history) การเลือกใช้ที่ถูกจะช่วยป้องกันปัญหาเมื่อทำงานร่วมกับทีม
สถานการณ์ที่ 1: Commit ยังอยู่ใน Local และยังไม่ได้ Push
หากคุณได้สร้าง Commit แล้วแต่ยังไม่ได้ Push ไปยัง Remote Repository คุณสามารถใช้ git reset เพื่อยกเลิก Commit ได้อย่างปลอดภัย คำสั่งนี้จะลบ Commit ออกจาก History ของเครื่องของคุณ และคืนไฟล์ให้อยู่ในสถานะก่อน Commit
ตัวเลือก Reset ทั้ง 3 แบบ
- git reset –soft HEAD~1: ยกเลิก Commit ล่าสุด แต่คงไว้ไฟล์ที่เปลี่ยนแปลงใน Staging Area ใช้เมื่อต้องการแก้ไข Commit Message หรือเพิ่มไฟล์ที่ลืมใส่ไป
- git reset HEAD~1 (–mixed): ยกเลิก Commit และ Unstage ไฟล์ แต่ไฟล์ที่เปลี่ยนแปลงยังคงอยู่ใน Working Directory คุณสามารถแก้ไขได้ก่อน Commit อีกครั้ง
- git reset –hard HEAD~1: ยกเลิก Commit และลบการเปลี่ยนแปลงทั้งหมด ระวัง: ไฟล์ที่เปลี่ยนแปลงจะหายไป และไม่สามารถกู้คืนได้โดยตรง
# ยกเลิก Commit ล่าสุด แต่คงไว้การเปลี่ยนแปลงใน Staging
git reset --soft HEAD~1
# ยกเลิก Commit และ Unstage ไฟล์ที่เปลี่ยนแปลง
git reset HEAD~1
# ยกเลิก Commit และลบการเปลี่ยนแปลงทั้งหมด (อันตรายสูง ไม่ใช้ถ้าไม่แน่ใจ)
git reset --hard HEAD~1
ตัวอย่าง: คุณได้ Commit แล้วแต่พบว่า Commit Message มีข้อผิดพลาด ให้ใช้ git reset --soft HEAD~1 เพื่อแก้ไข Commit Message แล้วสร้าง Commit ใหม่อีกครั้ง
สถานการณ์ที่ 2: Commit ที่ Push ไปแล้ว บน Feature Branch ส่วนตัว
หากคุณได้ Push Commit ไปยัง Feature Branch ส่วนตัวของคุณ และไม่มีคนอื่นใช้งาน Branch นี้ คุณสามารถใช้ git reset ร่วมกับ git push --force-with-lease เพื่อแก้ไขปัญหา
# Reset ใน Local ก่อน
git reset --hard HEAD~1
# Force push ไปยัง Remote เพื่อให้สอดคล้องกับ Local
# ใช้ --force-with-lease แทน --force เพราะปลอดภัยกว่า
git push --force-with-lease origin feature/my-branch
# หรือหาก Feature Branch ของคุณไม่มีคนใช้ร่วม
git push --force origin feature/my-branch
ความแตกต่างระหว่าง –force-with-lease และ –force
--force-with-lease ปลอดภัยกว่า --force เพราะมันจะตรวจสอบว่า Remote ยังเก็บข้อมูลเดิมเหมือนเครื่องของคุณ หากมีคนอื่นได้ Push ไปแล้ว –force-with-lease จะปฏิเสธการ Push เพื่อป้องกันการลบ Commit ของคนอื่น เหมาะสำหรับการทำงานร่วมกับทีมบน ผู้ให้บริการโฮสติ้ง Cloud VPS
สถานการณ์ที่ 3: Commit ที่ Push ไปแล้ว บน Shared Branch (Main/Develop)
หากคุณได้ Push Commit ไปยัง Main Branch หรือ Develop Branch ที่มีคนอื่นใช้งานด้วย ห้ามใช้ git reset เพราะมันจะลบ Commit จาก History และทำให้คนที่ Pull ไปแล้วเกิดปัญหา แทนที่จะนั้น ให้ใช้ git revert เพื่อสร้าง Commit ใหม่ที่ยกเลิกการเปลี่ยนแปลง
# สร้าง Revert Commit เพื่อยกเลิกการเปลี่ยนแปลงของ Commit ล่าสุด
git revert HEAD
git push origin main
# ยกเลิกหลายๆ Commit โดยรวม
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert: ยกเลิก Feature X ที่มีข้อผิดพลาด"
git push origin main
ทำไม git revert ถึงดีกว่า git reset สำหรับ Shared Branch
git reset ลบ Commit ออกจาก History ทำให้ History ดูราวกับ Commit นั้นไม่เคยเกิดขึ้น ส่วน git revert สร้าง Commit ใหม่ที่เป็นสิ่งตรงข้ามกับ Commit ที่ผิดพลาด ทำให้ History ยังอยู่สมบูรณ์ คนอื่นที่ Pull ไปแล้วจะเห็นว่า Commit ดังกล่าวถูกยกเลิก แทนที่จะสับสนว่า Commit หายไปไหน
การแก้ไข Commit Message ที่ผิดพลาด
หากต้องการแก้ไข Commit Message เท่านั้น ไม่ต้องยกเลิก Commit ให้ใช้ git commit --amend ซึ่งเป็นวิธีที่ง่ายและปลอดภัยกว่า
# แก้ไข Commit Message ของ Commit ล่าสุด
git commit --amend -m "Message ใหม่ที่ถูกต้อง"
# แก้ไข Commit Message โดยไม่เปลี่ยนการเปลี่ยนแปลงไฟล์
git commit --amend --no-edit
# แก้ไข Author ของ Commit
git commit --amend --author="ชื่อใหม่ "
# หากได้ Push ไปแล้ว ต้อง Force Push
git push --force-with-lease origin main
การกู้คืน Commit ที่ลบไป ด้วย git reflog
หากคุณได้ใช้ git reset --hard และลบ Commit ไปแล้ว อย่าตกใจ Git บันทึกประวัติทั้งหมดของการเปลี่ยนแปลง HEAD ใน reflog คุณสามารถใช้ git reflog เพื่อหาค่า Hash ของ Commit ที่ลบไป และกู้คืนมันได้
# ดูประวัติทั้งหมดของ HEAD
git reflog
# ตัวอย่าง output:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: Commit ที่ลบไป
# ghi9012 HEAD@{2}: commit: Commit ก่อนหน้า
# กู้คืน Commit ที่ต้องการ (e.g. HEAD@{1})
git reset --hard HEAD@{1}
# หรือใช้ Commit hash
git reset --hard def5678
git reflog เป็นเหมือน Safety Net ของคุณ เมื่อใช้คำสั่งอันตรายเช่น git reset --hard ข้อมูลจะยังคงอยู่ใน reflog เป็นเวลาประมาณ 30 วัน
Best Practices สำหรับการใช้ Git ในทีม
เมื่อทำงานกับทีมบน ผู้ให้บริการโฮสติ้ง Cloud VPS หรือโครงการ Git ที่มีหลายคน ให้ปฏิบัติตามกฎเหล่านี้:
- ใช้ git revert สำหรับ Shared Branches: หากต้องยกเลิก Commit บน Main/Develop Branch ให้ใช้ revert เสมอ
- ใช้ git reset เฉพาะสำหรับ Local Changes: ใช้ reset เมื่อต้องยกเลิก Commit ที่ยังไม่ได้ Push เท่านั้น
- ตรวจสอบ Commit ก่อน Push: ใช้
git logเพื่อตรวจสอบ Commit ก่อนที่จะ Push - ใช้ Feature Branches: สร้าง Feature Branch ส่วนตัวก่อนเพื่อป้องกันปัญหาบน Main Branch
- ทำ Code Review ก่อน Merge: ใช้ Pull Request และให้ทีมตรวจสอบโค้ดก่อน Merge
- เขียน Commit Message ที่ชัดเจน: ช่วยให้คนอื่นและตัวเองเข้าใจว่ามีการเปลี่ยนแปลงอะไร
สรุป
การย้อนกลับ Commit ที่ผิดพลาดใน Git ไม่ใช่ปัญหาใหญ่หากคุณเข้าใจว่าจะใช้ git reset หรือ git revert อย่างไร ให้จำไว้ว่า reset ใช้สำหรับการเปลี่ยน History ของตัวเอง ส่วน revert ใช้สำหรับการสร้าง History ใหม่ที่ปลอดภัยสำหรับทีม และเสมอจำไว้ว่ามี git reflog เพื่อช่วยเหลือเมื่อเกิดความผิดพลาด ด้วยการปฏิบัติตามหลักการเหล่านี้ คุณจะสามารถจัดการ Git Repository ได้อย่างมั่นใจและปลอดภัยบน ผู้ให้บริการโฮสติ้ง Cloud VPS
