Git 进阶系列 | 8. 用 Reflog 恢复丢失的提交

简介: Git 进阶系列 | 8. 用 Reflog 恢复丢失的提交

Git 是最流行的代码版本控制系统,这一系列文章介绍了一些 Git 的高阶使用方式,从而帮助我们可以更好的利用 Git 的能力。本系列一共 8 篇文章,这是最后一篇。原文:Using the Reflog to Restore Lost Commits[1]


“Reflog”是 Git 不太为人所知的特性之一,但可能非常有用。有些人把它称为“安全网”,而我喜欢把它看作 Git 的“日记”,因为 Git 用它来记录HEAD指针的每次移动(例如,每次提交、合并、rebase、cherry-pick、reset 等)。Git 会将操作记录在 Reflog 中,使它成为一个有价值的日志,当出现问题时,这是一个很好的起点。


在“Git 进阶”系列的最后一部分,我将解释git loggit reflog之间的区别,并展示如何使用 reflog 来恢复已删除的提交和已删除的分支。


Git 进阶系列:

  1. 创建完美的提交
  2. Git中的分支策略
  3. 基于Pull Request实现更好的协作
  4. 合并冲突
  5. Rebase vs Merge
  6. 交互式Rebase
  7. Git中的Cherry-pick提交
  8. 用Reflog恢复丢失的提交(本文)


git loggit reflog有什么区别?


在之前的文章中,我建议使用git log命令检查事件并查看提交历史,这正是它的工作。它可以显示当前的HEAD及其祖先,即父提交,下一个父提交,等等。git log通过递归打印每个提交的父节点来回溯提交历史,这是代码库的一部分,这意味着在 push、fetch、pull 之后这些信息都会被复制。


另一方面,git reflog是一个私有的、与工作空间相关的记录。它不遍历祖先列表。相反,它显示一个有序列表,包含HEAD过去所指向的所有提交。这就是为什么可以把它看作某种“撤销历史(undo history)”,就像在文字处理器、文本编辑器等中看到的那样。


技术上来说,这个本地记录不是代码库的一部分,它与提交分开存储。Reflog 是.git/logs/refs/heads/中的一个文件,用来跟踪每个分支的本地提交。Git 的日志通常会在 90 天后被清理(这是默认设置),但是可以轻松调整 Reflog 的过期日期。要将过期时间更改为 180 天,只需输入以下命令:


$ git config gc.reflogExpire 180.days.ago



image.png


仓库配置文件(.git/config)包含变量 reflogExpire,值为 180.days.ago

或者可以设置 Reflog 永不过期:


$ git config gc.reflogExpire never



提示: 记住,Git 区分了代码库的配置文件(.git /config)、每个用户的全局配置($HOME/.gitconfig)和系统全局设置(/etc/gitconfig)。要为用户或系统调整 Reflog 的过期时间,请在上面所示的命令后面添加--system--global参数。


好了,现在我们有了足够的理论背景知识,接下来可以展示如何使用git reflog来纠正错误。


恢复删除的提交


想象一下下面这个场景: 在查看了提交历史之后,我们决定删除最后两次提交。勇敢的执行了一次git reset后,两个提交从提交历史中消失了……过了一会儿,我们发现犯了个错误,我们丢失了有价值的更改,完蛋了!


image.png


真的要从头再来吗?不。换句话说,保持冷静,利用git reflog


所以,让我们尝试把事情搞砸,在现实生活中真的犯一下错。下图展示了我们最初在 Tower 中的提交历史:


image.png


我们想要删除两个提交,并将“Change headlines for about and imprint”提交(ID: 2b504bee)作为master分支上的最后一个修改。我们需要做的就是将哈希 ID 复制到剪贴板,然后在命令行中使用git reset并输入哈希:


$ git reset --hard 2b504bee



image.png


瞧。提交已经消失。现在,我们假设这是一个错误,并查看 Reflog 来恢复丢失的数据。在终端中输入git reflog查看日志:


image.png


有没有注意到所有条目都是按时间顺序排列的,这意味着顶部是最近的(也就是最新的)提交。如果仔细看,会注意到几分钟前致命的git reset操作就在顶部。


日记似乎起作用了,这是个好消息。因此,我们用它来撤销最后一个操作,并在执行 reset 命令之前恢复状态。与前面一样,将哈希 ID(在这个特定示例中为e5b19e4)复制到剪贴板,再次使用git reset,这完全有效。但在本例中,我将基于旧状态创建一个新分支:


$ git branch happy-ending e5b19e4



再看看图形化 Git 客户端:


image.png


如你所见,已经创建了新的happy-ending分支,包含了之前删除的提交。太棒了,什么都没丢!


接下来看看另一个示例,用 Reflog 来恢复整个分支。


恢复删除的分支


下面的示例和第一个场景类似,我们要删除一些东西,只是这一次要删除的是整个分支。也许你的客户或团队领导告诉你要摆脱一个特性分支,也许你自己想要进行清理。糟糕的是,有个提交(图中的C3)没有被包含在任何其他分支中,所以肯定会丢失数据:


image.png


我们来实际执行这个操作,稍后再恢复分支:


image.png


在删除分支feature/login之前,需要先切换出来。(正如截图中所示,这是当前的HEAD分支,不能在 Git 中删除HEAD分支。)所以,我们要切换分支(到master),然后删除feature/login:


image.png


好吧,假设我们的客户或团队领导改变了主意,现在又需要feature/login分支(包括它的提交)了,怎么办?


看看 Git 的日记:


$ git reflog
776f8ca (HEAD -> master) HEAD@{0}: checkout: moving from feature/login to master
b1c249b (feature/login) HEAD@{1}: checkout: moving from master to feature/login
[...]


我们又很幸运,最后一项显示了从feature/loginmaster的切换。我们尝试返回到之前的状态,将哈希 ID b1c249b复制到剪贴板,接下来,基于期望的状态创建一个名为feature/login的分支:


$ git branch feature/login b1c249b
$ git branch -vv
  feature/login b1c249b Change Imprint page title
* master        776f8ca Change about title and delete error page


太棒了,分支死而复生,仍然包含了我们认为已经丢失的有价值的提交:


image.png


如果使用像 Tower 这样的桌面 GUI,可以简单的按下CMD+Z来撤销最后一个操作,就像文本编辑器或文字处理器一样。


保持冷静,保证记录


Git 的 Reflog 可以成为真正的救星!如你所见,很容易将丢失的提交甚至整个分支从坟墓中带回来,只需要在 reflog 中找到正确的哈希 ID,其他都是小菜一碟。


如果想更深入了解高级 Git 工具,可以免费查看“Advanced Git Kit[3]”: 这是关于分支策略、交互式 Rebase、Reflog、子模块等主题的短视频集合。


本文是“Git 进阶”系列的最后一部分,希望你喜欢这些文章。编码快乐!


References:

[1] Using the Reflog to Restore Lost Commits: https://css-tricks.com/using-the-reflog-to-restore-lost-commits/


目录
相关文章
|
1天前
|
人工智能 数据可视化 开发工具
Git log 进阶用法(含格式化、以及数据过滤)
Git log 进阶用法(含格式化、以及数据过滤)
|
2月前
|
安全 Shell 网络安全
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
131 0
|
3月前
|
存储 Linux 开发工具
Python 进阶指南(编程轻松进阶):十二、使用 Git 组织您的代码项目
Python 进阶指南(编程轻松进阶):十二、使用 Git 组织您的代码项目
55 0
|
8月前
|
Shell 网络安全 开发工具
一些常用的 Git 进阶知识与技巧
一些常用的 Git 进阶知识与技巧
45 0
|
5月前
|
安全 网络安全 开发工具
Git的进阶操作,在idea中部署gie
Git的进阶操作,在idea中部署gie
|
6月前
|
前端开发 Cloud Native Go
《Git进阶:掌握版本控制的高级技巧》
《Git进阶:掌握版本控制的高级技巧》
33 0
|
6月前
|
Linux 网络安全 开发工具
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
|
8月前
|
数据采集 安全 JavaScript
代码版本管理笔记 | Python 程序员也应该会的 Git 进阶操作
代码版本管理笔记 | Python 程序员也应该会的 Git 进阶操作
118 0
|
持续交付 开发工具 git
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
如何保留原提交记录迁移Git项目,你还不知道吗?
|
Shell 开发工具 git
Git基础使用-如何用Git把代码提交至仓库/新建仓库/同步代码/推送代码
Git基础使用-如何用Git把代码提交至仓库/新建仓库/同步代码/推送代码
448 0