文章目录
前言
之前转载过一篇博文介绍了Git的三大分区,正是有这三大分区的存在,给Git操作创造了更多灵活性的空间,赋予了Git操作的“后悔药”。
本文针对Git操作中的版本回退和修改撤销进行一些介绍和总结。
提示:以下是本篇文章正文内容,下面案例可供参考
一、版本回退 (撤销commit修改)
如上图所示,Git有一个版本库的概念。每当你觉得文件修改到一定程度的时候,就可以进行一次commit提交,此时就好像是存储了一个当前版本。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。
版本查看
当我们想要回退到某一个版本的时候就需要知道我们都有哪些版本,也就是都进行了哪些commit
操作。此时就要使用git log
命令来查看提交历史,以便确定想要回退到那个版本去。
从上图中git log
显示的提交日志可以看出进行了4次提交,相当于是有4个版本。最近一次是第三次提交,上一次是第二次提交,以此类推。如果想要输出信息更简洁,方便查看都有哪些版本,可以在git log
命中后面加上--pretty=oneline
参数。
注意⚠️:每行前面黄色的一大长串就是一次commit的
commit id
(版本号)。Git的commit id
不同于SVN中的1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,
临近版本回退
知道如何查看版本后,就可以根据提交日志,确定我们要回退到那一个版本。一般情况下都是当前这个版本是想要放弃的,所以只需要回退到最近的上一个版本就好。让我们来看看如何操作。
首先这里你要知道,在Git中,用HEAD
表示当前版本,也就是最新的提交。所以上一个版本就用HEAD^
来表示,上上一个版本就是HEAD^^
,同理类推:往前多少个版本就在HEAD
上加多少个^
。当然这种情况下如果是往上非常多的版本(比如100),这种写法就不太实际,可以简写成HEAD~100
。
# 撤销上一次的提交
git reset --soft HEAD^
# 撤销输入数字n条commit记录
git reset HEAD~数字n
例如,我们把版本回退到上个版本(second time commit),就可以使用命令git reset
回退:
***deMacBook-Pro GitDemo % git reset --hard HEAD^
HEAD is now at 17798fe docs:This is the second time commit
看提示信息已经成功了,看看readme.txt的具体内容:
没有了third time commit,说明版本确实回退了。
指定版本回退
回退到上一版本后我们查看提交日志:
可以看到third time commit的记录完全没有了,这时候又后悔了,还想要third time commit 的版本怎么办?之前的回退是在已有的前任版本中回退,不适用于这种向后一个版本回退(回退的回退)。这就可以使用命令git reset --hard commit_id
指定到未来的某一个版本进行回退了:
***deMacBook-Pro GitDemo % git reset --hard ab8ef
HEAD is now at ab8ef0e docs: This is the third time commit
注意⚠️:版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了
查看readme.txt内容:
“third time commit”版本又回来了。
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向"third time commit"改为指向"second time commit"。然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。
这里有个问题是如果不记得未来某个版本的commit id
,git log
也没有了记录,该怎么办?这里Git中可以使用git reflog
记录每一次命令:
这样就知道未来版本的commit id
了。然后就可以指定版本回退了。
这里说明一下git reflog命令得到的结果:(以第4条结果为例分析)
17798fe
是 commit 的 SHA1 值,需要特别注意,它是移动后的 commit id。- HEAD@{3} 是标识这是 HEAD 指针3个移动前的指向内容(从当前往回数第4个操作),也就是上面的
17798fe
。commit
是表示造成这个移动的原因,是进行了 commit 操作。docs:This is the second time commit
表示操作的内容,commit 操作对应的就是 commit message。
git reflog <ref>
默认的是HEAD
指针,如果我们想查看其他的引用,换成对应的内容就可以。
//查看 master 分支指针的移动记录
git reflog master
//查看 test 分支指针的移动记录
git reflog test
git reset的模式
在上面的版本回退中,我们使用了git reset 命令来实现,在使用命令的时候我们加入了一个参数--hard
,这其实是指定一种模式。使用git reset help
命令可以看到一共有5中模式,比较常用的可以是以下三种:
- –soft
- –mixed(默认的模式)
- –hard
git reset --soft
只是将HEAD引用指向指定的提交,工作区跟暂存区的内容不会改变
git reset --mixed
(默认选项)将HEAD指向指定的提交,暂存区的内容随之改变,工作区内容不变
git reset --hard
将HEAD指向指定的提交,暂存区跟工作区都会改变
有兴趣的同学可以查看git使用手册自行研究一下,这里不多做说明了。
可以使用一下命令方式查看git使用手册:
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
二、修改撤销
如果说版本回退是针对每一次提交来进行的话,撤销修改就是针对文件的内容来进行的。
在工作区的修改撤销(撤销直接修改)
对readme.txt
文件进行内容修改,然后查看git status
会有类似下面的内容提示:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
可以看到可以使用git checkout -- file
丢弃工作区的修改:
git checkout -- readme.txt
这里注意⚠️:如果readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;如果readme.txt已经添加到暂存区后,才作了此次修改,现在,撤销修改就回到添加到暂存区后的状态。总之,就是让这个文件撤销到最近一次git commit或git add时的状态。
在暂存区的修改撤销(撤销add修改)
上面的修改撤销是在修改之后,没有进行add 和commit的操作,进行的修改撤销方式。如果某次修改之后,还git add
到暂存区了,但是还没有commit提交到版本库。可以使用命令git reset HEAD <filename>
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
在版本库的修改撤销(撤销commit修改)
假设你不但改错了东西,还从暂存区提交到了版本库,这时候就可以参照上半部分版本回退的讲解,回退到上一个版本。不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程。
总结
对于版本回退部分:
-
HEAD指向的版本就是当前版本,所以其实可以使用命令
git reset --hard commit_id
实现各种版本切换。 -
用
git log
可以查看提交历史,获得commit id等提交信息。 -
用
git reflog
查看命令历史,可以查看所有命令操作记录。
对于修改撤销部分:
- 想要直接丢弃工作区的修改,用命令
git checkout -- file
(注意中间是“–”,且左右都有空格) - 当在工作区修改了文件后还git add到了暂存区,要丢弃修改首先用
git reset HEAD <file>
命令丢弃修改到工作区(即第一条情况),然后按照第一条情况操作。 - 修改已经提交到版本库时,想要撤销修改的提交,需要进行版本回退操作(没有push到远程库)
git reset --soft 需要回退到的版本号
。 - 若已经push到远程库后也想回退,就需要完成版本回退操作后,强行推送到远程仓库:
//1.版本回退
git checkout 分支名
git reset --soft 需要回退到的版本号
//2.提交撤销动作到服务器,强制提交当前版本号
git push origin 分支名 --force