代码回滚:git reset、git checkout和git revert区别和联系
git reset、git checkout和git revert是你的Git工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件。
因为它们非常相似,所以我们经常会搞混,不知道什么场景下该用哪个命令。在这篇文章中,我们会比较git reset、git checkout和git revert最常见的用法。希望你在看完后能游刃有余地使用这些命令来管理你的仓库。
Git仓库有三个主要组成——工作目录,缓存区和提交历史。这张图有助于理解每个命令到底产生了哪些影响。当你阅读的时候,牢记这张图。
提交层面的操作
你传给git reset和git checkout的参数决定了它们的作用域。如果你没有包含文件路径,这些操作对所有提交生效。我们这一节要探讨的就是提交层面的操作。注意,git revert没有文件层面的操作。
Reset
在提交层面上,reset将一个分支的末端指向另一个提交。这可以用来移除当前分支的一些提交。比如,下面这两条命令让hotfix分支向后回退了两个提交。
git checkout hotfix
git reset HEAD~2
hotfix分支末端的两个提交现在变成了悬挂提交。也就是说,下次Git执行垃圾回收的时候,这两个提交会被删除。换句话说,如果你想扔掉这两个提交,你可以这么做。reset操作如下图所示:
如果你的更改还没有共享给别人,git reset是撤销这些更改的简单方法。当你开发一个功能的时候发现『糟糕,我做了什么?我应该重新来过!』时,reset就像是go-to命令一样。
除了在当前分支上操作,你还可以通过传入这些标记来修改你的缓存区或工作目录:
- --soft – 缓存区和工作目录都不会被改变
- --mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
- --hard – 缓存区和工作目录都同步到你指定的提交
把这些标记想成定义git reset操作的作用域就容易理解多了。
这些标记往往和HEAD作为参数一起使用。比如,git reset --mixed HEAD 将你当前的改动从缓存区中移除,但是这些改动还留在工作目录中。另一方面,如果你想完全舍弃你没有提交的改动,你可以使用git reset --hard HEAD。这是git reset最常用的两种用法。
当你传入HEAD以外的其他提交的时候要格外小心,因为reset操作会重写当前分支的历史。正如Rebase黄金法则所说的,在公共分支上这样做可能会引起严重的后果。
Checkout
你应该已经非常熟悉提交层面的git checkout。当传入分支名时,可以切换到那个分支。
git checkout hotfix
上面这个命令做的不过是将HEAD移到一个新的分支,然后更新工作目录。因为这可能会覆盖本地的修改,Git强制你提交或者缓存工作目录中的所有更改,不然在checkout的时候这些更改都会丢失。和git reset不一样的是,git checkout没有移动这些分支。
除了分支之外,你还可以传入提交的引用来checkout到任意的提交。这和checkout到另一个分支是完全一样的:把HEAD移动到特定的提交。比如,下面这个命令会checkout到当前提交的祖父提交。
git checkout HEAD~2
这对于快速查看项目旧版本来说非常有用。但如果你当前的HEAD没有任何分支引用,那么这会造成HEAD分离。这是非常危险的,如果你接着添加新的提交,然后切换到别的分支之后就没办法回到之前添加的这些提交。因此,在为分离的HEAD添加新的提交的时候你应该创建一个新的分支。
Revert
Revert撤销一个提交的同时会创建一个新的提交。这是一个安全的方法,因为它不会重写提交历史。比如,下面的命令会找出倒数第二个提交,然后创建一个新的提交来撤销这些更改,然后把这个提交加入项目中。
git checkout hotfix
git revert HEAD~2
如下图所示:
相比git reset,它不会改变现在的提交历史。因此,git revert可以用在公共分支上,git reset应该用在私有分支上。
你也可以把git revert当作撤销已经提交的更改,而git reset HEAD用来撤销没有提交的更改。
就像git checkout 一样,git revert 也有可能会重写文件。所以,Git会在你执行revert之前要求你提交或者缓存你工作目录中的更改。
文件层面的操作
git reset和git checkout 命令也接受文件路径作为参数。这时它的行为就大为不同了。它不会作用于整份提交,参数将它限制于特定文件。
Reset
当检测到文件路径时,git reset 将缓存区同步到你指定的那个提交。比如,下面这个命令会将倒数第二个提交中的foo.py加入到缓存区中,供下一个提交使用。
git reset HEAD~2 foo.py
和提交层面的git reset一样,通常我们使用HEAD而不是某个特定的提交。运行git reset HEAD foo.py 会将当前的foo.py从缓存区中移除出去,而不会影响工作目录中对foo.py的更改。
--soft、--mixed和--hard对文件层面的git reset毫无作用,因为缓存区中的文件一定会变化,而工作目录中的文件一定不变。
Checkout
Checkout一个文件和带文件路径git reset 非常像,除了它更改的是工作目录而不是缓存区。不像提交层面的checkout命令,它不会移动HEAD引用,也就是你不会切换到别的分支上去。
比如,下面这个命令将工作目录中的foo.py同步到了倒数第二个提交中的foo.py。
git checkout HEAD~2 foo.py
和提交层面相同的是,它可以用来检查项目的旧版本,但作用域被限制到了特定文件。
如果你缓存并且提交了checkout的文件,它具备将某个文件回撤到之前版本的效果。注意它撤销了这个文件后面所有的更改,而git revert 命令只撤销某个特定提交的更改。
和git reset 一样,这个命令通常和HEAD一起使用。比如git checkout HEAD foo.py等同于舍弃foo.py没有缓存的更改。这个行为和git reset HEAD --hard很像,但只影响特定文件。
总结
你现在已经掌握了Git仓库中撤销更改的所有工具。git reset、git checkout、和 git revert命令比较容易混淆,但当你想起它们对工作目录、缓存区和提交历史的不同影响,就会容易判断现在应该用哪个命令。
下面这个表格总结了这些命令最常用的使用场景。记得经常对照这个表格,因为你使用Git时一定会经常用到。
| 命令 | 作用域 | 常用情景 |
|---|---|---|
| git reset | 提交层面 | 在私有分支上舍弃一些没有提交的更改 |
| git reset | 文件层面 | 将文件从缓存区中移除 |
| git checkout | 提交层面 | 切换分支或查看旧版本 |
| git checkout | 文件层面 | 舍弃工作目录中的更改 |
| git revert | 提交层面 | 在公共分支上回滚更改 |
| git revert | 文件层面 | (然而并没有) |
代码回滚:git reset、git checkout和git revert区别和联系的更多相关文章
- git代码回滚:Reset、Checkout、Revert的选择
代码回滚:Reset.Checkout.Revert的选择 Zhongyi Tong edited this page on Dec 8, 2015 · 5 revisions Pages 19 Ho ...
- 代码回滚:Reset、Checkout、Revert的选择
代码回滚:Reset.Checkout.Revert的选择 Git仓库有三个主要组成——工作目录,缓存区和提交历史. 从图中我们可以看出,缓存区或者叫索引,其实是指一整套即将被下一个提交的文件集合.也 ...
- 代码回滚:Reset、Checkout、Revert 的选择
git reset.git checkout 和 git revert 是你的 Git 工具箱中最有用的一些命令.它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文 ...
- 转一篇Git代码回滚技巧
转 https://github.com/geeeeeeeeek/git-recipes/wiki/5.2-代码回滚:Reset.Checkout.Revert的选择
- Git配合Tag的代码回滚
现有的远程仓库版本的tag为v1.0 前置准备 具体操作: 我们在本地修改一下readme文件,然后进行add,commit操作. 再给我们的commit打上tag git tag -a v1.1 - ...
- 6.Git代码回滚
1.代码修改并提交 我们已经成功地添加并提交了一个helloWorld.txt文件,现在,是时候继续工作了. 于是,我们继续修改helloWorld.txt文件,改成如下内容: $ vi helloW ...
- gitlab基础命令之代码回滚
#:gitlab状态 root@ubuntu:~# gitlab-ctl status run: alertmanager: (pid 13305) 215965s; run: log: (pid 1 ...
- 利用PyCharm操作Github:仓库新建、更新,代码回滚
Github是目前世界上最流行的代码存储和分享平台,而PyCharm是Python圈中最流行的IDE,它很好地支持了Git操作.本文将会介绍如何利用PyCharm来连接Github,同时演示Git ...
- svn代码回滚命令
代码回滚提交: 比如要把73回滚到68 svn merge -r 73:68 http://my.repository.com/my/project/trunk 然后commit就行了 svn com ...
- gitlab一次代码回滚引起的bug...
问题描述:线上问题有一个bug,挺严重的.在线下排查后发现是一个之前的同事添加的代码影响的,为了不影响之前的业务,代码回滚了. 但是 过了几天,测人人员测试之后说这个问题又复现了,然后再次看,发现还是 ...
随机推荐
- 算术表达式解析(第二版) C++11版
//一个简单的计算器代码,主要用来练习C++11新标准的编程技术和stl应用 1 #include<iostream> #include<stack> #include< ...
- VS2010 有关测试的一些使用
Visual Studio 2010 单元测试之一---普通单元测试:http://blog.csdn.net/tjvictor/archive/2011/02/09/6175362.aspx V ...
- [NOIP2016]换教室 D1 T3 Floyed+期望DP
[NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...
- string类里find的用法
#include<bits/stdc++.h> using namespace std; typedef long long ll; //int INF=(1<<31)-1; ...
- Linux下定时执行任务的几种方式
如果说我说如果,你的某一个目录下会经常的生成一些垃圾文件,比如访问日志.错误日志.core文件,而你又不想过几分钟就去手动检查一下,那么可以使用定时执行任务的方式来解决.目前我所知道的可以执行定时任务 ...
- ArcEngine奇怪异常:HRESULT:0x80040351
错误如图 根据该博客,http://blog.csdn.net/u011609113/article/details/51155116, 显示该错误为Duplicate Field Names wit ...
- Python爬虫:Xpath语法笔记
一.选取节点 常用的路劲表达式: 表达式 描述 实例 nodename 选取nodename节点的所有子节点 xpath(‘//div’) 选取了div节点的所有子节点 / 从根节点选取 xpat ...
- ajax请求的封装
前端的工作,免不了要用到交互,请求后端的数据,可能大多人一直选择用jq封装好的方法直接使用,要知道封装这个事我们自己也可以的,今天给大家介绍一种封装方法,而且连跨域问题都不在话下,有了这个函数,是不是 ...
- 带你玩转JavaWeb开发之六-mysql基本语法详解及实例(1)
1.1.1 对数据库的表进行操作 1.1.1.1 对数据库中表进行创建 [语法:] create table 表名( 列名 列类型 [列约束], 列名 列类型 [列约束], 列名 列类型 [ ...
- ASP.Net一键自动化更新代码、编译、合并dll、压缩js、css、混淆dll、zip打包、发布到测试环境的bat批处理
不废话,直接代码: D: cd D:\src\testproj\PrecompiledWeb svn revert ../ -R svn update .. rmdir BS /S /Q C:\Win ...