git reset –hard ลบงานหาย: เข้าใจความต่างของ –soft, –mixed, –hard

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

ตัวเลือกHEADStaging AreaWorking 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 directory
  • git reset --mixed: ย้าย HEAD และยกเลิก staging แต่เก็บไฟล์
  • git reset --hard: ลบทุกอย่าง แต่สามารถกู้คืนได้โดย git reflog

ใช้ git reset อย่างรู้เรื่องจะช่วยให้คุณจัดการ commit history ได้อย่างมีประสิทธิภาพ และไม่ต้องกลัวว่าจะลบงานหาย