撤销更改

相信你已经了解了 git 的基本概念,也清楚了工作区,暂存区和版本库的关系,现在让我们用所学的知识继解决实际问题吧!

背景

正常看得见的目录是我们最为熟悉的工作区,在工作中不可能总是100%的精力,难免会犯错,尤其是下午犯困,晚上加班更是如此.下面列举了常见的一些场景

  • 场景一: 工作区出现意外更改且尚未添加到暂存区

北京时间现在是晚上10点钟,你正在赶制一份工作报告,尽管心中一万个不愿意,还是不得不做.

开始模拟意外更改前,先查看一下 test.txt 文件相关信息:

# 列出当前目录的文件
$ ls
file1.txt file2.txt file3.txt newFile.txt test.txt
# 查看 `test.txt` 文件内容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
# 查看 `test.txt` 文件状态
$ 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: test.txt Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store no changes added to commit (use "git add" and/or "git commit -a")
# 查看 `test.txt` 文件差异
$ git diff
diff --git a/test.txt b/test.txt
index d31bdd2..56c76b7 100644
--- a/test.txt
+++ b/test.txt
@@ -3,4 +3,4 @@ git init
git diff
understand how git control version
how git work
-git tracks changes
+git tracks changes of files
$

还记得在上一节中我们讲解 git 版本控制的到底是什么,为了证明 git 管理的是更改而不是文件本身,我们特意在第二次更改时没有添加到暂存区,现在我们先把这个遗留问题解决掉.

# 工作区更改添加到暂存区
$ git add test.txt
# 暂存区内容提交到版本没哭
$ git commit -m "git tracks changes of files"
[master b7bda05] git tracks changes of files
1 file changed, 1 insertion(+), 1 deletion(-)
# 查看文件状态
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track)
$

现在正在加班加点干活,一不小心将心中的不满表露出来了,于是有了下面的内容:

# 意外更改正是这么犯傻的一句话
$ echo "My stupid boss still prefers svn" >> test.txt
# 当前文件内容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
My stupid boss still prefers svn
$

虽然强打精神,可还是很困,于是打算喝杯咖啡提提神,猛然发现 stupid boss 可能会让你丢掉这个月的奖金!

暗自庆幸,咖啡果然是个好东西,既然发现了问题,那就事不宜迟赶紧修复,因为不适宜的话正是 stupid boss ,所以你完全可以手动删除,但是假如你说了一大堆不合适的话,或者复制粘贴时弄错了,这就不是删除一两行那么简单了!

既然手动解决比较麻烦,那git 有没有什么好方法来解决这类问题呢?在寻求git 帮助前,首先再看一下当前文件状态(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: test.txt Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store no changes added to commit (use "git add" and/or "git commit -a")
$

git 不负众望,果然给了我们希望,(use "git checkout -- <file>..." to discard changes in working directory) 这句话的告诉我们可以丢弃工作区的更改!

脑海中在快速回忆一下工作区,暂存区,版本库三者之间的关系,其实git checkout -- <file> 命令的意思是用暂存区的内容替换掉工作区内容,因此也就是丢弃掉工作区的更改了.

事不宜迟,运行 git checkout -- <file> 命令试试看吧:

# 丢弃工作区的更改
$ git checkout -- test.txt
# 查看文件内容: My stupid boss still prefers svn 终于不见了
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
# 查看文件状态
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track)
$

一顿操作猛如虎,撤销掉意外更改,回到上一次版本控制状态,世界如此美好...

注意: git checkout -- <file> 中的 -- 至关重要,没有它就是切换分支了!

  • 场景二: 工作区出现意外更改且已经添加到暂存区,但尚未提交到版本库

时间一分一秒过去了,转眼间已经11点了,假设你不但写了一些胡话,还添加到暂存区了(git add).可想而知,这次意外比场景一要糟糕.

# 模拟正常提交(不然岂不是从场景一到场景二你什么都没做,那还能叫做赶制工作报告吗?!)
$ echo "someone prefers svn,but i don't care it" >> test.txt
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
$ git add test.txt
$ git commit -m "normal commit"
[master ab1cbd2] normal commit
1 file changed, 1 insertion(+) # 意外更改的前夕
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it # 意外更改内容: my teammate is stupid too.
$ echo "my teammate is stupid too." >> test.txt
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too. # 意外操作: 将意外更改内容提交到暂存区
$ git add test.txt

不过庆幸的是,在提交到版本库(git commit)之前及时发现问题,还是看一下现在的文件状态(git status)吧!

# 查看文件状态: 救命稻草 (use "git reset HEAD <file>..." to unstage)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage) modified: test.txt Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store $

git 同样告诉我们,可以使用 git reset HEAD <file> 命令撤销暂存区更改.

其实 git reset HEAD <file> 命令是用版本库的内容替换掉暂存区的内容,也就是说原来暂存区的内容已被丢弃了!

所以说这个命令并不会影响工作区内容,不如我们现在再看一眼工作区内容,方便执行 git reset HEAD <file> 命令后证实我们的结论.

# 查看文件内容: my teammate is stupid too.
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too.
$

迫不及待执行 git reset HEAD <file> 命令,先睹为快!

# 救命稻草: 版本库内容替换掉暂存区内容
$ git reset HEAD test.txt
Unstaged changes after reset:
M test.txt # 效果: 目标文件已修改但未添加到暂存区
$ 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: test.txt Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store no changes added to commit (use "git add" and/or "git commit -a") # 目标文件内容: 仍然保持不变
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
my teammate is stupid too.
$

现在场景二已经退化成场景一了,目标文件发生意外更改但还没添加到暂存区,如何撤销工作区更改,请参考场景一方法.

提示: git checkout -- test.txt

  • 场景三: 工作区出现意外更改不仅已添加到暂存区,还已提交到版本库,但尚未推送到远程仓库

时间不紧不慢地已经到凌晨了,困意越来越浓,洋洋洒洒写下几千字的工作报告,总算是写完了,添加到暂存区(git add),提交到版本库(git commit)一气呵成,等等,好像有什么不对劲,难免会犯糊涂,这不又发生意外了!

# 衔接场景二
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it # 正常提交一
$ echo "i love working,work makes me happy" >> test.txt
$ git add test.txt
$ git commit -m "encourage myself"
[master a44cf7a] encourage myself
1 file changed, 1 insertion(+) # 正常提交二
$ echo "fix 110 bugs,so happy" >> test.txt
$ git add test.txt
$ git commit -m "fix bugs"
[master c66399d] fix bugs
1 file changed, 1 insertion(+)
sunpodeMacBook-Pro:demo sunpo$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track) # 意外更改: hate to work overtime
$ echo "hate to work overtime" >> test.txt
$ git add test.txt
$ git commit -m "test.txt"
[master c965724] test.txt
1 file changed, 1 insertion(+)
$

天妒英才,加班加点做事情,本想赢得老板的赏识,没想到最后一句话"hate to work overtime"让所有的努力都付之一炬,怎么办?

死马当活马医,还是照例看看git status 能提供什么建议吧!

$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track)
$

没有提供任何意见能帮助我们撤销意外更改,先别慌,容我深思三秒钟...

既然意外更改已经提交到版本库,那么应该用什么内容替换版本库内容呢?有了,既然最新版本库不可用,那上一个版本库内容可用的啊,完全可以用上一个版本库内容替换最新版本库内容,真乃"天生我材必有用"!

# 当前文件内容: 闯祸的"hate to work overtime"
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
i love working,work makes me happy
fix 110 bugs,so happy
hate to work overtime # 版本回退: 回到过去假装什么都没发生过
$ git reset --hard HEAD^
HEAD is now at c66399d fix bugs
sunpodeMacBook-Pro:demo sunpo$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track) # 岁月静好,一切似乎都没发生过
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
someone prefers svn,but i don't care it
i love working,work makes me happy
fix 110 bugs,so happy # 当前文件状态
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed) .DS_Store nothing added to commit but untracked files present (use "git add" to track)
$

详情请参考回到过去,时空穿越之旅就是这么方便哈!

提示: git reset --hard HEAD^

  • 场景四: 工作区出现意外更改不仅已添加到暂存区,还提交到版本库,还已推送到远程仓库

场景一到场景三都是本地仓库,所有的文件更改只能本机访问,小伙伴也好,上级领导也罢都无法查看到你本地更改,但是一旦你推送到远程仓库了,那么其他人就能查看你的更改了!

正常的提交更改还好,怕就怕这种"stupid boss"被领导看到就不好了,那应该怎么办?暂时还是自求多福吧!

小结

  • 丢弃工作区更改: git checkout -- <file>
  • 丢弃暂存区更改: git reset HEAD <file>
  • 丢弃本地版本库更改: git reset --hard HEAD^
  • 丢弃远程版本库更改: 自求多福

原文请访问 https://snowdreams1006.github.io/git/usage/checkout-reset.html

git 入门教程之撤销更改的更多相关文章

  1. git 入门教程

    git 入门教程之协同开发 前面我们已经介绍过远程仓库的相关概念,不过那时并没有深入探讨,只是讲解了如何创建远程仓库以及推送最新工作成果到远程仓库,实际上远程仓库对于团队协同开发很重要,不仅仅是团队协 ...

  2. 廖雪峰Git入门教程

    廖雪峰Git入门教程  2018-05-24 23:05:11     0     0     0 https://www.liaoxuefeng.com/wiki/00137395163059296 ...

  3. git 入门教程之分支总览

    分支就是一条独立的时间线,既有分支,必有主干,正如一棵树谈到树枝,必有树干一样的道理.我们先前对git 的全部操作默认都是在主干上进行的,这个主干也是一种特殊的分支,名为 master 分支. 无论是 ...

  4. git 入门教程之备忘录[译]

    备忘录[译] 创建 | Create 克隆一个已存在的仓库 | Clone an existing repository git clone git@github.com:snowdreams1006 ...

  5. git 入门教程之删除文件

    删除文件 回忆一下文件的常见操作,新增文件,修改文件,删除文件等,新增和修改文件都单独讨论过,现在我们来研究一下如何删除文件. 你可能会说删除文件还不简单啊,直接 rm -rf <file> ...

  6. git 入门教程之远程仓库

    远程仓库 如果说本地仓库已经足够个人进行版本控制了,那么远程仓库则使多人合作开发成为可能. 如果你只是打算自己使用git,你的工作内容不需要发布给其他人看,那就用不到远程仓库的概念. git 是分布式 ...

  7. git 入门教程之版本控制

    版本控制 我们知道 git 是分布式版本控制系统,所以称被控制对象是版本本身没错,但是从git 命令中发现,并没有版本这个名词,有的只是commit,所以前几节我一直称其为提交. 为了避免后续教程引发 ...

  8. git 入门教程之基本概念

    基本概念 了解工作区,暂存区和版本库的区别和联系有助于我们更好理解 git 的工作流程,了解命令的操作意图. git 和其他版本控制系统如 svn 的不同之处就是有暂存区的概念. 基本概念 工作区 | ...

  9. git入门教程,主要命令详解。

    准备工作 git clone url / ssh  ----------------------------------------------------------------------从git ...

随机推荐

  1. [原创]K8Cscan插件之多种方式系统版本探测

    [原创]K8 Cscan 大型内网渗透自定义扫描器 https://www.cnblogs.com/k8gege/p/10519321.html Cscan简介:何为自定义扫描器?其实也是插件化,但C ...

  2. [学习笔记]利用e-debug和GetWindowTextA破解CM课件

    本课是针对注册时候的报错弹窗不是信息框MessageBox,而是窗体的情况 首先打开课件看一下 既然课件是个易语言程序,那使用E-DEBUG试试 E-DEBUG打开课件,点击“start”,课件弹出登 ...

  3. rest-framework之APIView 序列化组件

    rest-framework之APIView 一 安装djangorestframework 方式一:pip3 install djangorestframework 方式二:pycharm图形化界面 ...

  4. DDD实战进阶第一波(十三):开发一般业务的大健康行业直销系统(订单上下文领域逻辑)

    前一篇文章主要讲了订单上下文的POCO模型,其中订单与订单项中有大量的值对象.这篇文章主要讲讲这些值对象以及订单项.订单相关的领域逻辑. 1.ProductSKUs值对象领域逻辑:ProductSKU ...

  5. 在Mac OSX上配置Appium+Android自动化测试环境

    前提准备 开始正文之前,你需要准备好一些基本条件: 1.安装好Mac OSX 操作系统的设备 2.能够访问中国局域网以外资源的方法(没有也行,但很痛苦) 3.已经安装好 homebrew 4.已经安装 ...

  6. JavaScript高级编程(1)——JavaScript初识

    一.javascript的简介 1.1 javascript的历史回顾. Javascript诞生于1995年.当时,它主要的目的是用来处理一些由服务器端处理的输入验证操作.在javascript没有 ...

  7. 关于Flutter初始化流程,我必须告诉你的是...

    1. 引言 最近在做性能优化的时候发现,在混合栈开发中,第一次启动Flutter页面的耗时总会是第二次启动Flutter页面耗时的两倍左右,这样给人感觉很不好.分析发现第一次启动Flutter页面会做 ...

  8. 从前端界面开发谈微信小程序体验

    本文由云+社区发表 作者介绍:练小习,2011年加入搜狐,负责搜狐相册的产品策划与前端开发.2015年后加入腾讯 ISUX (社交用户体验设计部),目前主要负责腾讯云的UI开发工作,专注于人机交互,有 ...

  9. Hive默认数据库修改配置

    此文是基于上一篇文章:Hive环境搭建及测试 因为Hive默认的数据库是derby,不支持同时开启两个./hive的命令终端: 而将Hive的默认数据库修改成mysql后,可以解决该问题. 仅在安装H ...

  10. Python爬虫之诗歌接龙

    介绍   本文将展示如何利用Python爬虫来实现诗歌接龙.   该项目的思路如下: 利用爬虫爬取诗歌,制作诗歌语料库: 将诗歌分句,形成字典:键(key)为该句首字的拼音,值(value)为该拼音对 ...