LV01-Git-04-Git本地仓库-04-撤销与版本回退
本文主要是Git中撤销与数据恢复的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
点击查看本文参考资料
参考方向 | 参考原文 |
Git 官网 | https://git-scm.com/ |
Git 官方文档 | https://git-scm.com/doc |
Pro Git Book | https://git-scm.com/book/zh/v2 |
Git 快速使用指南 | https://training.github.com/downloads/zh_CN/github-git-cheat-sheet/ |
Visual Git Cheat Sheet | https://ndpsoftware.com/git-cheatsheet.html#loc=index |
【说明】本节笔记的相关操作在Windows下进行,因为VS Code有个Git的插件,可以很直观的演示一些东西。由于Git安装后自带一个Git-Bash终端,所以就不用Win下的命令行啦,就用的这个终端,因为它里边的命令与Linux很类似,而windows中的命令行有些命令与linux并不相同,为了统一,还是用用Git自带的终端啦。另外VS Code是可以选择使用的终端的,我直接将VS Code使用的终端改成了git-bash,这样更方便一些。
一、文件准备
我们这里重新准备一个版本库用于这一节笔记的使用:
1 | git init |
二、撤销操作
1. 修改上次提交
1.1 情况说明
我们上边创建了一个空的readme.md文件,并且提交了,但是,现在我们希望创建一个test.c文件,并且将test.c这个文件的功能写入到readme文件中。
一般来讲,我们可以重新提交一次,但是这就意味着版本库中有两个提交记录,但是其实根本没必要有两个提交记录啊,readme文件本来就是记录一些说明信息的,那么现在我们既想将新文件提交上去,又不想产生两次提交记录,那么要怎么样解决呢?
1.2 命令说明
此时,为了解决上边的问题,我们可以运行带有 –amend
选项的提交命令来重新提交,这样可以避免让仓库历史纪录变得复杂,一般格式如下:
1 | git commit --amend -m "新的描述" # 如果不加-m参数,系统会让进行输入的 |
这个命令会将暂存区中的文件提交。 如果自上次提交以来我们还未做任何修改(例如,在上次提交后马上执行了此命令), 那么快照会保持不变,而我们所修改的只是提交信息。
当我们在修补最后的提交时,与其说是修复旧提交,倒不如说是完全用一个 新的提交 替换旧的提交。从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。
修补提交最明显的价值是可以稍微改进我们最后的提交,而不会让“啊,忘了添加一个文件”或者 “小修补,修正笔误”这种提交信息弄乱我们的仓库历史。
1.3 使用实例
1.3.1 查看文件状态
我们需要创建一个test.c文件,然后再修改readme文件,完成后,文件状态如下:
1.3.2 重新提交
我们重新提交这一次的修改:
1 | git add . |
然后,Git就会打开默认的编辑器,可以看到之前的提交信息,我们编辑后保存会覆盖原来的提交信息。
提交后如下图所示:
1.3.3 提交记录
我们使用自定义的git命令查看一下提交记录:
会发现,整个仓库就只有这一条提交记录。也就是我们第二次提交的结果代替了第一次提交,就相当于第一次提交没有存在一样。
2. 撤销对文件的修改
这部分说的文件修改还暂未提交到暂存库,也就是修改文件之后,git add
之前的状态。
2.1 情况说明
我们现在对test.c做一系列的修改,这个时候我们并未但是改完之后,这些修改我不想要了,我并不想保留对这个文件的修改,这个时候怎么办,一行一行吧修改的地方删掉吗?是个办法,对于我们测试文件来说,比较简单,倒无所谓,可是当我们在大型项目中开发,修改了大量的文件的时候,也不想保留修改这该怎么办?也一个一个改嘛,这显然是不现实的。
那么我们该如何方便地撤消修改——将它还原成上次提交时的样子(或者刚克隆完的样子,或者刚把它放入工作目录时的样子)? 幸运的是,git status
也告诉了我们应该如何做。
2.2 git status的提示
我们来修改一下test.c文件,然后看一下git status
命令有什么提示:
可以看到,有这么一句话:
1 | (use "git restore <file>..." to discard changes in working directory) |
这个命令其实就可以用于撤销我们对于文件的修改。
2.3 撤销命令
其实可以达到撤销未暂存的文件的修改的命令不仅仅上边这一个,还有一个checkout,具体为什么git status
命令没有给出提示,还不清楚,不过不重要,我们知道就可以了:
1 | git checkout -- <file>... |
<file>…可以是多个文件,当然要是我们向直接撤销所有文件的修改,那么可以直接用下边的两个命令:
1 | git checkout -- . |
需要特别注意,这两个命令是很危险的命令。 我们对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非我们确实清楚不想要对那个文件的本地修改了,否则最好不要使用这个命令。
2.4 使用实例
我们用git checkout
来试一下吧:
1 | git checkout -- test.c |
然后我们会看到如下信息:
如果我们仍然想保留对那个文件做出的修改,但是现在仍然需要撤消,我们将会在 Git 分支 介绍保存进度与分支,这通常是更好的做法。在 Git 中任何 已提交 的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 --amend
选项覆盖的提交也可以恢复 (阅读 数据恢复 了解数据恢复)。 然而,任何我们未提交的东西丢失后很可能再也找不到了。
3. 取消暂存的文件
这一部分是针对我们修改了文件,并且已经通过git add
添加到暂存区的文件。
3.1 情况说明
现在有这样的情况,我们已经修改了两个文件并且想要将它们作为两次独立的修改提交, 但是却意外地输入 git add *
或者git add .
暂存了它们两个。但是这两个文件我想作为两次提交,有两个提交记录便于追溯,那么如何只取消暂存两个中的一个呢?
3.2 git status的提示
我们来修改一下test.c和readme文件,然后看一下git status
命令有什么提示:
修改完毕后,我们将修改提交到暂存区,然后查看一下文件状态:
1 | git add . |
可以看到,有这么一句话:
1 | (use "git restore --staged <file>..." to unstage) |
这个命令其实就可以用于撤销我们对于文件的修改。
3.3 撤销命令
其实撤销提交到暂存区的修改为命令一共有两个,但是git提示只给出了一个:
1 | git restore --staged <file>... |
<file>…可以是多个文件,当然要是我们向直接撤销所有文件的修改,那么可以直接用下边的两个命令:
1 | git restore --staged . |
这两个命令没有想象中那么危险,我们取消暂存区的修改后,这些修改还保留在工作区,只是回到了我们刚修改完文件的状态。
3.4 使用实例
我们用git restore
来试一下吧:
1 | git restore --staged test.c |
然后我们会看到如下信息:
可以看到test.c文件已经回到了未提交到暂存库的状态了。
3.5 提交更新
我们将上面的更改提交到版本库中,方便后边继续使用此仓库做测试。
1 | git commit -m "feat:取消暂存文件测试(修改readme文件)" |
可以看到当前的提交记录如下:
三、版本回退
1. 情况说明
现在我们产生了v1、v2、v3三次提交,如下图所示,主要以test.c修改来做测试:
v1、v2和v3的提交,分别对应一行内容:
现在,我们不想要v2和v3的提交了,我现在需要回到版本v1,这该怎么办?
2. 跳到指定版本
Git给我们提供了一个命令,用于跳到指定的提交节点去,也可以叫版本回滚吧:
1 | git reset --hard <版本号> # 回到指定版本,版本号即为每次提交的hash值 |
3. 查看提交记录hash值
要想通过上边的命令来跳转到指定的版本,我们就需要知道这个指定的版本提交记录的hash值,我们有两个命令:
1 | git reflog # 查看所有提交记录(包括因为回滚丢失的记录) |
其实这里查看所有提交记录的时候,也可以使用 git log
指令来查看,那么该指令与 git reflog
区别在哪里呢?
git reflog
命令可以查看所有分支的所有操作记录信息,包括已经被删除的 commit 记录和 reset 的操作。git log
命令可以显示当前分支所有提交过的版本信息,不包括已经被删除的 commit 记录和 reset 的操作。(注意: 只是当前分支操作的信息)。
所以,当我们回滚版本回滚错了的时候,想要恢复回滚之前的版本的话, git reflog 就为该操作的实现提供了可能,后边会提到的。
4. 使用实例
4.1 查看提交记录
这一步主要是为了获取跳转的版本的hash值:
1 | git mylog # 用自定义的方便看 |
我们要想跳转到v1版本的话,它对应的hash值为b065bb7
。
4.2 跳转指定版本
我们现在执行下边的命令,跳转到v1提交的时候:
1 | git reset --hard b065bb7 |
执行完毕后,我们会得到以下提示:
然后我们再看一下提交记录和文件:
可以看到文件回到了v1版本的时候,并且提交记录也只剩下v1及以前了。
5. git reflog的应用
5.1 情况说明
上边我们已经跳转到v1的版本了,可是这个时候,突然发现v2版本也是很重要的,我现在想到v2版本去,可是那次提交貌似被我们丢掉了哎?怎么办?这个时候git reflog
就派上用场了。
5.2 查看所有提交记录
我们执行下边的命令,看一下会有什么输出:
1 | git reflog |
然后我们会得到以下输出信息:
这两个不就是我们的v2和v3的提交嘛,这样我就就可以获取这两次提交的hash值了,例如v2提交记录的hash为68b6e33
。
5.3 跳转到指定版本
我们执行以下命令跳转到v2版本的提交:
1 | git reset --hard 68b6e33 |
然后我们看一下文件和提交记录:
可以看到目前已经位于v2提交记录的版本啦。