Sau Bài 5 và Bài 6 viết lại/di chuyển lịch sử, bài này trả lời câu hỏi mọi người dùng Git đều từng hoảng loạn hỏi ít nhất 1 lần: "tôi vừa làm hỏng mọi thứ, cứu tôi với!". Tin vui: nhờ mọi object trong Git đều bất biến (Bài 1), gần như mọi thứ đều cứu được — miễn bạn biết công cụ đúng.
1. git reset: Ba Mức Độ "Xoá"
git reset <commit> di chuyển con trỏ branch hiện tại về 1 commit khác — nhưng có 3
chế độ khác nhau về việc Working Directory bị ảnh hưởng ra sao:
| Chế độ | Con trỏ branch | Staging Index | Working Directory |
|---|---|---|---|
--soft |
Di chuyển | Giữ nguyên | Giữ nguyên |
--mixed (mặc định) |
Di chuyển | Reset về commit đích | Giữ nguyên |
--hard |
Di chuyển | Reset về commit đích | Ghi đè — mất thay đổi chưa commit |
Nhớ lại 3 cây từ Bài 2: càng xuống dưới bảng, reset càng "lan"
sâu hơn qua 3 cây. --soft chỉ đụng tới HEAD; --hard đụng tới
cả 3.
reset --hard mất vĩnh viễn thứ CHƯA commit
reset --hard ghi đè
chúng và không có cách nào cứu lại. Luôn git stash (mục 4) trước khi
chạy reset --hard nếu còn thay đổi dở dang.
2. git revert: Undo An Toàn Cho Nhánh Công Khai
Khác hẳn reset (di chuyển con trỏ, có thể làm mồ côi commit),
git revert <commit> tạo ra 1 commit MỚI áp dụng đúng thay đổi
ngược lại của commit đó — lịch sử cũ được giữ nguyên vẹn, không branch nào bị "lùi lại". Đây là lựa
chọn an toàn khi cần undo trên nhánh đã push, đúng theo Golden Rule đã học ở
Bài 5.
3. git reflog: Nhật Ký Cứu Sinh
Mỗi lần HEAD di chuyển — commit, checkout, reset, rebase — Git âm thầm ghi lại vào
reflog, một nhật ký cục bộ hoàn toàn tách biệt với các branch ref. Ngay cả sau
reset --hard khiến 1 commit trông như "biến mất" (không branch nào trỏ tới, mồ côi giống
cơ chế ở Bài 3), reflog vẫn nhớ hash của nó — bạn chỉ cần
git branch <tên> <hash-từ-reflog> để "cứu" nó trở lại reachable.
.git/refs mà Git đồng bộ khi
push/pull — nó là 1 file log riêng (.git/logs/HEAD) chỉ ghi
lại lịch sử thao tác trên chính máy bạn. Đây là lý do reflog là công cụ cứu hộ
tuyệt vời cho lỗi cục bộ, nhưng vô dụng nếu bạn cần khôi phục thứ gì đó chỉ tồn tại trên máy đồng
nghiệp — mặc định reflog cũng tự dọn dẹp các entry cũ (thường sau 90 ngày), không phải kho lưu trữ
vĩnh viễn.
4. git stash: Cất Tạm Thay Đổi Chưa Commit
Khi cần chuyển nhánh gấp nhưng thay đổi hiện tại chưa đủ hoàn chỉnh để commit,
git stash cất toàn bộ Working Directory + Staging Index vào 1 "ngăn kéo" riêng, trả
Working Directory về trạng thái sạch của HEAD. git stash pop lấy lại đúng những gì vừa
cất, tiếp tục làm việc như chưa hề rời đi.
Sân chơi tương tác: Demo "Làm Hỏng Rồi Tự Cứu"
Tiếp nối engine từ các bài trước. Thử đúng kịch bản kinh điển: commit vài lần,
reset --hard lùi về 1 commit cũ (các commit sau "biến mất" — mồ côi), rồi dùng
git reflog tìm lại hash và git branch cứu chúng trở lại.
Terminal giả lập
git commit -m "..."git reset --soft|--mixed|--hard <ref>git revert <ref>git refloggit stash/git stash popgit branch <tên> <ref>
Nhật ký
Trắc nghiệm ôn tập
Câu 1: Bạn git reset --hard HEAD~1 trong khi đang sửa dở 1 file (chưa
git add, chưa commit). Chuyện gì xảy ra với phần đang sửa dở đó?
Trắc nghiệm ôn tập
Câu 2: Điều gì khiến git revert an toàn hơn git reset --hard khi cần undo
trên 1 nhánh đã push lên remote?
Trắc nghiệm ôn tập
Câu 3: Vì sao git reflog không đồng bộ khi bạn push/pull với đồng nghiệp?