Chuyển đến nội dung chính

Git Reflog: Tìm hiểu và sử dụng nhật ký tham chiếu trong Git

Tìm hiểu cách git reflog giúp theo dõi và khôi phục commit bị mất, hoàn tác lỗi và quản lý lịch sử nhánh. Khám phá các tình huống thực tế và lệnh để làm chủ git reflog.
· 10 phút đọc

Khám phá cùng AI

Không có gì khó chịu hơn với một nhà phát triển hay kỹ sư dữ liệu bằng việc lỡ tay xóa nhánh git hoặc reset commit khi bạn không hề muốn. Vì vậy, tôi rất vui được chia sẻ điều tôi học được qua trải nghiệm của chính mình và ước gì biết sớm hơn: cách dùng git reflog. git reflog là một trong những kỹ thuật rất đáng để học; bỏ ra chút thời gian bây giờ có thể giúp bạn tránh được nhiều rắc rối sau này. 

Trong khi tôi sẽ giới thiệu git reflog, công cụ tôi thấy cực kỳ hữu ích để điều hướng và phục hồi sau khi mắc lỗi, tôi cũng muốn gợi ý các khóa học Foundations of Git và Introduction to GitHub Concepts của chúng tôi để bạn nắm vững mọi thứ về kiểm soát phiên bản.

git reflog là gì?

Git reflog, hay reference log (nhật ký tham chiếu), là một cơ chế theo dõi cục bộ ghi nhận các cập nhật đến các đầu nhánh (branch tip) và tham chiếu HEAD trong một kho Git. (Trong ngữ cảnh Git, HEAD chỉ commit hiện tại mà thư mục làm việc và khu vực staging của bạn dựa vào.)

Không giống git log, vốn hiển thị lịch sử commit dựa trên phả hệ và cách các commit liên kết trong một nhánh, git reflog ghi nhận mọi chuyển động của HEAD, bao gồm chuyển nhánh, rebase, reset và commit. Điều này khiến reflog hữu ích để khôi phục commit bị mất và gỡ lỗi các thao tác gần đây.

Khi nào mục reflog được tạo?

Các mục reflog được tạo bất cứ khi nào bạn thực hiện hành động làm thay đổi trạng thái của HEAD hoặc tham chiếu nhánh. Những tình huống thường gặp gồm:

  • Tạo commit bằng git commit.

  • Checkout sang một nhánh khác bằng git checkout branch_name.

  • Tạo nhánh mới bằng git branch new_branch.

  • Rebase git rebase

  • Reset về một commit trước đó git reset --hard.

  • Merge các nhánh bằng git merge.

Đây là lệnh bạn dùng để theo dõi cập nhật trong kho cục bộ:

git reflog

Sử dụng git reflog để theo dõi cập nhật trong kho cục bộ.

Sử dụng git reflog để theo dõi cập nhật trong kho cục bộ. Ảnh: Tác giả.

Bạn diễn giải đầu ra của git reflog như thế nào?

Bạn có thể diễn giải đầu ra như sau:

  • HEAD@{0}: Hành động gần nhất là chuyển sang nhánh HEAD.

  • HEAD@{1}: Trước đó, tôi đã đổi kiểu tệp từ định dạng .xlxs sang .csv.

  • HEAD@{2}: Tôi thực hiện commit đầu tiên khi đẩy tệp lên kho.

Mỗi mục hiển thị:

  • Mã băm commit (fa82776)

  • Chỉ mục reflog (HEAD@{0}, HEAD@{1}, v.v.)

  • Mô tả hành động đã thực hiện (commit, checkout, rebase)

Cách sử dụng git reflog

Git reflog cung cấp cách để theo dõi cập nhật tham chiếu và khôi phục các trạng thái trước đó của kho. Bằng cách hiểu cách điều hướng các mục reflog, bạn có thể khôi phục commit bị mất, hoàn tác thay đổi và so sánh các phiên bản trước của công việc.

Lệnh git reflog cơ bản

Dưới đây là lệnh reflog cơ bản:

git reflog

Lệnh trên hiển thị danh sách các hành động gần đây đã cập nhật HEAD hoặc tham chiếu nhánh, bao gồm commit, chuyển nhánh, reset, rebase và hơn thế nữa. Mỗi mục được đánh chỉ mục, như HEAD@{0} và HEAD@{1}, để biểu thị vị trí của nó trong lịch sử reflog.

Tham chiếu các trạng thái trước đây

Git reflog đóng vai trò như bản ghi các cập nhật tham chiếu trong quá khứ, cho phép chúng ta định vị và khôi phục các điểm trước đó trong lịch sử kho. Nếu không có nó, các tham chiếu này sẽ không tồn tại và chúng ta sẽ phải cần chính xác mã băm commit để quay lại các trạng thái cụ thể trong quá khứ. Giờ hãy xem Git cho phép chúng ta điều hướng các trạng thái trước đây này bằng git checkout như thế nào.

HEAD@{n}: Chỉ một mục reflog cụ thể, trong đó n là chỉ số. Ví dụ, HEAD@{2} là trạng thái thứ ba gần đây nhất của HEAD.

git checkout HEAD@{2}

Sử dụng git checkout để theo dõi các thay đổi trước đây.

Sử dụng git checkout để theo dõi các thay đổi trước đây. Ảnh: Tác giả.

branch@{time}: Chỉ trạng thái của một nhánh tại một thời điểm cụ thể. Ví dụ, main@{1.week.ago} là trạng thái của nhánh main một tuần trước, còn feature@{yesterday} là trạng thái của nhánh feature vào ngày hôm qua.

git checkout main@{1.week.ago}

Sử dụng git checkout để theo dõi các thay đổi trước đây.

Sử dụng git checkout để theo dõi các thay đổi trước đây. Ảnh: Tác giả.

Bổ ngữ theo mốc thời gian

git reflog không chỉ giúp chúng ta khôi phục các trạng thái trước đây mà còn cho phép chúng ta so sánh chúng. Vì reflog theo dõi các cập nhật tham chiếu, ta có thể dùng nó để xem kho đã thay đổi như thế nào theo thời gian. Bây giờ, hãy xem git diff sử dụng các mục reflog để so sánh trạng thái quá khứ và hiện tại ra sao.

Dưới đây là các ví dụ về bổ ngữ thời gian giúp bạn khôi phục kho về một thời điểm cụ thể thay vì chỉ dựa vào số chỉ mục reflog.

git checkout HEAD@{1.minute.ago}     # Trạng thái từ một phút trước
git checkout HEAD@{1.hour.ago}       # Trạng thái từ một giờ trước
git checkout HEAD@{1.week.ago}       # Trạng thái từ một tuần trước
git checkout HEAD@{yesterday}        # Trạng thái của ngày hôm qua
git checkout HEAD@{2024-01-01.12:00:00} # Trạng thái tại một mốc thời gian cụ thể

So sánh các trạng thái trước đây với git diff

Bạn có thể so sánh các trạng thái trước đây bằng các lệnh như git diff. Lệnh sau so sánh trạng thái hiện tại của nhánh chính main@{0} với trạng thái của nó từ một ngày trước, main@{1.day.ago}. Đầu ra sẽ hiển thị mọi khác biệt giữa hai ảnh chụp này.

git diff main@{0} main@{1.day.ago}

So sánh các trạng thái trước đây với git diff.

So sánh các trạng thái trước đây với git diff. Ảnh: Tác giả.

Các trường hợp sử dụng thường gặp của Git Reflog

Git reflog là công cụ vô giá để khôi phục thay đổi bị mất, hoàn tác lỗi và sửa các trục trặc Git thường gặp. Dưới đây là một số tình huống thực tế nơi git reflog có thể giúp bạn.

Hoàn tác một lệnh reset lỗi

Nếu bạn lỡ reset nhánh bằng git reset --hard, bạn có thể dùng reflog để khôi phục trạng thái trước đó.

git reset --hard HEAD@{3}

Khôi phục các commit bị mất

Nếu bạn vô tình xóa một nhánh hoặc mất commit do reset hay rebase, bạn có thể tìm commit bị mất bằng git reflog.

git reflog

Xác định mã băm commit từ đầu ra reflog và checkout nó:

git checkout <commit-hash>

Khi đã xác minh commit bị mất, bạn có thể tạo nhánh mới để lưu giữ nó:

git branch recovered-branch <commit-hash>

Sửa một lần rebase hỏng

Nếu rebase gặp trục trặc, bạn có thể dùng git reflog để tìm commit trước rebase và reset nhánh của mình. Xác định commit trước rebase và reset về đó.

git reset --hard HEAD@{3}  # Điều chỉnh con số dựa trên đầu ra reflog

Khôi phục nhánh đã xóa

Nếu bạn vô tình xóa một nhánh, bạn có thể khôi phục nó bằng git reflog. Tìm commit cuối cùng đã biết của nhánh bị xóa và tạo lại nhánh:

git branch restored-branch <commit-hash>

Theo dõi lịch sử stash

Git reflog cũng có thể dùng để xem lịch sử stash. Lệnh dưới đây liệt kê các thao tác stash, cho phép bạn khôi phục các stash cũ khi cần. 

git reflog stash

Để áp dụng một mục stash trước đó, dùng lệnh sau:

git stash apply stash@{2}

Xem hướng dẫn Git Pull Force: Cách ghi đè một nhánh cục bộ bằng nhánh từ xa để học các thực tiễn tốt nhất khi ghi đè thay đổi cục bộ.

Các lệnh con và tùy chọn của Git Reflog

Git cung cấp một số lệnh con và tùy chọn để quản lý và tương tác với reflog. 

Các lệnh con của git reflog

Dưới đây là phần tổng hợp có cấu trúc về các lệnh con git reflog quan trọng và cách sử dụng chúng.

git reflog show: Hiển thị các mục reflog cho HEAD theo mặc định hoặc cho một tham chiếu được chỉ định như nhánh.

git reflog show

Sử dụng git reflog show để hiển thị các mục cho tham chiếu chỉ định.

Sử dụng git reflog show để hiển thị các mục cho tham chiếu chỉ định. Ảnh: Tác giả.

git reflog list: Lệnh này hiển thị tất cả tham chiếu có reflog. Hữu ích để xác định các nhánh và tham chiếu HEAD có mục reflog được lưu trữ.

git reflog list

git reflog delete <ref>@{<specifier>}: Dọn dẹp các mục reflog cũ vượt quá giới hạn thời gian chỉ định. Ví dụ, lệnh sau xóa các mục cũ hơn 30 ngày.

git reflog expire --expire=30.days.ago

git reflog delete <ref>@{<specifier>}: Xóa một mục reflog cụ thể dựa trên tham chiếu và vị trí của nó. Lệnh dưới đây xóa mục reflog tại chỉ mục 2 của HEAD.

git reflog delete HEAD@{2}

git reflog exists <ref>: Kiểm tra liệu có reflog cho một tham chiếu cụ thể hay không. Ví dụ, lệnh dưới đây trả về thành công nếu nhánh main có reflog.

git reflog exists main

Tùy chọn cho các lệnh con git reflog

Dưới đây là các tùy chọn có sẵn cho các lệnh con git reflog và cách sử dụng chúng.

--expire-unreachable=<time>: Chỉ cắt tỉa các mục reflog không thể truy cập từ bất kỳ tham chiếu nào. Ví dụ, lệnh dưới đây xóa các mục reflog không thể truy cập cũ hơn 7 ngày.

git reflog expire --expire-unreachable=7.days.ago

--all: Xử lý reflog cho tất cả tham chiếu, không chỉ HEAD. Lệnh dưới đây dọn dẹp mọi reflog cũ hơn 60 ngày trên tất cả nhánh.

git reflog expire --expire=60.days.ago --all

--dry-run: Mô phỏng việc thực thi lệnh, hiển thị những gì sẽ bị cắt tỉa mà không thực sự xóa gì cả. Ví dụ, lệnh dưới đây hiển thị các mục sẽ bị xóa.

git reflog expire --expire=30.days.ago --dry-run

--verbose: Cung cấp đầu ra chi tiết về các hành động lệnh thực hiện. Lệnh dưới đây hiển thị thông tin chi tiết khi loại bỏ các mục reflog cũ.

git reflog expire --expire=90.days.ago --verbose

Git Reflog so với Git Log: Những khác biệt chính

Cả git log và git reflog đều mang lại thông tin về lịch sử của kho, nhưng chúng phục vụ các mục đích khác nhau. Hãy xem những khác biệt này để hiểu cách mỗi công cụ có thể được dùng cho chiến lược kiểm soát phiên bản và khôi phục.

  • git log hiển thị lịch sử commit bằng cách theo dõi phả hệ của các commit trong một nhánh. Nó cung cấp cái nhìn theo trình tự thời gian về cách nội dung của kho phát triển.

  • git reflog ghi nhận các cập nhật đến tham chiếu như HEAD, nhánh và stash, bao gồm các hành động như chuyển nhánh, reset, rebase, v.v. Nó theo dõi các thay đổi có thể không nằm trong phả hệ commit.

  • git reflog chỉ tồn tại cục bộ trên máy của bạn và không được chia sẻ với kho từ xa.

  • Trong khi git log không thể khôi phục các commit không còn nằm trong phả hệ nhánh, git reflog có thể giúp khôi phục các commit “bị mất” bằng cách theo dõi cập nhật tham chiếu, ngay cả khi các commit đó không còn truy cập được từ bất kỳ nhánh nào.

Bảng dưới đây tóm tắt những khác biệt chính này.

Tính nănggit loggit reflog
Theo dõi commitCóKhông
Theo dõi cập nhật tham chiếuKhôngCó
Chia sẻ trên kho từ xaCóKhông
Có thể khôi phục commit bị mấtKhôngCó

Thực tiễn tốt nhất khi sử dụng Git Reflog

Git reflog là công cụ mạnh mẽ để khôi phục commit bị mất và sửa các vấn đề lịch sử, nhưng để dùng hiệu quả cần sự thận trọng. Dưới đây là một số thực tiễn tốt nên áp dụng khi làm việc với reflog.

  • Dùng Reflog cho Khôi phục và Gỡ lỗi: Nếu bạn lỡ reset hoặc rebase nhánh sai cách, hãy kiểm tra git reflog để tìm tham chiếu trước đó và khôi phục nó.

  • Thận trọng với git reset --hard: git reset --hard có thể xóa vĩnh viễn các thay đổi chưa commit. Luôn kiểm tra reflog trước để đảm bảo bạn có thể khôi phục nếu có sự cố.

  • Sao lưu trước khi chạy các lệnh phá hủy dữ liệu: Để chống mất dữ liệu, hãy triển khai sao lưu tự động cho các kho Git của bạn. Luôn lưu sao lưu ở vị trí an toàn, tách biệt để đảm bảo có thể khôi phục trong trường hợp hỏng hóc phần cứng hoặc thảm họa khác.

  • Đừng chỉ dựa vào Reflog cho khôi phục dài hạn: Theo mặc định, các mục reflog được giữ trong 90 ngày. Sau khoảng thời gian này, chúng có thể bị dọn rác và không thể khôi phục. Hãy thường xuyên đẩy commit của bạn lên kho từ xa để đảm bảo chúng được lưu giữ ngoài reflog cục bộ.

  • Dùng git reflog expire để quản lý mục cũ: Nếu reflog của kho trở nên lộn xộn, hãy cắt tỉa các mục cũ hoặc không thể truy cập bằng git reflog expire.

Kết luận

Quản lý hiệu quả lịch sử dự án trong Git đòi hỏi nhiều hơn các lệnh cơ bản. Khai thác các công cụ nâng cao theo dõi cập nhật tham chiếu có thể cung cấp một “lưới an toàn” quý giá để khôi phục commit bị mất, khôi phục nhánh đã xóa và sửa lỗi. Trải nghiệm thực hành với các công cụ này, cùng với các lệnh như git reset, git checkout và git revert, có thể nâng cao đáng kể năng lực của bạn trong kiểm soát phiên bản.

Việc tham gia các khóa học của chúng tôi không chỉ là cách tuyệt vời để học mà còn là cách thể hiện với nhà tuyển dụng rằng bạn nghiêm túc với phát triển phần mềm. Vì mục tiêu đó, tôi khuyến nghị bạn đọc bài blog Top 20 câu hỏi và trả lời phỏng vấn Git cho mọi cấp độ và tham gia lộ trình kỹ năng Git Fundamentals mới của chúng tôi để trở thành chuyên gia về Git.

Allan Ouko

Tác giả

Allan Ouko

Biên tập viên kỹ thuật về Khoa học dữ liệu với kinh nghiệm thực tế trong phân tích dữ liệu, trí tuệ doanh nghiệp và khoa học dữ liệu. Tôi viết nội dung thực tiễn, tập trung vào ngành về SQL, Python, Power BI, Databricks và kỹ thuật dữ liệu, dựa trên công việc phân tích trong thế giới thực. Bài viết của tôi kết nối chiều sâu kỹ thuật với tác động kinh doanh, giúp các chuyên gia chuyển đổi dữ liệu thành những quyết định vững chắc.

Câu hỏi thường gặp về git reflog

Git reflog là gì?

Git reflog là nhật ký tham chiếu theo dõi các cập nhật đến đầu nhánh và HEAD, giúp người dùng khôi phục commit bị mất và hoàn tác lỗi.

Git reflog khác Git log như thế nào?

git log theo dõi lịch sử commit, còn git reflog ghi nhận thay đổi của các tham chiếu như HEAD và nhánh.

Git reflog có được chia sẻ với kho từ xa không?

Không, git reflog là cục bộ và không được chia sẻ khi đẩy lên kho từ xa.

Reflog có theo dõi các thay đổi chưa commit không?

Không, reflog chỉ theo dõi thay đổi của tham chiếu và không ghi nhận công việc chưa commit.

Những hành động nào tạo mục reflog?

Commit, checkout nhánh, reset, rebase, merge và thao tác stash đều tạo mục reflog.

Mục reflog tồn tại trong bao lâu?

Theo mặc định, các mục reflog hết hạn sau 90 ngày, nhưng có thể cấu hình được.

Chủ đề

Liên quan