对开发人员或数据工程师来说,没有什么比在不想要的情况下意外删除git分支或重置提交更令人恼火的了。这就是为什么我很高兴分享我通过自己的经验学到的东西,希望我更早学到,那就是如何使用git reflog
。git reflog
是那些绝对值得学习的技术之一;如果你现在花点时间学习,以后就可以避免很大的麻烦。
虽然我将向您展示我发现在导航和从错误中恢复中非常有帮助的git reflog
,但我也想推荐我们的Git基础和GitHub概念介绍课程,以学习关于版本控制的所有知识。
git reflog是什么?
Git reflog,即引用日志,是记录Git仓库中分支提示和HEAD引用更新的本地跟踪机制。(在Git的上下文中,HEAD指的是您的工作目录和暂存区域基于的当前提交。)
与git log
不同,后者基于血统显示提交历史,展示提交在分支中如何连接,git reflog
捕获HEAD的所有移动,包括分支切换、变基、重置和提交。这使得reflog对于恢复丢失的提交和调试最近的操作非常有用。
何时创建reflog条目?
Reflog 条目是在您执行更改 HEAD 或分支引用状态的操作时创建的。常见情况包括以下:
-
使用
git commit
提交更改。 -
使用
git checkout branch_name
切换到不同的分支。 -
使用
git branch new_branch
创建新分支。 -
Rebasing
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或分支引用的操作列表,包括提交、分支切换、重置、变基等。每个条目都被索引,比如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
如果 rebase 操作出错,你可以使用 git reflog
命令找到 rebase 前的提交,并重置你的分支。识别 rebase 前的提交并进行重置。
git reset --hard HEAD@{3} # 根据 reflog 输出调整数字
恢复已删除的分支
如果你意外删除了一个分支,你可以使用 git reflog
来恢复它。找到已删除分支的最后已知提交并重新创建:
git branch restored-branch <commit-hash>
跟踪存储历史
Git reflog 还可以用于查看存储历史。下面的命令列出了存储操作,允许你在需要时恢复旧的存储。
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 exists <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、分支和存储)的更新,包括分支切换、重置、变基等操作。它跟踪可能不属于提交祖先的更改。 -
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方面的专家。