git reset –hard ลบงานหาย: เข้าใจความต่างของ –soft, –mixed, –hard
การใช้งาน Git เป็นทักษะพื้นฐานสำหรับนักพัฒนา แต่คำสั่ง git reset มักจะทำให้หลายคนกังวล เพราะกลัวว่าจะลบงานหาย ในบทความนี้ เราจะอธิบายความต่างระหว่าง git reset --soft, --mixed และ --hard อย่างละเอียด พร้อมตัวอย่างปฏิบัติจริง เพื่อให้คุณสามารถใช้คำสั่งนี้ได้อย่างปลอดภัยและมั่นใจ
git reset คืออะไร
git reset เป็นคำสั่งที่ใช้สำหรับการย้าย HEAD ไปยัง commit ที่ต้องการ โดยมีตัวเลือกต่างๆ ที่ควบคุมว่าจะเปลี่ยนแปลง Staging Area และ Working Directory อย่างไร การเข้าใจความต่างระหว่างตัวเลือกต่างๆ จึงเป็นสิ่งสำคัญมาก
ก่อนที่จะเข้าใจ git reset ให้ดีขึ้น เราควรรู้ว่า Git มี 3 ส่วนหลัก:
- Repository (Commit History): ประวัติการเปลี่ยนแปลงทั้งหมด
- Staging Area (Index): ไฟล์ที่เตรียมพร้อมสำหรับ commit
- Working Directory: ไฟล์ที่คุณแก้ไขในเครื่องของคุณ
git reset –soft: เก็บ Staging Area และ Working Directory
git reset --soft ย้าย HEAD ไปยัง commit ที่ต้องการ แต่ เก็บ Staging Area และ Working Directory ไว้ นี่คือตัวเลือกที่ปลอดภัยที่สุด เพราะงานของคุณจะไม่หาย
ใช้กรณี: เมื่อคุณต้องการแยก commit เดียวออกเป็นหลาย commit
$ git log --oneline a1b2c3d (HEAD) Add feature X 9f8e7d6 Add feature Y $ git reset --soft 9f8e7d6 $ git status On branch main Changes to be committed: modified: feature-x.js new file: config.js
เมื่อใช้ --soft ไฟล์ทั้งหมดจากงานที่ถูกยกเลิก (undo) จะยังคงอยู่ใน Staging Area ทำให้คุณสามารถแก้ไขหรือแยก commit ได้ตามต้องการ
git reset –mixed: ยกเลิก Staging แต่เก็บ Working Directory
git reset --mixed (ค่าเริ่มต้น) ย้าย HEAD และ ยกเลิก Staging Area แต่ เก็บไฟล์ในไดเรกทอรี่ทำงาน นี่เป็นตัวเลือกที่ใช้บ่อยที่สุด
ใช้กรณี: เมื่อคุณ stage ไฟล์ไว้แล้ว แต่ต้องการถอนการ stage (unstage) แต่ไม่ต้องการลบการเปลี่ยนแปลง
$ git add file1.js file2.js $ git status On branch main Changes to be committed: modified: file1.js modified: file2.js $ git reset file1.js $ git status On branch main Changes to be committed: modified: file2.js Changes not staged for commit: modified: file1.js
ไฟล์ file1.js ถูก unstage แต่การเปลี่ยนแปลงยังคงอยู่ในไฟล์
git reset –hard: ลบทุกอย่าง (ระวัง!)
git reset --hard ย้าย HEAD, ยกเลิก Staging Area, และลบการเปลี่ยนแปลงทั้งหมดใน Working Directory นี่เป็นตัวเลือกที่อันตรายที่สุด
ใช้กรณี: เมื่อคุณต้องการกลับไปยังสถานะเดิมของ commit โดยไม่เก็บการเปลี่ยนแปลงใดๆ
$ git log --oneline a1b2c3d (HEAD) Break everything 9f8e7d6 Last good commit $ git reset --hard 9f8e7d6 HEAD is now at 9f8e7d6 Last good commit $ git status On branch main nothing to commit, working tree clean
ทุกการเปลี่ยนแปลงตั้งแต่ commit a1b2c3d จะถูกลบไปทั้งหมด
ตารางเปรียบเทียบ –soft vs –mixed vs –hard
| ตัวเลือก | HEAD | Staging Area | Working Directory | ความปลอดภัย |
|---|---|---|---|---|
--soft | ย้าย | เก็บไว้ | เก็บไว้ | ปลอดภัยที่สุด |
--mixed | ย้าย | รีเซ็ต | เก็บไว้ | ปลอดภัย |
--hard | ย้าย | รีเซ็ต | ลบ | อันตรายที่สุด |
วิธีการกู้คืนงานที่ลบไป
ถึงแม้ว่า git reset --hard จะลบการเปลี่ยนแปลง แต่ยังมีวิธีกู้คืนได้อยู่โดยใช้ git reflog
ใช้ git reflog เพื่อหา commit ที่หาย
git reflog แสดงประวัติของการเปลี่ยนแปลง HEAD ทั้งหมด เหมือนประวัติในเบราว์เซอร์
$ git reflog
a1b2c3d HEAD@{0}: reset: moving to 9f8e7d6
9f8e7d6 HEAD@{1}: commit: Last good commit
c5d4e3f HEAD@{2}: commit: Some other work
$ git reset --hard a1b2c3d
HEAD is now at a1b2c3d Break everything
ดังที่เห็น เราสามารถใช้ git reflog หา commit ที่หายไปและ reset กลับมาได้
วิธีการจำหลัก: “git reflog” เป็นเบรคเพื่อความปลอดภัย
แม้ว่าคุณใช้ git reset --hard แล้ว ยังคงสามารถกู้คืนได้ 30 วัน โดยใช้ git reflog ตราบใดที่คุณไม่ได้รัน garbage collection
สถานการณ์ 1: ต้องการแยก commit เดียวออกเป็นหลาย commit
$ git log --oneline a1b2c3d Add multiple features (feature A, B, C) $ git reset --soft HEAD~1 $ git reset # unstage all $ git add feature-a.js $ git commit -m "Add feature A" $ git add feature-b.js $ git commit -m "Add feature B" $ git add feature-c.js $ git commit -m "Add feature C"
สถานการณ์ 2: Unstage ไฟล์บางตัว
$ git add . $ git status On branch main Changes to be committed: modified: production.js modified: test.js modified: debug.js $ git reset production.js $ git commit -m "Fix tests" # production.js ยังไม่ถูก commit
สถานการณ์ 3: ลบ commit ล่าสุดที่เสีย
$ git log --oneline
a1b2c3d BROKEN: Remove database
9f8e7d6 Add new feature
$ git reset --hard 9f8e7d6
HEAD is now at 9f8e7d6 Add new feature
$ git reflog # เพื่อให้ใจสบาย ตรวจสอบว่าสามารถกู้คืนได้
a1b2c3d HEAD@{0}: reset: moving to 9f8e7d6
เคล็ดลับและวิธีปฏิบัติที่ดี
- ใช้ –soft โดยค่าเริ่มต้น: เมื่อคุณไม่แน่ใจว่าต้องการอะไร ให้ใช้
--softเพราะปลอดภัยที่สุด - ตรวจสอบด้วย git status: เสมอใช้
git statusก่อนและหลังการ reset - สำรอง branch ก่อน: ก่อน reset ที่อันตราย ให้สร้าง backup branch:
git branch backup - จำไว้ว่า –hard ไม่ได้หมายถึง “ไม่มีการกู้คืน”: git reflog ยังคงเก็บประวัติ
- ใช้ –force-with-lease แทน –force: เมื่อ push หลังจาก reset:
git push --force-with-lease
สรุป
ความเข้าใจเรื่อง git reset เป็นทักษะที่สำคัญสำหรับทีมพัฒนาที่ทำงานกับ Git ได้อย่างมั่นใจ:
git reset --soft:ย้าย HEAD แต่เก็บ staging และ working directorygit reset --mixed:ย้าย HEAD และยกเลิก staging แต่เก็บไฟล์git reset --hard:ลบทุกอย่าง แต่สามารถกู้คืนได้โดย git reflog
ใช้ git reset อย่างรู้เรื่องจะช่วยให้คุณจัดการ commit history ได้อย่างมีประสิทธิภาพ และไม่ต้องกลัวว่าจะลบงานหาย
