首页 > 代码库 > Git 撤销指南

Git 撤销指南

Git 撤销指南

Git 撤销有三个场景
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,用命令:git reset --hard commit_id不过前提是没有推送到远程库。

 

场景一

在熬夜加班时,你正在赶一份代码,你在readme.txt中添加了一行:

$ cat readme.txtGit is a distributed version control system.Git is free software distributed under the GPL.Git has a mutable index called stage.Git tracks changes of files.Git is not a good tool

在你准备提交前,突然发现发现了“Git is not a good tool”这句话是不对的!

如果用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会提示你,git checkout -- file可以丢弃工作区的修改:

$ git checkout -- readme.txt

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,就是让这个文件回到最近一次git commit或git add时的状态。

现在,看看readme.txt的文件内容:

$ cat readme.txtGit is a distributed version control system.Git is free software distributed under the GPL.Git has a mutable index called stage.Git tracks changes of files.

文件内容果然复原了。

git checkout -- file命令中的--很重要,没有--,就变成了“创建一个新分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。

 

场景二

加班愈发困了,你不但写错了,还git add到暂存区了:

$ cat readme.txtGit is a distributed version control system.Git is free software distributed under the GPL.Git has a mutable index called stage.Git tracks changes of files.My stupid boss still prefers SVN.

$ git add readme.txt

在commit之前,聪明的你发现了这个问题。用git status查看一下,修改只是添加到了暂存区,还没有提交:

$ git status

# On branch master# Changes to be committed:# (use "git reset HEAD <file>..." to unstage)## modified: readme.txt#

Git同样告诉我们,用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:

$ git reset HEAD readme.txtUnstaged changes after reset:M readme.txt

git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

再用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 -- readme.txt

 

$ git status

# On branch master

nothing to commit (working directory clean)

 

场景三

readme.txt文件一共有几个版本被提交到Git仓库里了:
版本1:wrote a readme file

Git is a version control system.

Git is free software.

版本2:add distributed

Git is a distributed version control system.

Git is free software.

版本3:append GPL

Git is a distributed version control system.

Git is free software distributed under the GPL.

在Git中,我们用git log命令查看:

$ git logcommit 3628164fb26d48395383f8f31179f24e0882e1e0Author: f_zhou <f_zhou@ctrip.com>Date: Tue Aug 20 15:11:49 2013 +0800 append GPL commit ea34578d5496d7dd233c827ed32a8cd576c5ee85Author: f_zhou <f_zhou@ctrip.com>Date: Tue Aug 20 14:53:12 2013 +0800 add distributed commit cb926e7ea50ad11b8f9e909c05226233bf755030Author: f_zhou <f_zhou@ctrip.com>Date: Mon Aug 19 17:51:55 2013 +0800 wrote a readme file

git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是“append GPL”,上一次是“add distributed”,最早的一次是“wrote a readme file”。

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

$ git log --pretty=oneline

3628164fb26d48395383f8f31179f24e0882e1e0 append GPLea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributedcb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file

我们现在回滚版本咯
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一样),

上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

现在,我们要把当前版本“append GPL”回退到上一个版本“add distributed”,

就可以使用git reset命令:

$ git reset --hard HEAD^

HEAD is now at ea34578 add distributed

看看readme.txt的内容是不是版本“add distributed”:

$ cat readme.txtGit is a distributed version control system.Git is free software.

还可以继续回退到上一个版本“wrote a readme file”,不过且慢,然我们用git log再看看现在版本库的状态:

$ git logcommit ea34578d5496d7dd233c827ed32a8cd576c5ee85Author: f_zhou <f_zhou@ctrip.com>Date: Tue Aug 20 14:53:12 2013 +0800 add distributed commit cb926e7ea50ad11b8f9e909c05226233bf755030Author: f_zhou <f_zhou@ctrip.com>Date: Mon Aug 19 17:51:55 2013 +0800 wrote a readme file

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向“append GPL”:

然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?

在Git中,总有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到“add distributed”版本时,再想恢复到“append GPL”,就必须找到“append GPL”的commit id。

Git提供了一个命令git reflog用来记录你的每一次命令:

$ git reflog ea34578 HEAD@{0}: reset : moving to HEAD^ 3628164 HEAD@{ 1 }: commit : append GPL ea34578 HEAD@{ 2 }: commit : add distributed cb926e7 HEAD@{ 3 }: commit (initial): wrote a readme file 

第二行显示“append GPL”的commit id是3628164,现在,你又可以乘坐时光机回到未来了。

要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本

 

 http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013744142037508cf42e51debf49668810645e02887691000

Git 撤销指南