TL;DR: muốn undo commit cuối nhưng giữ thay đổi, chạy git reset --soft HEAD~1 (thay đổi vẫn staged) hoặc git reset HEAD~1 (thay đổi nằm trong working tree). Nếu commit đã push rồi, chạy git revert HEAD thay thế — nó tạo commit mới để vô hiệu commit cũ mà không viết lại history. Ba lệnh đó phủ gần như mọi khoảnh khắc “commit vội quá”. Phần còn lại của bài đi qua từng trường hợp bằng lệnh copy-paste, giải thích khác biệt giữa --soft, --mixed và --hard, và chỉ cách phục hồi nếu có gì đó sai. Mọi lệnh dưới đây chạy được trên mọi bản Git mới trên Linux, macOS hay Windows.
Làm sao undo commit cuối mà vẫn giữ thay đổi?
Tình huống phổ biến nhất: bạn commit xong rồi phát hiện typo, thiếu file, hoặc nhận ra thay đổi lẽ ra thuộc commit khác. Chưa push gì cả. Undo commit và trả mọi thứ về chỗ cũ:
# Commit biến mất khỏi history — thay đổi quay lại staging area
git reset --soft HEAD~1
# Thay đổi quay lại working tree (unstaged) thay vì thế
git reset HEAD~1 HEAD~1 nghĩa là “một commit trước vị trí HEAD đang trỏ”. Sau một trong hai lệnh, file trên đĩa không bị đụng đến — chỉ con trỏ branch di chuyển. Kiểm tra bằng git status: với --soft thay đổi staged, sẵn sàng commit lại với các bản sửa gộp vào; không cờ thì thay đổi unstaged, bạn sửa thoải mái trước.
Thói quen an toàn hơn khi bạn chỉ muốn thêm file vào commit cuối là đừng undo gì cả:
git add forgotten-file.txt
git commit --amend --no-edit --amend thay thế commit cuối tại chỗ (ở đây không đổi commit message). Lưu ý amend một commit đã push là viết lại history — nói kỹ ở dưới.
—soft, —mixed và —hard khác nhau thế nào?
Đây là phần đáng thuộc, vì cờ quyết định thay đổi của bạn đi về đâu — và liệu chúng có thể mất không:
| Cờ | Commit bị hủy? | Thay đổi trên đĩa | Thay đổi staged? | Dùng khi |
|---|---|---|---|---|
--soft | Có | Giữ | Có | Commit lại với bản sửa nhỏ |
--mixed (mặc định) | Có | Giữ | Không | Gom lại thay đổi, stage chọn lọc |
--hard | Có | Xóa | — | Vứt bỏ toàn bộ công việc |
git revert | Không (commit mới) | Giữ | — | Undo commit đã push |
--hard là cờ duy nhất nguy hiểm: nó vứt cả commit lẫn thay đổi. Trước mọi lệnh reset --hard, stash hoặc branch phần việc của bạn:
git branch backup-before-reset # bảo hiểm giá rẻ
git reset --hard HEAD~1 # commit + thay đổi biến mất Nếu bạn đã chạy bản nguy hiểm rồi, chưa mất tất cả — git reflog nhớ HEAD đã từng ở đâu:
git reflog # tìm hash commit bạn vừa mất
git reset --hard HEAD@{1} # hoặc: git reset --hard <hash> Reflog giữ commit mồ côi khoảng 90 ngày theo mặc định, nên “hard-reset nhầm” hầu như luôn phục hồi được nếu bạn hành động trước garbage collection.
Nếu đã push commit rồi thì sao?
Nếu commit nằm trên shared branch (bất cứ nhánh nào không phải feature branch của riêng bạn), đừng viết lại history. Dùng git revert — nó tính thay đổi ngược lại rồi commit nó:
git revert HEAD
git push Ai pull về cũng chỉ nhận một commit mới xóa thay đổi của commit cũ. Không force-push, không đồng nghiệp gãy. Cần undo cả chuỗi commit thì revert một range: git revert --no-commit HEAD~3..HEAD && git commit.
Phương án thay thế — git reset --hard HEAD~1 && git push --force-with-lease — chỉ chấp nhận được trên branch không ai khác build trên đó, và --force-with-lease (đừng bao giờ dùng --force trơn) là dạng duy nhất an toàn vì nó từ chối nếu có ai đó đã push xen giữa. Force-push shared branch là cách cả team mất commit và log CI bí ẩn không khớp checkout của bất kỳ ai.
Làm sao undo commit cuối mà vẫn giữ nó để dành?
Đôi khi commit là công việc tốt nhưng sai địa chỉ — nhầm branch, hoặc sớm quá. Thay vì undo, hãy chuyển nó đi:
git branch stash-commit # gửi commit vào một branch mới
git reset --hard HEAD~1 # rồi dọn branch hiện tại Hoặc đưa riêng commit đó sang branch khác mà không đụng đến branch hiện tại:
git cherry-pick <hash> # khi đang ở branch đích Với reset --soft, cherry-pick và revert, không có commit nào bạn không thể di chuyển hoặc vô hiệu — cái khó là quyết định “chuyển” hay “hủy” trước khi với tay lấy cờ.
Nên dùng kiểu undo nào? Hướng dẫn chọn nhanh
- Chưa push, muốn sửa rồi commit lại →
git reset --soft HEAD~1 - Chưa push, muốn stage chọn lọc lại →
git reset HEAD~1(mixed) - Muốn thay đổi biến mất hoàn toàn →
git reset --hard HEAD~1(reflog biết, nếu bạn hối hận) - Đã push lên shared branch →
git revert HEAD - Commit thuộc về branch khác →
cherry-pick, đừng undo
Mẹo vận hành cuối: nếu commit hỏng có lọt tới server — deploy hook trục trặc, CI runner hành xử lạ sau force-push — chỗ tiếp theo để xem là log của máy, không phải Git. Trên máy systemd nào, journalctl -u <service> -n 100 chỉ chính xác cái gì đã chạy và lúc nào; journalctl cheat sheet của chúng tôi có sẵn các pattern copy-paste. Còn nếu workflow của bạn có tool LLM local để review diff, chúng tôi đã so sánh hai lựa chọn chính trong Ollama vs LM Studio.
— mrsaynothing
— mrsaynothing
Ghi chú thực địa về AI, Linux và self-hosting.
Thảo luận bài này trên dev.to dev.to ↗
Nhận how-to tiếp theo qua email
Một email mỗi bài viết. Sửa xong rồi đi tiếp.
cái này là gì?journalctl Cheat Sheet: Tail, Lọc và Theo Dõi Log Linux
Thích kiểu viết này? Tôi build như vậy để kiếm sống. thuê tôi