Về blog

Git Undo Last Commit: Giữ thay đổi, vẫn an toàn

3 tháng 9, 2026

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--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 đĩaThay đổi staged?Dùng khi
--softGiữCommit lại với bản sửa nhỏ
--mixed (mặc định)GiữKhôngGom lại thay đổi, stage chọn lọc
--hardXóaVứt bỏ toàn bộ công việc
git revertKhô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-pickrevert, 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

  1. Chưa push, muốn sửa rồi commit lạigit reset --soft HEAD~1
  2. Chưa push, muốn stage chọn lọc lạigit reset HEAD~1 (mixed)
  3. Muốn thay đổi biến mất hoàn toàngit reset --hard HEAD~1 (reflog biết, nếu bạn hối hận)
  4. Đã push lên shared branchgit revert HEAD
  5. Commit thuộc về branch kháccherry-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.

self-hosted · không bên thứ ba · hủy đăng ký một cú bấm

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