撤销更改

相信你已经了解了 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. [Leetcode]895.最大频率栈

    Problem 实现 FreqStack,模拟类似栈的数据结构的操作的一个类. FreqStack 有两个函数: push(int x),将整数 x 推入栈中. pop(),它移除并返回栈中出现最频繁 ...

  2. 原生js的简单倒计时

    <!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>倒计 ...

  3. 一道关于:ArrayList、Vector、LinkedList的存储性能和特性 的面试题

    ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢 ...

  4. css笔记详解(1)

    css讲解 版权声明 本文原创作者:雨点的名字 作者博客地址:https://home.cnblogs.com/u/qdhxhz/ 首先在我们学习css之前先来思考一个问题,为什么html标签上不直接 ...

  5. Java后端工程师必备书单(含大后端方向相关书籍)

    学习Java和其他技术的资源其实非常多,但是我们需要取其精华去其糟粕,选择那些最好的,最适合我们的,同时也要由浅入深,先易后难.基于这样的一个标准,我在这里为大家提供一份Java的学习资源清单. 一: ...

  6. MySQL中支持emoji表情的存储

    由于需要实现emoji表情评论的功能,所以数据库需要支持emoji表情的存储,根据查询的资料最终实现了该功能,现将实现的过程以及过程遇到的一些问题记录下来,供大家参考和交流. mysql的utf8编码 ...

  7. ZOOKEEPER典型应用场景解析

    zookeeper实现了主动通知节点变化,原子创建节点,临时节点,按序创建节点等功能.通过以上功能的组合,zookeeper能够在分布式系统中组合出很多上层功能.下面就看几个常用到的场景,及使用方式和 ...

  8. shell脚本动画小工具

    shell脚本动画小工具 看gif图: shell脚本版 脚本内容如下: #!/usr/bin/env bash ## ---------------------------------------- ...

  9. Bootstrap-table使用总结(整合版)

    一.什么是Bootstrap-table? 在业务系统开发中,对表格记录的查询.分页.排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这 ...

  10. Android Studio 杀掉当前进程

    android.os.Process.killProcess( android.os.Process.myPid());