Git 撤销修改和版本回退

时间:2021-11-16 15:06:57

撤销修改

撤销修改是指将工作区中的修改撤销。

语法:git checkout 文件名或路径

# 撤销工作区中当前目录中的所有更改
git checkout .
 # 撤销工作区中指定文件的修改
git checkout -- filename

git checkout 命令只能撤销工作区中的修改,而不能撤销暂存区中的修改。

git checkout 命令还有一个非常重要的功能就是切换分支。可用于分支管理。

# 切换到已经存在的分支
git checkout master

# 切换分支的同时,创建分支 git checkout -b my-dev

这里,只是简单说一下 git checkout 如何切换分支,等你需要用到分支管理的时候,自然就明白了。

版本回退

版本回退是指将版本库从当前版本回退到其他的版本。

语法:git reset --hard 版本号

有时,我们需要将 Git 版本库回退(还原)到以前的某个版本,可以使用 git reset 命令。

在 Git 中,HEAD 指针指向的是当前版本,也就是最新的 commit id,上一个版本是 HEAD^,上上一个版本就是 HEAD^^,上50个版本可以写成 HEAD~50。

可以使用下面的命令,将 Git 回退到上一个版本:

git reset --hard HEAD^

这时,我们再来使用 git log 命令查看版本库被修改的日志。却发现,看不到被回退的版本之后的历史记录了。如果,想再回到最新的版本,怎么办?

只要刚刚的命令行窗口没有关掉,你就可以顺着往上面找,直到发现最新的版本号(如4b2a0c88a2d03675694013ac6a2bd6f55c830cdc),于是,就可以使用下面的命令还原到指定的版本:

git reset --hard 4b2a0c8

版本号(commit id)没必要写全,一般写前七位就够了,Git会自动去匹配。

但是,假如你回退到了某个版本后,把电脑关了。第二天又后悔了,想要恢复到最新版本。

这时,可以使用命令 git reflog 来查看你的每一次操作日志,该命令可以输出对应的版本号的操作记录。这样,我们就可以恢复到任意版本了。

git reset 的选项

git reset 有很多可用的选项。可以通过帮助命令来查看。

git reset -h

其中,最常用的三个选项是:

  • --mixed: reset HEAD and index。表示重置 HEAD 指针和 index 暂存区,但保持工作区不变。它是默认选项。
  • --soft: reset only HEAD。表示仅仅重置 HEAD 指针,即只改变 HEAD 的指向,但保持工作区和暂存区不变。
  • --hard: reset HEAD, index and working tree。表示重置 HEAD 指针、index 暂存区和工作区。这个才是完整的版本回退。

查看版本库的状态

git status

git status 命令非常有用。它可以查看版本库的当前状态,还可以看到相关操作的提示信息。

查看修改

如果你修改了工作区中的某些文件,想要查看具体更改了什么内容,可以使用 git diff 命令。

git diff .

git diff filename

查看工作区和版本库的区别

如果你只是修改了工作区,还没有 git add 到暂存区,想要查看工作区和版本库的区别。

# 查看工作区和版本库的区别
git diff

上述命令只能查看到工作区中已经存在的文件的修改,如果是新创建的文件,它追踪不到。如果修改和新文件已经 git add 到了暂存区,就需要使用下面的命令来查看。

查看暂存区和版本库的区别

如果你修改了工作区,已经 git add 到了暂存区,想要查看暂存区和版本库的区别。

git diff --cached

查看两个版本之间的区别

如果你修改了工作区,已经 git add 到了暂存区,并且 git commit 到了版本库。这样 head 指针就指向了最新的版本。想要比较两个版本之间的区别。

语法: git diff 版本号1 版本号2

# 比较两个版本之间的差异
git diff 4129523 0a7d9af

在这个例子中,412952 是上一个版本的版本号,0a7d9af 是当前的版本号(最新版本号)。只取前 7 位就够了。

# 比较之前的版本和当前版本的差异
git diff 4129523 head
 # 比较某个文件在两个版本之间的差异
git diff 09d9b45 head ./config/app.php
 # 比较之前的版本和当前版本的差异的简写形式
git diff 4129523

查看本地的两个分支的区别

语法格式为:git diff branch1 branch2

# 比较 develop 分支和 master 分支的区别
git diff develop master

查看本地分支和远程分支的区别

# 对比本地的 develop 分支和远程的 master 分支的区别
git diff develop origin/master

查看版本库的历史记录

如果你想查看版本库提交的历史记录 ,可以使用 git log 命令。

# 查看版本库的历史记录
git log

# 查看版本库的历史记录,美化输出
git log --pretty=oneline

# 查看版本库的历史记录,只显示前 5 
git log -5

git log -5 --pretty=oneline

git log 命令默认会进入日志查看模式,可按 q 退出查看模式。

git log 命令会显示从最近到最远的提交日志,每一行的前面的一大串字符就是 commit id(版本号),它和 SVN 的版本号不一样,Git 的版本号不是递增的数字,而是一个 SHA1 加密计算出来的一个非常大的数字,用十六进制表示。

场景分析

场景一

假如你只是修改了工作区,还没有 git add 到暂存区。可以使用下面的命令撤销工作区中的修改。

# 仅仅是撤销工作区中的修改
git checkout .

场景二

假如你修改了工作区,并把工作区中的修改 git add 到了暂存区。

如果你想撤销工作区和暂存区中的修改。

git reset --hard head
# 简写为
git reset --hard

如果你仅仅只是想要撤销暂存区中的修改。

git reset --mixed
# 简写为
git reset

场景三

假如你修改了工作区,并把工作区中的修改 git add 到了暂存区,然后又 git commit 提交到了版本库。

如果你想回退到上一个版本,可以使用下面的命令。

git reset --hard head^

查看当前的版本号,可以使用。

git rev-parse HEAD

需要注意的是,在 Windows 的 CMD 中, ^ 代表换行,即命令没输完,在下一行继续输命令。它相当于 Linux 中的 \ 。

因此,在 CMD 中回退到上一个版本的写法,就略有不同。

具体的解决方法有:

  • git reset --hard "head^"
  • git reset --hard HEAD^^
  • git reset --hard HEAD~
  • git reset --hard HEAD~1
  • 改用 PowerShell 或 Git Bash 终端

还有一个需要注意的问题是,通常我们所说的版本回退是指完整的版本回退。

如果你回退版本时,采用的是 『 git reset --mixed 版本号 』,--mixed 其实本来就是默认选项。那么,你只是更改了 head 的指向和回退了暂存区,而并没有回退工作区。如果想要继续把工作区也回退,你还需执行下面的命令

git checkout .

这样,才算完整的版本回退。

完整的版本回退,包含三个要素:

  • 更改 HEAD 指针的指向(即让 HEAD 指向目标版本)
  • 回退工作区(即工作区中的内容也要回退到目标版本)
  • 回退暂存区(即暂存区中的内容也要回退到目标版本)

为此,推荐使用 git reset --hard 来完成版本回退。