Git 错误提交后该如何回滚操作
1. Git 架构
Workspace
:工作区(当前用户操作修改的区域)Index / Stage
:暂存区 (add 后的区域)Repository
:仓库区或本地仓库(commit 后的区域)Remote
:远程仓库(push 后的区域)
整体过程可以简述为:
- 工作区–>
add
–>暂存区–>commit
–>本地仓库区–>push
–>远程仓库区 - 远程仓库区–>
fetch
–>使用 refs\remotes 下对应分支文件记录远程分支末端 commit_id 和 本地仓库区 -->merge
–>工作区 - 远程仓库区–>
pull
–>使用 refs\remotes 下对应分支文件记录远程分支末端 commit_id and 本地仓库区 and 工作区
具体的 git 的组成部分和概念命令,请移步下述两个博客(超链接):
Git 技术干货!工作中 Git 的使用实践和常用命令合集!
Git - 使用 git 不知道内部实现机制怎么行
新建一个 Git 仓库,在 Git 仓库中可逻辑上划分三个区域——工作目录、暂存区、版本库,这三个区域是抽象的,Git 仓库中以文件来记录各个区域的内容。
Git 会追踪工作目录里文件及内容的变更。当我们在 Git 仓库的工作目录下新建三个文件,Git 会将新建的文件视作变更(图中五角星表示被 Git 检测到更改)。
我们想将 html 文件提交到仓库中,首先将变更(新建的 HTML )从工作目录添加到暂存区。然后将这个文件从暂存区提交到版本库。这时才算拍摄了一组快照,提交的更改不会丢失。
当我们在工作目录下修改了一个文件, Git 仓库会识别文件修改部分(标记 2 颗星),然后我们将文件修改添加到暂存区,最后将文件修改提交到版本库。
修改 CSS 文件,将修改添加到暂存区,再提交到仓库。
问题:如果我们在工作目录下第一次修改一个文件,并将它添加到暂存区,然后我们第二次修改文件,第二次修改没有添加到暂存区,最后我们将文件 commit 到版本库,请问仓库的文件内容是第几次修改的?请思考。
如果第一次修改 CSS 文件,添加到暂存区,再第二次修改 CSS 文件,现在执行 commit,提交到版本库只有第一次修改的内容。
当执行 commit 时,只有暂存区中的内容会被提交到版本库。
如果我们想要将第二次修改也 commit 到版本库,我们必须先将第二次修改先添加到暂存区,第一次修改的暂存与第二次修改的暂存合并,然后执行 commit,仓库中就会有第一次和第二次修改的内容。
添加到暂存区的内容会合并,一起提交到仓库。
第一次修改 CSS 文件,添加到暂存区,但没有提交仓库;第二次修改 CSS 文件,添加到暂存区,会与第一次的修改合并,这时提交到版本库的内容是两次修改的合并。
2. 实践
假设项目存在这么一个提交记录:
$ git log
commit commit_id4 (HEAD -> master)
Author: test
Date: Thu Aug 20 16:28:45 2020 +0800第三次修改 README 文件
commit commit_id3 (HEAD -> master)
Author: test
Date: Thu Aug 20 16:28:45 2020 +0800第二次修改 README 文件
commit commit_id2
Author: test
Date: Thu Aug 20 16:28:19 2020 +0800第一次修改 README 文件
commit commit_id1
Author: test
Date: Thu Aug 20 16:26:59 2020 +080初始化项目
提交顺序为:commit_id1
--> commit_id2
--> commit_id3
--> commit_id4
注意:在 git
中每次的 commit
都有一个 commit id
唯一标识当前的提交!
下面,我们先来解决小明的这个问题,使用git reset
即可完美解决~
3. 问题解决
洋仔:小明,你的这个就可以用git reset 这个命令来完美的搞定,下面我们看一下如何解决
1、获取当前提交的 commit id
命令:git log
获取到当前项目分支下的所有 commit 记录;
假设上述小明提交错误的 commit id 为commit id:commit_id4
这一次提交;
他的上一次提交就是commit id:commit_id3
,我们要将修改回滚到commit_id3
的时刻!
小明:我想要把我刚才 commit 的修改保留下来,我修改的代码不能给我删除掉呀!
洋仔:没问题
2、将某个 commit id 前的 commit 清除,并保留修改的代码
命令:git reset <commit_id>
当前场景下就是:git reset commit_id3
将指定 commit_id 后的所有提交,都去除,并保留修改的代码在本地的区域,也就是Workspace
中
小明:啊哈,这样的话我就可以把错误代码修改后再提交了; 但是我已经 push 到线上仓库的数据怎么办呢?
洋仔:别急,有办法~
3、修改代码完成后,将修改好的代码 add 到暂存区,并提交到本地仓库中
命令:git add <file_name>
and git commit
当前场景下:git add .
and git commit
将最新修改后的代码 commit 则提交后的提交记录假设如下:
可以看到,我们错误提交的commit_id4
提交记录消失,取而代之的是我们更新代码后提交的记录commit_id5
; 这样就完成了本地的代码修改和更新
$ git log
commit commit_id5 (HEAD -> master)
Author: test
Date: Thu Aug 20 16:28:45 2020 +0800第三次修改 README 文件-更新错误后提交
commit commit_id3 (HEAD -> master)
Author: test
Date: Thu Aug 20 16:28:45 2020 +0800第二次修改 README 文件
commit commit_id2
Author: test
Date: Thu Aug 20 16:28:19 2020 +0800第一次修改 README 文件
commit commit_id1
Author: test
Date: Thu Aug 20 16:26:59 2020 +080初始化项目
整体流程如下:
git log
git reset commit_id3
修改代码
git add .
git commit -m '第三次修改 README 文件-更新错误后提交'
洋仔:好了,小明,你的问题完美解决了
小明:哦吼,但是我还有一个问题: 如果我想要不保留回滚 commit 的修改,直接删除掉修改!该怎么处理呢?
洋仔:简单~ 我们整体看一下 git reset 命令
3.1 后悔药 git reset
在进行下面的讲解是,还是先假设有这么一个提交链:
commit_id1 --> commit_id2 --> commit_id3 --> commit_id4
git reset <param> commit_id2
reset
是将 HEAD
重新定位到commit_id2
上,对于 commit_id3
和 commit_id4
和本地当前的修改,对于不同的参数 param,会有不同的处理:
reset 命令有三种处理模式:
- –soft:保留 commit 修改,将修改存储到 index 中;也就是说 git add 后的区域
- –mixed:保留 commit 修改,将修改存储到本地工作区域中;也就是说 git add 前的区域
- –hard:删除 commit 修改,慎用!
git reset --soft
回滚 commit_id 前的所有提交,不删除修改:
git reset --soft commit_id
重设 head,不动 index,所以效果是 commit_id 之后的 commit 修改全部在 index 中 将 id3 和 id4 的修改放到 index 区(暂存区),也就是 add 后文件存放的区域,本地当前的修改保留git reset --soft SHA 会将对应的 commit 更改回退到暂存区:
git reset --mixed
回滚 commit_id 前的所有提交,不删除修改:git reset commit_id
等同于git reset --mixed commit_id
与下述的git reset --hard commit_id
效果不同。
重设 head 和 index,不重设 work tree,效果就是 commit_id 之前的修改,全部在 work tree 中,为还未 add 的状态 将 id3 和 id4 的所有修改放到本地工作区中,本地当前的修改保留。git reset --mixed SHA 会将对应的 commit 更改回退到工作目录:
git reset --hard
回滚 commit_id 前的所有提交,将修改全部删除:git reset --hard commit_id
重设 head、index、work tree,也就是说将当前项目的状态恢复到 commit_id 的状态,其余的全部删除(包含 commit_id 后的提交和本地还未提交的修改) 慎用!!git reset --hard SHA 会将对应的 commit 直接删除,无法恢复。
git reset --hard commit_id
该命令主要是用于代码回退,仅对已经 commit 到本地的代码有效。通过git reflog
命令查看之前版本 id 信息。wohu@ubuntu-dev:~/git_demo/test_demo$ git reflog eda37f0 HEAD@{0}: commit: third commit 8d2efe6 HEAD@{1}: commit: second commit 14b5e12 HEAD@{2}: commit (initial): first commit wohu@ubuntu-dev:~/git_demo/test_demo$ cat README.md - first commit - second commit - third commit wohu@ubuntu-dev:~/git_demo/test_demo$
想再次切回到注释为
second commit
版本下,可以再次通过git reset --hard 8d2efe6
进行版本切换。wohu@ubuntu-dev:~/git_demo/test_demo$ git reset --hard 8d2efe6 HEAD is now at 8d2efe6 second commit wohu@ubuntu-dev:~/git_demo/test_demo$ ls README.md wohu@ubuntu-dev:~/git_demo/test_demo$ cat README.md - first commit - second commitwohu@ubuntu-dev:~/git_demo/test_demo$
3.2 后悔药 git revert
小明:原来 git reset 这么强大呀! 但是我这还有个问题:
如果想要只操作修改中间的一个 commit,不对其他的 commit 产生影响; 也就是类似于我们只修改 commit_id2,而对 commit_id3 和 commit_id4 无影响,该怎么处理呢?
洋仔:(这么多问题,幸亏我懂,要不这次就丢大了。。) 简单! git revert 命令!
适用场景: 在项目开发中,突然发现在前几次的提交中,有一次提交中包含一个 bug; 当然我们可以进行一个新的修改,然后再提交一次; 但是,不优雅哈哈; 我们可以直接重做有 bug 的 commit~
为什么不直接去再添加一个 commit 呢?
git revert 是用于“反做”某一个版本,以达到撤销该版本的修改的目的。
比如,我们 commit 了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有 bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西;
在 revert 命令中常用的就两个:
git revert -e <commit_id>
:重做指定 commit 的提交信息git revert -n <commit_id>
:重做执行 commit 的代码修改
git revert -e
重做 commit_id 的提交信息,生成为一个新的 new_commit_id
git revert -e commit_id
git revert -n
重做 commit_id 的提交git revert -n commit_id
将 commit_id 中修改,放到 index 区,我们可以对他重新做修改并重新提交
git revert <commitHash> 回退指定提交记录git revert --no-commit <commitHash>
回退指定提交记录 --no-commit 不会自动提交成一条 `commit` 后续手动操作git revert --no-commit <commitHash1> <commitHash2>
回退多个提交记录git revert --no-commit <commitHash1>..<commitHashN>
回退一定范围的提交记录,前开后闭(不包含 1,包含 N)
3.3 revert vs reset
- git revert 是用一次新的 commit 来回滚之前的 commit,此次提交之前的 commit 都会被保留不动;
- git reset 是回到某次提交,提交及之前的 commit 都会被保留,但是此 commit id 之后的修改都会被删除或放回工作区等待下一次提交;
小明:还有这种操作,可以直接单独操作提交过程中的某一个 commit! 太棒了!
4. 后悔药git checkout
小明:还有最后一个问题:
如果我在一次开发中,发现某个文件修改错误了,想要将文件恢复到刚 pull 代码时的状态怎么办呢?
洋仔:简单! 看 git checkout 解决这个问题!
我们知道使用git checkout
可以
git checkout <branch_name>
切换分支git checkout -b <branch_bame>
创建分支等操作
它还有回滚指定文件的修改的功能,命令:git checkout -- <file_name>
上述语句的作用,就是将 file_name 的本地工作区的修改全部撤销,有两种情况:
如果 file_name 在 commit 后没有 add 过这个文件,则撤销到版本库中的状态
如果 file_name 在 commit 后 add 过这个文件,则撤销到暂存区的状态,也就是 add 后的状态
总之,就是让指定的文件回滚到最近的一次git add
或者 git commit
时的状态!
git checkout --file
该命令是对未提交到缓存区的代码进行撤销。创建空文件 Readme.md。通过 git status
查看文件在工作区的状态。
wohu@ubuntu-dev:~/git_demo/test_demo$ echo "hello world" >> Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ git status
On branch master
Your branch is up-to-date with 'origin/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.mdno changes added to commit (use "git add" and/or "git commit -a")
wohu@ubuntu-dev:~/git_demo/test_demo$
然后执行 git checkout -- Readme.md
。我们又回复到了修改前的版本。
wohu@ubuntu-dev:~/git_demo/test_demo$ cat Readme.md
hello world
wohu@ubuntu-dev:~/git_demo/test_demo$ git checkout -- Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ cat Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$
我们再次对 Readme 内容进行编辑,并将其放入到缓存区中。
wohu@ubuntu-dev:~/git_demo/test_demo$ echo "hello world" >> Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ git add Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: Readme.mdwohu@ubuntu-dev:~/git_demo/test_demo$ git checkout -- Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: Readme.mdwohu@ubuntu-dev:~/git_demo/test_demo$
此时执行 git checkout
没有啥效果,如果想恢复就要用到我们接下来介绍的命令。
git reset HEAD -- file
该命令是将放入暂存区的代码进行撤销,放入到工作区中。
wohu@ubuntu-dev:~/git_demo/test_demo$ git reset HEAD -- Readme.md
Unstaged changes after reset:
M Readme.md
wohu@ubuntu-dev:~/git_demo/test_demo$ git status
On branch master
Your branch is up-to-date with 'origin/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.mdno changes added to commit (use "git add" and/or "git commit -a")
wohu@ubuntu-dev:~/git_demo/test_demo$
这样我们的 Readme.md 代码又再次回到了工作区。再次进行 git checkout
将代码内容进行恢复。
参考:
https://gitbook.cn/books/5f4db870237b0e7d7f238fa0/index.html
https://gitbook.cn/books/5ebca21b9b907c12334b6287/index.html
Git 错误提交后该如何回滚操作相关推荐
- git错误提交怎么整?强行回滚最为致命
首先将本地分支重置到你错误提交前的分支 git reset --hard 要重置到的commitId 其次强制提交本地的代码到远程 git push origin master --force 如果发 ...
- Git:撤销回滚操作
Git撤销&回滚操作(git reset 和 get revert) git的工作流 工作区:即自己当前分支所修改的代码,git add xx 之前的!不包括 git add xx 和 git ...
- 在idea中纯界面进行git回滚操作
在idea中git回滚操作 红色:工作区 绿色:缓存区 白色:已提交(本地版本库或者远程版本库) 通常我们都是在缓存区中写代码 第一步:reset到回滚的版本 找到需要回滚的版本,将代码重置到需要回滚 ...
- git 常规操作以及回滚操作
2019独角兽企业重金招聘Python工程师标准>>> 在这里记录一些平时比较常用的git的命令行操作,以及一些回滚的操作,以提高我们平时的开发效率. 首先我的 git 项目仓库在 ...
- [20131014] 出现错误,显示事务没有回滚
[20131014] 出现错误,显示事务没有回滚 测试代码: SET XACT_ABORT OFF goBEGIN TRANBEGIN TRYDELETE dbo.T SELECT * FROM [不 ...
- 1.2 git回滚操作
1.远程仓库中有的文件,但是本地要给删除掉,如何同步 git ls-files //查看暂存区是否有该文件,以readme.md为例 git rm -r --cached readme.md //删除 ...
- Team Foundation Server的回滚操作
VSTF Rollback 操作 最近遇到要把有些项目需要做回滚操作,发现TFS的UI上没有回滚的操作. 经过百度,查到一个CSDN上的博主发了一种方法,经过验证,那种方法是错误的: 他通过先获取指定 ...
- sqlsever回滚操作_SqlServer 事务回滚(1)
SQL事务 一.事务概念 事务是一种机制.是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行.因此事务是一个不可分割的工作逻辑单元.在数据库系统上执行并发操作时事务是作为 ...
- javaweb中mysql数据库的回滚操作代码
2019独角兽企业重金招聘Python工程师标准>>> 在mysql中创建用户账户数据库(注意,count不能为负数,要设置无符号型) 添加数据 下面我们得到connection对象 ...
最新文章
- 老司机做VR视频,需要什么样的全景相机?
- 黑客们的故事(连载三) 因为好奇
- 常见的网站布局方式---左固定右自适应、左右固定中自适应等
- 容器和 批量删除 镜像_更高更快更稳,看阿里巴巴如何修炼容器服务「内外功」...
- ros开发增加clion常用模板及初始化配置(三)
- 使用kubeadm搭建的k8s集群修改node节点主机名
- 学习Python的第七天
- oracle联合分组查询,Oracle分组查询
- 你要知道的N个Android适配问题
- Ubuntu18.04安装分析
- MacOS图标文件 .icns 一键生成脚本
- 麦克风产品 麦克风元器件 市场调研
- FPGA资源类型简介
- 大学计算机python期末考试_大学计算机程序设计(Python)_章节测验,期末考试,慕课答案查询公众号...
- 树莓派(raspberry pi)日记1之个人网站的构建(localhost内网穿透实现公网可以访问)
- nkd 编译ffmpeg错误: clang is unable to create an executable file. C compiler test failed.
- CDN和CDN加速有什么关联
- html布局方式有哪些,HTML几种布局方式-HTML教程第十六讲
- 苹果手机几月份最便宜_1亿像素最便宜手机, 不是小米10, 网友: 这款手机拍照不错...
- 利用OSG实现模拟飞机尾迹-粒子系统