head/reset/revert/rebase代码回滚全解:git提交记录的背后原理
多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,操作有:
回退(reset):reset是彻底回退到指定的commit版本,该commit后的所有commit都将被清除;reset执行后不会产生记录
反转(revert):revert仅是撤销指定commit的修改,并不影响后续的commit。revert执行后会产生记录。
reset,revert都有撤销、回退的意思,但却各有千秋,区别还是很大的,所以该使用哪种命令一定要结合实际情况来决定。要搞清这些,还是得多学习下git基础知识。
Git 的四个工作区域
工作区:也称工作目录、工作副本,简单来说就是 clone 后我们看到的包含项目文件的目录。我们日常开发操作也是在工作区中进行的。
本地仓库(.git):在工作区中有个隐藏目录.git,这就是 Git 本地仓库的数据库。工作区中的项目文件实际上就是从这里签出(checkout)而得到的,修改后的内容最终提交后记录到本地仓库中。
Tips:不要手动修改 .git 目录的内容暂存区:也称缓存区,逻辑上处于工作区和本地仓库之间,主要作用是标记修改内容,暂存区里的内容默认将在下一次提交时记录到本地仓库中。
远端仓库:团队协作往往需要指定远端仓库(一般是一个,也可以有多个),团队成员通过跟远端仓库交互来实现团队协作。
一个基本的 Git 工作流程如下:
在工作区中修改文件
暂存文件,将文件存放在暂存区
将改动从暂存区提交到本地仓库
从本地仓库推送到远端仓库
git的版本管理,及HEAD的理解
使用git的每次提交,Git都会自动把它们串成一条时间线,这条时间线就是一个分支。
如果没有新建分支,那么只有一条时间线,即只有一个分支,在Git里,这个分支叫主分支,即master分支。
有一个HEAD指针指向当前分支(只有一个分支的情况下会指向master,而master是指向最新提交)。
每个版本都会有自己的版本信息,如特有的版本号、版本名等。如下图,假设只有一个分支:
还需了解的术语
HEAD:这是当前分支版本顶端的别名,也就是在当前分支你最近的一个提交
Index:index也被称为staging area,是指一整套即将被下一个提交的文件集合。他也是将成为HEAD的父亲的那个commit
Working Copy:working copy代表你正在工作的那个文件集
Flow:git项目管理的流程和规划。比如分支规划:Master/Devlop 分支、Feature 分支、Release 分支、Hotfix 分支
理解 Git 处理分支的方式
commit 操作会为每目录每一个文件计算hash校验,然后在 Git 仓库中将这些校验和保存为树对象。
随后,Git 会创建一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针。还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。如此一来,Git 就可以在需要的时候重现此次保存的快照。
然后会把当前版本的文件快照保存到 Git 仓库中(Git 使用 blob 对象来保存它们),最终将校验和加入到暂存区域等待提交。
首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象,
Git 仓库中有五个对象:
三个 blob 对象(保存着文件快照)、一个树对象(记录着目录结构和 blob 对象索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息)。
Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照。
HEAD是指当前的快照
这个命令主要配合reset的--hard,--mixed和--solf三个参数对对本次的修改进行处理
HEAD~1指回退一个快照,可以简写为HEAD~
HEAD~2指回退两个快照,
HEAD^主要是控制merge之后回退的方向
HEAD~才是回退的步数
通过命令行删除远程和本地提交记录
常见的代码回滚场景
回滚场景:仅在工作区修改时
当文件在工作区修改,还没有提交到暂存区和本地仓库时,可以用 git checkout -- 文件名 来回滚这部分修改。
执行以下命令回滚工作区的修改:
git checkout -- build.sh
不过需要特别留意的是这些改动没有提交到 Git 仓库,Git 无法追踪其历史,一旦回滚就直接丢弃了。
示例: 用 git status 查看,还没提交到暂存区的修改出现在 “Changes not staged for commit:” 部分。
回滚场景:已添加到暂存区时
即执行过 git add 添加到暂存区,但还没 commit,这时可以用 git reset HEAD 文件名 回滚。
执行以下命令回滚暂存区的修改:
git reset HEAD build.sh
回滚后工作区会保留该文件的改动,可重新编辑再提交,或者 git checkout -- 文件名 彻底丢弃修改。
回滚场景:已 commit,但还没有 push 时
即已经提交到本地代码库了,不过还没有 push 到远端。这时候可用 git reset 命令,命令格式为:
git reset <要回滚到的 commit> 或者 git reset --hard <要回滚到的 commit>
需注意的是,提供的是 要回滚到的 commit,该 commit 之后的提交记录会被丢弃。
回滚场景:已 push 到远端时
注意!此时不能用 "git reset",需要用 "git revert"!
重要事情说三遍!之所以这样强调,是因为 "git reset" 会抹掉历史,用在已经 push 的记录上会带来各种问题;而 "git revert" 用于回滚某次提交的内容,并生成新的提交,不会抹掉历史。
命令 | 是否抹掉历史 | 适用场景 |
---|---|---|
git reset | 是,回滚的历史将消失 | 本地未push的记录 |
git revert | 否,历史记录保留,回滚后重新生成提交记录 | 回滚已push的内容 |
git reset回滚某次提交
确保还没其他人提交之前,进行强制回滚——重置HEAD(当前分支的版本顶端)到另外一个commit
git reset --hard HEAD~2
git reset 代码撤回
--hard 和 --soft 及默认mixed
--hard就是删除提交记录并不保存所删除记录所做的更改——将重置HEAD返回到另外一个commit
重置index以便反映HEAD的变化,并且重置working copy也使得其完全匹配起来。这是一个比较危险的动作,具有破坏性,数据因此可能会丢失!
--soft 虽然删除了最近两个提交记录,但是还保存了提交所做的更改——告诉Git重置HEAD到另外一个commit,但也到此为止
index,working copy都不会做任何变化,所有的在original HEAD和你重置到的那个commit之间的所有变更集都放在stage(index)区域中。
--mixed是reset的默认参数。它将重置HEAD到另外一个commit,并且重置index以便和HEAD相匹配,但是也到此为止。
working copy不会被更改。所有该branch上从original HEAD(commit)到你重置到的那个commit之间的所有变更将作为local modifications保存在working area中,(被标示为local modification or untracked via git status),但是并未staged的状态,你可以重新检视然后再做修改和commit
数字代表回退几个版本
git push -f ////强制覆盖
记住git reset不会产生commits,它仅仅更新一个branch(branch本身就是一个指向一个commit的指针)指向另外一个commit(Head和branch Tip同时移动保持一致).其他的仅剩对于index和work tree(working directory)有什么影响。git checkout xxxCommit则只影响HEAD,如果xxxCommit和一个branch tip是一致的话,则HEAD和branch相匹配,如果xxxCommit并不和任何branch tip相一致,则git进入detached HEAD 状态
如果别已经提交了代码,怎么删除远程的历史提交记录
删除提交记录中间的提交
git reset --hard 2b93fa8bdc8a1ca8e0c7498bd56460e6d1c408d1 //跟版本号
git push origin HEAD --force
关闭分支的protected权限
但是,你根据上面命令,确无法操作成功,比如报如下提示:
! [remote rejected] master -> master (pre-receive hook declined)
这个分支权限被限制了
settings/repository/Protected Branches ->un protected
git revert放弃某次提交
git revert 之前的提交仍会保留在git log中,而此次撤销会做为一次新的提交。
revert和reset 操作上都差不多,不同的是:
git revert 是撤销某次操作,此次操作之前的commit都会被保留
git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区
git reset操作会将版本回退至指定的commit,指定commit后的操作都将被撤销
而git revert则撤销指定commit的修改,同时生成一个新的commit
git rebase 重建提交顺序
git rebase --onto
然后开始删除提交记录2,3[执行 rebase 时会可能遇到冲突,解决冲突不在本文描述范围
git rebase --onto master~3 master~1 master
删除某条commit记录
git rebase -i d65f0fba23f2113ece6fbb3d104a33a1a8a80406
会进入vim模式,pick改为drop即可,具体操作,查看:https://www.jianshu.com/p/520f8661659c
顺便推荐下:《git中merge还是rebase?git之圣战merge vs rebase》
参考文章:
Git 代码回滚与找回的艺术https://segmentfault.com/a/1190000039320926
git reset soft,hard,mixed之区别深解 https://www.cnblogs.com/kidsitcn/p/4513297.html
git 理解 HEAD^与HEAD~ https://blog.csdn.net/claroja/article/details/78858411
git reset revert rebase 区别 https://blog.csdn.net/lainegates/article/details/72897693
git reset 、rebase和 revert的区别 https://blog.csdn.net/rebeccachong/article/details/39379703
git reset与git revert的区别 https://segmentfault.com/a/1190000019153248
代码回滚:git reset、git checkout和git revert区别和联系 https://www.cnblogs.com/houpeiyong/p/5890748.html
git中reset和revert的区别是什么 https://www.php.cn/tool/git/485052.html
Git恢复之前版本的两种方法reset、revert(图文详解) https://blog.csdn.net/yxlshk/article/details/79944535
转载本站文章《head/reset/revert/rebase代码回滚全解:git提交记录的背后原理》,
请注明出处:https://www.zhoulujun.cn/html/tools/VCS/git/4828.html
head/reset/revert/rebase代码回滚全解:git提交记录的背后原理的更多相关文章
- 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仓库有三个主要组成——工作目录,缓存区和提交历史. 从图中我们可以看出,缓存区或者叫索引,其实是指一整套即将被下一个提交的文件集合.也 ...
- 6.Git代码回滚
1.代码修改并提交 我们已经成功地添加并提交了一个helloWorld.txt文件,现在,是时候继续工作了. 于是,我们继续修改helloWorld.txt文件,改成如下内容: $ vi helloW ...
- svn代码回滚命令
代码回滚提交: 比如要把73回滚到68 svn merge -r 73:68 http://my.repository.com/my/project/trunk 然后commit就行了 svn com ...
- 利用PyCharm操作Github:仓库新建、更新,代码回滚
Github是目前世界上最流行的代码存储和分享平台,而PyCharm是Python圈中最流行的IDE,它很好地支持了Git操作.本文将会介绍如何利用PyCharm来连接Github,同时演示Git ...
- gitlab基础命令之代码回滚
#:gitlab状态 root@ubuntu:~# gitlab-ctl status run: alertmanager: (pid 13305) 215965s; run: log: (pid 1 ...
- gitlab一次代码回滚引起的bug...
问题描述:线上问题有一个bug,挺严重的.在线下排查后发现是一个之前的同事添加的代码影响的,为了不影响之前的业务,代码回滚了. 但是 过了几天,测人人员测试之后说这个问题又复现了,然后再次看,发现还是 ...
- Git提交代码规范 而且规范的Git提交历史,还可以直接生成项目发版的CHANGELOG(semantic-release)
Git提交代码规范 - 木之子梦之蝶 - 博客园 https://www.cnblogs.com/liumengdie/p/7885210.html Commit message 的格式 Git 每次 ...
- 怎样快速找到某一行代码的git提交记录
利用notepad++提高问题分析效率,以及快速找到某一行代码的git提交记录 1. 全目录搜索/替换 Notepad++是一款强大的文本编辑工具,当知道大概的关键词但不知道在哪个日志时可以使用not ...
- 代码回滚:git reset、git checkout和git revert区别和联系
git reset.git checkout和git revert是你的Git工具箱中最有用的一些命令.它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件. 因为 ...
随机推荐
- 🎁平平无奇的 Docker 命令(日常流)
Docker search docker search 命令用于在 Docker Hub 上搜索镜像,语法如下: docker search [OPTIONS] TERM 常用的选项包括: --fil ...
- HTML5学习内容-3
(一)行高 line-height,一行文字的高度 例子 <!DOCTYPE html> <html lang="en"> <head> < ...
- jenkins实践篇(2)—— 自动打tag的可回滚发布模式
大家好,我是蓝胖子,在上一篇我简单介绍了如何基于特定分支做自动编译和发布,在生产环境中,为了更加安全和快速回滚,我采取的是通过对代码打tag的方式来进行部署,下面我将详细介绍整个发布过程的逻辑. 发布 ...
- Centos7安装msf
文章来自:https://blog.csdn.net/weixin_44268918/article/details/129771330 1. 前言在日常使用中,模拟攻击以及测试的时候都是直接使用本地 ...
- C++基础杂记(2)
将数组传入函数 禁止修改数组的值 函数的地址与函数的指针 函数的指针数组 函数的 static 与 inline 引用左值和引用传参 C++11 的数组 for 循环 64 位 Linux 操作系统中 ...
- Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战
一.前言 在现代软件开发中,事务处理是必不可少的一部分.当多个操作需要作为一个整体来执行时,事务可以确保数据的完整性和一致性,并避免出现异常和错误情况.在SpringBoot框架中,我们可以使用声明式 ...
- JAVA 类显式加载
类显式加载 1.Class.forName("classloader.Dog"); 方式加载 Example1 1 package classloader; 2 3 publ ...
- STM8 STM32 GPIO 细节配置问题
在MCU的GPIO配置中我们经常需要预置某一 IO 上电后为某一固定电平, 如果恰好我们需要上电后的某IO为高电平, 那么在配置GPIO的流程上面需要特别注意. 配置如下: (以下问题仅在STM8 / ...
- nmap命令说明
目录 主机发现 扫描技术 端口规格和扫描顺序 服务/版本检测 脚本扫描 操作系统检测 时间和性能: 防火墙/IDS的逃避和欺骗 输出 杂项 平时看到别人的nmap命令都是一大串,根本看不懂为什么,自己 ...
- Grok AI 是什么?
原文链接:https://openaigptguide.com/grok-ai/ Grok AI是由马斯克推出的一款高级别的人工智能大语言模型,旨在帮助软件开发者以不同的口头语言交流和表达.它是基于多 ...