“Cứu dữ liệu” với git reflog: Khôi phục Commit và Branch bị xóa nhầm trong 5 phút
Hướng dẫn git reflog phục hồi dữ liệu trong 5 phút: tìm commit thất lạc, khôi phục branch bị xóa, sửa reset hard/rebase/amend sai và tạo nhánh cứu hộ an toàn.
ShanverseUpdated 11 min read— viewsLoading views
Git
Developer Tools
Bạn vừa xóa nhầm branch, chạy git reset --hard, rebase sai hoặc amend mất commit cũ. git log không còn hiển thị lịch sử mong muốn, nhưng dữ liệu chưa chắc đã biến mất. Git thường vẫn lưu object commit và nhật ký di chuyển của các reference trong reflog.
Bài này cung cấp quy trình phục hồi trong khoảng năm phút, sau đó đi sâu vào từng tình huống và giới hạn thực tế.
Reflog là gì?
Reflog là nhật ký cục bộ ghi lại việc các reference như HEAD và branch di chuyển qua các commit.
Ví dụ:
Kết quả:
Mỗi dòng gồm:
Comments
Commit hash tại thời điểm đó.
Selector như HEAD@{1}.
Thao tác làm reference thay đổi.
Message liên quan.
git log đi theo lịch sử commit hiện đang được reference trỏ tới. git reflog ghi lại những nơi reference từng trỏ tới, nên nó có thể tìm commit không còn xuất hiện trong log hiện tại.
Quy trình cứu dữ liệu trong 5 phút
Phút 1 — Dừng thao tác phá hủy
Không tiếp tục chạy:
Không rebase, amend hoặc force push thêm trước khi xác định trạng thái cần phục hồi.
Kiểm tra:
Phút 2 — Xem reflog
Hoặc dạng dễ đọc:
Tìm entry ngay trước thao tác sai, ví dụ trước reset, rebase, amend hoặc checkout.
Phút 3 — Kiểm tra commit ứng viên
Kiểm tra cây file:
Đừng reset ngay chỉ vì message trông quen. Hãy xác minh diff và file.
Phút 4 — Tạo branch cứu hộ
Cách an toàn nhất:
Hoặc tạo và chuyển:
Branch mới giữ commit có tên để Git không còn xem nó là object không được tham chiếu.
Phút 5 — So sánh và chọn cách đưa dữ liệu trở lại
Sau đó chọn:
Merge branch cứu hộ.
Cherry-pick một vài commit.
Reset branch cá nhân về commit cũ.
Chỉ lấy lại một file.
Tình huống 1: Khôi phục branch vừa bị xóa
Giả sử bạn chạy:
Git thường in hash commit cuối của branch. Nếu không ghi lại, xem reflog:
Tìm checkout/commit liên quan đến branch hoặc message cuối cùng. Kiểm tra hash:
Tạo lại branch:
Hoặc dùng tên cứu hộ trước:
Xác nhận:
Reflog riêng của branch có còn không?
Bạn có thể thử:
Sau khi branch bị xóa, reflog riêng có thể không còn truy cập bằng tên đó. HEAD reflog hoặc --all vẫn có thể chứa entry từ lúc bạn checkout/commit trên branch.
Tình huống 2: Hoàn tác git reset --hard
Bạn đang ở commit D:
Sau:
Branch trỏ về B, nhưng reflog thường ghi vị trí cũ.
Ví dụ:
Tạo branch cứu hộ:
Nếu đây là branch cá nhân và bạn muốn đưa branch hiện tại trở lại hoàn toàn:
Nhưng chỉ reset sau khi:
Working tree không có thay đổi cần giữ.
Đã tạo branch cứu hộ.
Branch không phải lịch sử dùng chung hoặc team cho phép rewrite.
Tình huống 3: Khôi phục sau rebase sai
Rebase tạo commit mới và branch trỏ sang lịch sử mới. Vị trí trước rebase thường xuất hiện trong reflog.
Tìm entry trước:
Hoặc entry cũ trước khi rebase (finish).
Kiểm tra:
Tạo branch:
So sánh lịch sử:
Hoặc so sánh nội dung cuối:
Nếu rebase đang diễn ra, ưu tiên:
Reflog phù hợp hơn khi rebase đã hoàn tất hoặc abort không còn khả dụng.
Tình huống 4: Tìm commit trước git commit --amend
Amend tạo commit mới thay commit cũ. Commit cũ thường vẫn có trong reflog:
Ví dụ:
Khôi phục commit cũ bằng branch:
Nếu chỉ muốn lấy một file từ commit cũ:
Kiểm tra diff rồi commit có chủ đích:
Tình huống 5: Mất commit sau khi chuyển khỏi Detached HEAD
Bạn checkout một commit cũ, tạo commit mới nhưng không tạo branch:
Commit mới không còn branch trỏ tới. Tìm bằng:
Entry thường liên quan đến commit hoặc checkout. Sau khi xác minh:
Tình huống 6: Lấy lại một file hoặc thư mục
Không phải lúc nào bạn cũng muốn quay cả branch về quá khứ.
Sau khi tìm commit đúng:
Lấy cả thư mục:
Kiểm tra:
Sau đó commit thay đổi phục hồi. Cách này an toàn hơn reset khi chỉ mất một phần nội dung.
Tình huống 7: Khôi phục stash bị drop
Stash được biểu diễn bằng commit-like object. Nếu vừa drop và object chưa bị dọn, bạn có thể thử:
Nếu reference không còn, tìm object không được tham chiếu:
Kiểm tra candidate:
Tạo branch hoặc áp dụng theo cấu trúc stash khi đã xác định đúng. Đây là phục hồi nâng cao và không được đảm bảo; stash không nên là bản backup duy nhất.
HEAD@{n} và hash commit
Bạn có thể dùng selector reflog trực tiếp:
Hoặc selector theo thời gian:
Cú pháp thời gian phụ thuộc entry có trong reflog local. Khi đã tìm đúng, commit hash cụ thể dễ ghi lại và chia sẻ hơn.
Reflog cho từng reference
Xem reflog của HEAD:
Của branch:
Của tất cả reference có thể truy cập:
Dạng chi tiết:
Tìm theo message:
Chọn branch, cherry-pick, restore hay reset?
Mặc định, tạo branch cứu hộ trước vì thao tác này không thay đổi working tree hoặc branch hiện tại.
Reflog có được push lên GitHub không?
Không. Reflog là dữ liệu local của từng clone.
Điều này có nghĩa:
Reflog trên máy bạn có thể chứa commit mà máy khác không có.
Clone mới không có reflog lịch sử từ máy cũ.
GitHub không thể khôi phục mọi commit chỉ dựa vào reflog local của bạn.
Nếu commit từng push, remote refs, Pull Request hoặc cache phía server có thể cung cấp đường phục hồi khác.
Khi tìm được commit quan trọng, hãy tạo branch và push nếu cần backup/chia sẻ:
Reflog tồn tại bao lâu?
Entry reflog và object Git không tồn tại vĩnh viễn. Git có chính sách hết hạn và garbage collection; thời gian cụ thể phụ thuộc cấu hình, trạng thái object và hoạt động repository.
Xem cấu hình liên quan:
Các giá trị mặc định thường được nhắc tới là khoảng 90 ngày cho entry thông thường và khoảng 30 ngày cho entry không còn reachable, nhưng không nên coi đó là cam kết phục hồi. Cấu hình và quá trình GC có thể khác.
Điều reflog không thể cứu chắc chắn
File chưa từng được Git ghi nhận và đã bị xóa.
Thay đổi working tree chưa commit bị ghi đè bởi reset --hard.
File Untracked bị git clean xóa mà không có backup.
Object đã bị garbage collection xóa.
Lịch sử trên máy khác nếu clone hiện tại chưa từng có object đó.
Secret đã lộ; khôi phục/xóa commit không thay thế việc rotate credential.
IDE, hệ điều hành, backup hoặc cloud history có thể là lựa chọn khác cho file chưa từng được Git lưu.
Sai lầm thường gặp khi phục hồi
Reset ngay vào hash đầu tiên nhìn thấy
Hãy tạo branch trước:
Rồi xem và so sánh.
Dùng reset --hard trên branch chung
Nếu branch đã chia sẻ, rewrite có thể ảnh hưởng người khác. Lấy commit bằng cherry-pick hoặc hoàn tác bằng revert thường an toàn hơn.
Force push sau khi phục hồi mà không kiểm tra
Nếu thực sự cần cập nhật branch cá nhân đã rewrite:
Không force push branch chung theo phản xạ.
Chỉ xem git log
Commit thất lạc có thể không reachable từ branch hiện tại. Hãy dùng git reflog --all, rồi git fsck chỉ khi cần phục hồi nâng cao.
Tiếp tục tạo nhiều commit trong lúc hoảng
Nhiều thao tác làm reflog dài và khiến bạn khó nhận diện thời điểm sai. Dừng, ghi lại hash ứng viên và tạo branch cứu hộ.
Checklist phục hồi
Dừng thao tác phá hủy và cleanup.
Ghi lại branch hiện tại và git status.
Chạy git reflog --all --date=local.
Tìm entry ngay trước thao tác sai.
Xác minh bằng git show.
Tạo recover/... branch trước reset.
So sánh commit, file và test.
Chọn cherry-pick/restore thay vì reset nếu chỉ cần một phần.
Không rewrite branch chung mà chưa phối hợp.
Push branch cứu hộ nếu dữ liệu quan trọng.
Xóa branch backup chỉ sau khi phục hồi hoàn tất.
Cheat sheet
Tổng kết
Quy tắc cứu dữ liệu với reflog:
Dừng lại trước khi chạy thêm lệnh phá hủy.
Tìm hash bằng reflog và xác minh bằng git show.
Tạo branch cứu hộ trước khi reset hoặc rewrite.
Khôi phục đúng phạm vi bằng branch, cherry-pick hoặc restore.
Đẩy branch cứu hộ nếu dữ liệu quan trọng.
Table of contents(30)
Codeplain text
19f8e7d6 HEAD@{0}: reset: moving to HEAD~224c3b2a1 HEAD@{1}: commit: feat: add checkout flow33b2a190 HEAD@{2}: rebase (finish): returning to refs/heads/feature/checkout
1# Xem reflog2gitreflog--all--date=local34# Kiểm tra commit5gitshow--stat<hash>67# Tạo branch cứu hộ8gitswitch-crecover/lost-work<hash>910# Lấy một commit11gitcherry-pick<hash>1213# Lấy một file14gitrestore--source=<hash>--path/to/file1516# Hủy rebase đang chạy17gitrebase--abort1819# Tìm object nâng cao20gitfsck--no-reflog--unreachable
Related posts
More articles with related topics and technologies.
Hướng dẫn Git Aliases và .gitconfig thực chiến: alias an toàn, log đẹp, cấu hình pull/push/rebase, includeIf cho tài khoản work/personal, bảo mật và chia sẻ dotfiles.
Phân tích Gitflow vs GitHub Flow vs Trunk-Based Development: cấu trúc branch, ưu nhược điểm, điều kiện áp dụng, ma trận quyết định và lộ trình chuyển đổi cho từng loại dự án.
Hướng dẫn git worktree từ cơ bản đến thực tế: tạo nhiều working tree, làm feature và hotfix song song, review PR, quản lý list/remove/prune/lock/repair và tránh lỗi phổ biến.