對於開發人員或數據工程師來說,沒有比意外刪除 git 分支或重置提交更令人惱火的事情了。這就是為什麼我很高興分享我通過自己的經驗學到並希望早點學到的東西,那就是如何使用 git reflog
。 git reflog
是其中一種絕對值得學習的技巧;如果你現在花一點時間學習,將來就可以避免一大場頭痛。
儘管我將向你展示我認為在導航和從錯誤中恢復方面非常有幫助的 git reflog
,但我也想推薦我們的 Git 基礎 和 GitHub 概念入門 課程,以學習有關版本控制的所有知識。
何謂 git reflog?
Git reflog,即參考日誌,是一種本地跟踪機制,記錄 Git 存儲庫中分支尖端和 HEAD 參考的更新。(在 Git 的上下文中,HEAD 指的是您的工作目錄和暫存區所基於的當前提交。)
與 git log
不同,後者基於祖先顯示提交歷史,顯示提交在分支中如何相連,git reflog
捕獲 HEAD 的所有移動,包括分支切換、rebase、重置和提交。這使得 reflog 用於恢復丟失的提交和調試最近的操作。
什麼時候創建 reflog 記錄?
Reflog條目是在您執行更改HEAD或分支引用狀態的操作時創建的。常見情況包括以下:
-
使用
git commit
提交更改。 -
使用
git checkout branch_name
切換到不同的分支。 -
使用
git branch new_branch
創建新分支。 -
重新定位
git rebase
-
重置到先前的提交
git reset --hard
。 -
合併分支使用
git merge
。
以下是用於跟踪本地存儲庫中更新的代碼:
git reflog
使用git reflog跟踪本地存儲庫中的更新。圖片由作者提供。
如何解釋git reflog的輸出?
您可以以下列方式解釋輸出:
-
HEAD@{0}
:最近的操作是切換到HEAD分支。 -
HEAD@{1}
:在那之前,我將一個文件類型從.xlxs
更改為.csv
格式。 -
HEAD@{2}
:當將文件推送到存儲庫時,我進行了第一次提交。
每個條目顯示:
-
提交哈希(
fa82776
) -
reflog 索引(
HEAD@{0}
,HEAD@{1}
,等等) -
操作描述(提交,檢出,重置)
如何使用 git reflog
Git reflog 提供了一种跟踪引用更新并恢复存储库先前状态的方法。通过理解如何浏览 reflog 条目,您可以恢复丢失的提交,撤消更改,并比较您工作的过去版本。
基本的 git reflog 命令
以下是基本的 reflog 命令:
git reflog
上述命令显示了最近更新 HEAD 或分支引用的操作列表,包括提交、分支切换、重置、rebase 等。每个条目都被索引,例如 HEAD@{0}
和 HEAD@{1}
,以表示其在 reflog 历史中的位置。
引用过去的状态
Git reflog 用作記錄過去參考更新,讓我們能夠找到並還原儲存庫歷史中的先前點。如果沒有它,這些參考將不存在,我們需要確切的提交哈希才能返回到特定的過去狀態。現在,讓我們探索 Git 如何讓我們使用 git checkout
來導航這些過去狀態。
HEAD@{n}
:指的是特定的 reflog 輸入,其中 n
是索引。例如,HEAD@{2}
指的是 HEAD 的倒數第三個最近狀態。
git checkout HEAD@{2}
使用 git checkout 追踪過去的變更。圖片由作者提供。
branch@{time}
: 指的是分支在特定时间点的状态。例如,main@{1.week.ago}
指的是主分支一周前的状态,而 feature@{yesterday}
指的是功能分支昨天的状态。
git checkout main@{1.week.ago}
使用 git checkout 跟踪过去的变化。图片由作者提供。
基于时间的限定符
git reflog
不仅帮助我们恢复过去的状态,还允许我们进行比较。由于 reflog
跟踪引用的更新,我们可以使用它来查看我们的仓库如何随时间变化。现在,让我们看看 git diff
如何利用 reflog 条目来比较过去和现在的状态。
以下是一些时间限定符的示例,这些限定符使得将仓库恢复到特定时间点变得容易,而不是仅仅依赖 reflog 索引号。
git checkout HEAD@{1.minute.ago} # 一分钟前的状态
git checkout HEAD@{1.hour.ago} # 一小时前的状态
git checkout HEAD@{1.week.ago} # 一周前的状态
git checkout HEAD@{yesterday} # 昨日狀態
git checkout HEAD@{2024-01-01.12:00:00} # 特定時間戳記的狀態
使用 git diff 比較過去的狀態
您可以使用像 git diff
這樣的命令來比較過去的狀態。以下命令將比較主分支 main@{0}
目前的狀態與一天前的狀態 main@{1.day.ago}
。輸出將顯示這兩個快照之間的任何差異。
git diff main@{0} main@{1.day.ago}
使用 git diff 比較過去的狀態。圖片由作者提供。
Git Reflog 的常見用例
Git reflog 是一個無價的工具,用於恢復丟失的更改,撤消錯誤,以及修復常見的 Git 失誤。以下是一些實際情況,git reflog
可以提供幫助。
撤消錯誤的重置
如果您誤操作使用 git reset --hard
重置分支,您可以使用 reflog 恢復到之前的狀態。
git reset --hard HEAD@{3}
找回丟失的提交
如果您意外刪除了分支或由於重置或rebase而丟失了提交,您可以使用git reflog
找回丟失的提交。
git reflog
從reflog輸出中找到提交的哈希並檢查它:
git checkout <commit-hash>
確認丟失的提交後,您可以創建一個新分支來保留它:
git branch recovered-branch <commit-hash>
修復失敗的rebase
如果重新定位操作出现问题,您可以使用git reflog
命令找到重新定位前的提交,并重置您的分支。识别重新定位之前的提交并重置它。
git reset --hard HEAD@{3} # 根据reflog输出调整数字
恢复已删除的分支
如果您意外删除了一个分支,您可以使用git reflog
来恢复它。找到已删除分支的最后已知提交,并重新创建它:
git branch restored-branch <commit-hash>
跟踪stash历史记录
Git reflog也可以用于查看stash历史记录。下面的命令列出了stash操作,让您在需要时恢复旧的stash。
git reflog stash
要應用先前的暫存條目,請使用以下命令:
git stash apply stash@{2}
查看我們的Git Pull Force: 如何用遠端覆蓋本地分支教程,了解覆蓋本地更改的最佳實踐。
Git Reflog 子命令和選項
Git 提供了幾個子命令和選項來管理和與 reflogs 進行交互。
Git reflog 子命令
以下是關鍵git reflog
子命令及其用法的結構化分解。
git reflog show
:默認顯示 HEAD 的 reflog 條目,或者顯示指定引用(如分支)的條目。
git reflog show
使用git reflog show來顯示指定引用的條目。圖片由作者提供。
git reflog list
:此命令顯示所有具有 reflog 的引用。它有助於識別具有存儲的 reflog 條目的分支和 HEAD 引用。
git reflog list
git reflog delete <ref>@{<specifier>}
:清理超出指定時間限制的舊 reflog 條目。例如,以下命令將刪除30天前的條目。
git reflog expire --expire=30.days.ago
git reflog delete <ref>@{<specifier>}
:根據其引用和位置刪除特定的 reflog 條目。下面的命令刪除了 HEAD 的索引 2
的 reflog 條目。
git reflog delete HEAD@{2}
git reflog 存在 <ref>
: 驗證特定參考的 reflog 是否存在。例如,下面的命令將在主分支有 reflog 時返回成功。
git reflog exists main
git reflog 子命令的選項
以下是 git reflog
子命令及其用法的選項。
--expire-unreachable=<time>
: 只清理從任何參考都無法達到的 reflog 條目。例如,下面的命令將刪除舊於 7 天的不可達 reflog 條目。
git reflog expire --expire-unreachable=7.days.ago
--all
: 處理所有參考的 reflogs,而不僅限於 HEAD
。下面的命令將清理所有分支上舊於 60 天的 reflogs。
git reflog expire --expire=60.days.ago --all
--dry-run
:模擬執行命令,顯示將要被修剪的內容,但不會實際刪除任何東西。例如,下面的命令顯示將要被刪除的項目。
git reflog expire --expire=30.days.ago --dry-run
--verbose
:提供有關命令執行的詳細輸出。下面的命令在清除舊的 reflog 項目時顯示詳細信息。
git reflog expire --expire=90.days.ago --verbose
Git Reflog vs. Git Log:主要區別
無論是 git log
還是 git reflog
都可以提供存儲庫歷史的洞察,但它們有不同的用途。讓我們了解這些區別,以便瞭解如何使用它們進行版本控制和恢復策略。
-
git log
通過跟踪分支上提交的祖先來顯示提交歷史。它提供了存儲庫內容進化的時間順序視圖。 -
git reflog
記錄對 HEAD、分支和暫存區等引用的更新,包括分支切換、重置、rebase 等操作。它跟蹤可能不屬於提交祖先的更改。 -
git reflog
嚴格限於您的本機並不與遠端存儲庫共享。 -
雖然
git log
無法恢復不再屬於分支祖先的提交,但git reflog
可以通過跟踪引用更新來幫助恢復“丟失”的提交,即使這些提交已不再從任何分支可達到。
下表總結了這些關鍵差異。
Feature | git log | git reflog |
---|---|---|
跟踪提交 | 是 | 否 |
跟踪引用更新 | 否 | 是 |
在遠端共享 | 是 | 否 |
可以恢復丟失的提交 | 否 | 是 |
使用Git Reflog的最佳實踐
Git reflog是一個用於恢復丟失的提交和修復歷史問題的強大工具,但要有效使用它需要小心。以下是在使用reflog時應遵循的一些最佳實踐。
-
用於恢復和調試的Reflog: 如果不小心重置或重新定義了一個分支,請檢查
git reflog
以查找先前的引用並恢復它。 -
謹慎使用
git reset --hard
:git reset --hard
可能永久刪除未提交的更改。請務必先檢查 reflog,以確保在出現問題時可以恢復。 -
在執行破壞性指令前請先備份:為防止資料遺失,請對 Git 存儲庫實施自動備份。始終將備份存儲在安全的離線位置,以確保在硬件故障或其他災難發生時可以恢復。
-
不要僅僅依靠Reflog進行長期恢復:默認情況下,Reflog條目保留90天。此後,它們可能被垃圾回收並變得不可恢復。定期將你的提交推送到遠程存儲庫,以確保它們在本地Reflog之外得到保存。
-
使用
git reflog expire
管理舊條目:如果您的存儲庫的reflog變得混亂,請使用git reflog expire
來修剪舊的或無法訪問的條目。
結論
在Git中有效管理項目的歷史記錄不僅僅需要基本命令。探索跟踪引用更新的高級工具可以為恢復丟失的提交、還原已刪除的分支和糾正錯誤提供有價值的安全網。通過這些工具以及像git reset
、git checkout
和git revert
這樣的命令的實踐經驗,可以顯著提高您在版本控制方面的能力。
參加我們的課程不僅是學習的好方法,也是向雇主表明您認真對待軟件開發的好方法。為此,我建議閱讀我們的所有級別的前20個Git面試問題和答案博客文章,並參加我們的新Git基礎知識技能培訓,成為Git方面的專家。