TL;DR: จะย้อนคอมมิตสุดท้ายแต่เก็บการเปลี่ยนแปลงไว้ ให้รัน git reset --soft HEAD~1 (การเปลี่ยนแปลงยังอยู่ใน staging) หรือ git reset HEAD~1 (การเปลี่ยนแปลงอยู่ใน working tree) ถ้าคอมมิตถูกพุชไปแล้ว ให้รัน git revert HEAD แทน — มันสร้างคอมมิตใหม่ที่ยกเลิกคอมมิตเดิมโดยไม่แตะประวัติ สามคำสั่งนี้ครอบคลุมแทบทุกสถานการณ์ “คอมมิตเร็วเกินไป” ที่เหลือของบทความจะไล่แต่ละกรณีด้วยคำสั่ง copy-paste อธิบายความต่างของ --soft, --mixed และ --hard พร้อมวิธีกู้คืนเมื่ออะไรก็ตามผิดพลาด ทุกคำสั่งด้านล่างใช้ได้กับ Git เวอร์ชันใหม่บน Linux, macOS และ Windows
จะย้อนคอมมิตสุดท้ายโดยเก็บการเปลี่ยนแปลงไว้ได้อย่างไร?
สถานการณ์ที่พบบ่อยที่สุด: คอมมิตไปแล้วค่อยเจอพิมพ์ผิด ไฟล์ตกหล่น หรือนึกได้ว่าการเปลี่ยนแปลงนี้ควรอยู่อีกคอมมิต ยังไม่ได้พุชอะไรเลย ย้อนคอมมิตแล้วคืนทุกอย่างกลับที่เดิม:
# คอมมิตหายจากประวัติ — การเปลี่ยนแปลงกลับเข้า staging area
git reset --soft HEAD~1
# การเปลี่ยนแปลงกลับไปอยู่ใน working tree (ยังไม่ staged) แทน
git reset HEAD~1 HEAD~1 หมายถึง “หนึ่งคอมมิตก่อนจุดที่ HEAD ชี้อยู่” หลังจากคำสั่งใดก็ตาม ไฟล์บนดิสก์ของคุณไม่ถูกแตะ — สิ่งที่ขยับมีแค่พอยเตอร์ของ branch เช็กด้วย git status: ถ้าใช้ --soft การเปลี่ยนแปลงจะอยู่ในสถานะ staged พร้อมคอมมิตซ้ำพร้อมแก้ไข ถ้าไม่ใส่ flag จะเป็น unstaged เพื่อให้แก้ไขเพิ่มก่อนได้อย่างอิสระ
นิสัยที่ปลอดภัยกว่า เมื่อคุณแค่อยากเพิ่มไฟล์เข้าคอมมิตล่าสุด คือไม่ต้องย้อนเลย:
git add forgotten-file.txt
git commit --amend --no-edit --amend แทนที่คอมมิตล่าสุดในที่เดิม (ตรงนี้ไม่แก้ข้อความคอมมิต) ข้อควรจำ: amend คอมมิตที่ พุชไปแล้ว คือการเขียนทับประวัติ — รายละเอียดอยู่ด้านล่าง
ความต่างของ —soft, —mixed และ —hard คืออะไร?
ส่วนที่ควรจำ เพราะ flag ตัดสินว่าการเปลี่ยนแปลงของคุณจะไปจบที่ไหน — และจะหายได้หรือไม่:
| Flag | ยกเลิกคอมมิต? | ไฟล์บนดิสก์ | ยัง staged? | ใช้เมื่อ |
|---|---|---|---|---|
--soft | ใช่ | เก็บไว้ | ใช่ | คอมมิตซ้ำพร้อมแก้เล็กน้อย |
--mixed (ค่าเริ่มต้น) | ใช่ | เก็บไว้ | ไม่ | จัดกลุ่มการเปลี่ยนแปลงใหม่ stage แบบเลือกทีละไฟล์ |
--hard | ใช่ | ถูกลบ | — | ทิ้งงานทั้งหมด |
git revert | ไม่ (เป็นคอมมิตใหม่) | เก็บไว้ | — | ยกเลิกคอมมิตที่พุชไปแล้ว |
--hard เป็นตัวเดียวที่อันตราย: มันทิ้งทั้งคอมมิต และ การเปลี่ยนแปลง ก่อน reset --hard ทุกครั้ง ให้เก็บงานไว้ใน stash หรือ branch ก่อน:
git branch backup-before-reset # ประกันราคาถูก
git reset --hard HEAD~1 # คอมมิตและการเปลี่ยนแปลงหายทั้งคู่ ถ้ารันเวอร์ชันอันตรายไปแล้ว ยังไม่ใช่จุดจบ — git reflog จำได้ว่า HEAD เคยไปที่ไหน:
git reflog # หา hash ของคอมมิตที่เสียไป
git reset --hard HEAD@{1} # หรือ: git reset --hard <hash> reflog เก็บคอมมิตที่ลอยอยู่ไว้ราว 90 วันโดยดีฟอลต์ ดังนั้น “ผม hard-reset ผิดมือ” แทบกู้คืนได้เสมอ ถ้ารีบก่อนถูกเก็บขยะ
ถ้าพุชคอมมิตไปแล้วล่ะ?
ถ้าคอมมิตอยู่บน branch ที่ใช้ร่วมกัน (อะไรก็ตามที่ไม่ใช่ feature branch ส่วนตัวของคุณ) อย่าเขียนทับประวัติ ให้ใช้ git revert ซึ่งคำนวณการเปลี่ยนแปลงตรงข้ามแล้วคอมมิตลงไป:
git revert HEAD
git push ทุกคนที่ pull จะได้แค่คอมมิตใหม่ที่ลบการเปลี่ยนแปลงของคอมมิตเก่า ไม่มี force-push ไม่มีเพื่อนร่วมงานพัง ถ้าต้องยกเลิกคอมมิตหลายตัว ให้ revert เป็นช่วง: git revert --no-commit HEAD~3..HEAD && git commit
ทางเลือก — git reset --hard HEAD~1 && git push --force-with-lease — ยอมรับได้เฉพาะบน branch ที่ไม่มีใครอื่นใช้ และ --force-with-lease (ไม่ใช่ --force เปล่า ๆ) คือรูปแบบเดียวที่ปลอดภัย เพราะจะปฏิเสธถ้ามีคนพุชแทรกมาก่อน force-push บน branch ส่วนกลางคือวิธีที่ทีมเสียคอมมิต และ log ของ CI เลิกแมตช์กับ checkout ของใครสักคนอย่างน่างง
จะย้อนคอมมิตล่าสุดแต่เก็บไว้ใช้ทีหลังได้อย่างไร?
บางทีคอมมิตนั้นเป็นงานดีที่อยู่ผิดที่ — ผิด branch หรือเร็วไป แทนที่จะย้อน ก็ย้ายมัน:
git branch stash-commit # จอดคอมมิตไว้บน branch ใหม่
git reset --hard HEAD~1 # แล้วค่อยเก็บกวาด branch ปัจจุบัน หรือหยิบเฉพาะคอมมิตนั้นไปอีก branch โดยไม่แตะ branch ปัจจุบัน:
git cherry-pick <hash> # ขณะอยู่บน branch ปลายทาง ระหว่าง reset --soft, cherry-pick และ revert ไม่มีคอมมิตใดที่ย้ายหรือลบล้างไม่ได้ — เทคนิคคือเลือกให้ออกว่าอยาก “ย้าย” หรือ “ยกเลิก” ก่อนยื่นมือไปหา flag
ควรใช้การย้อนแบบไหน? คู่มือตัดสินใจฉบับเร่งรัด
- ยังไม่พุช อยากแก้แล้วคอมมิตใหม่ →
git reset --soft HEAD~1 - ยังไม่พุช อยาก stage เลือกไฟล์ →
git reset HEAD~1(mixed) - อยากให้การเปลี่ยนแปลงหายไปเลย →
git reset --hard HEAD~1(reflog ยังรู้ ถ้าคุณใจเสีย) - พุชไปแล้วบน branch ร่วม →
git revert HEAD - คอมมิตควรอยู่อีก branch →
cherry-pickไม่ต้องย้อน
เคล็ดลับปฏิบัติการข้อสุดท้าย: ถ้าคอมมิตพังมันลอดไปถึงเซิร์ฟเวอร์จริง ๆ — deploy hook ที่พัง หรือ CI runner ทำตัวประหลาดหลัง force-push — จุดหมายถัดไปของการตามคือ log ของเครื่อง ไม่ใช่ Git บนเครื่องที่ใช้ systemd ใด ๆ journalctl -u <service> -n 100 จะบอกได้ละเอียดว่าอะไรรันไปแล้วเมื่อไหร่ ใน สรุปคำสั่ง journalctl ของเรามีรูปแบบคำสั่ง copy-paste ครบ และถ้าเวิร์กโฟลว์ของคุณมีเครื่องมือ LLM ในเครื่องไว้รีวิว diff เราเคยเทียบสองตัวหลักไว้แล้วใน Ollama vs LM Studio
— mrsaynothing
— mrsaynothing
บันทึกหน้างานเรื่อง AI, Linux และ self-hosted
คุยต่อโพสต์นี้บน dev.to dev.to ↗
รับวิธีแก้ฉบับถัดไปทางอีเมล
อีเมลหนึ่งฉบับต่อหนึ่งโพสต์ แก้เสร็จแล้วไปต่อ
นี่คืออะไร?สรุปคำสั่ง journalctl: ดู กรอง และติดตาม log บน Linux
ถ้าอ่านแล้วชอบ — ผมสร้างงานแบบนี้เป็นอาชีพ จ้างผม