git撤销修改各种情况
如何在Git里撤销(几乎)任何操作
一、撤销一个已经公开的改变
场景:已经执行了gitpush,将修改发送到了github,需要撤销某一个commit。
方法:git revert<commit版本号>,则改commit的所有改变都会被反转。这是git最安全、最基本的撤销场景。
二、修正最后一个commit消息
场景:在最后一条commit消息里有一个笔误,已经执行git commit –m’xxx’,但在push之前发现说明信息有误
方法:git commit–-amend 或者git commit –amend –m’正确的信息’
原理:git commit–amend会用一个新的commit更新并替换最近的commit,这个心的commit会把任何修改内容和上一个commit的内容结合起来。如果当前没有提出任何修改,这个操作会把上次的commit消息重写一遍。
三、撤销本地修改
场景:git add后恢复,撤销git add。
方法:git checkout– filename
此种撤销会使任何修改完全消失,所以使用前最好用git diff确认下。
四、重置本地的修改
场景:在本地提交了一些东西(还没有push),希望撤销前面的三次提交。
方法:git reset <lastgood SHA>或git reset –hard <last good SHA>
原理:git reset会把代码库历史返回到指定的SHA状态。这样就像这些提交从来没有发生过。缺省情况下,git reset会保留工作目录。这样提交是没有了,但是修改内容还在磁盘上。这是一种安全选择,但通常希望一步就撤销提交及修改内容,这就是—hard选项的功能了。
五、在撤销了本地修改之后再恢复
场景:提交了几个commit后,用git reset –-hard撤销了这些修改,希望还原这些修改。
方法:git reflog和git reset或git checkout
原理:git reflog对于恢复项目历史是一个超棒的资源。可以恢复几乎任何东西——任何你commit过得东西。
一些注意事项:
l 它涉及的只是HEAD的改变。在切换分支、用git commit进行提交、以及用git reset撤销commit时,HEAD都会改变,但是当用git checkout -- <bad filrname>时,HEAD并不会改变,因此reflog也无法恢复。
l git reflog不会永远保持。Git会定期清理那些用不到的对象,不要指望几个月前的提交还在那里。
l 不能用reflog来恢复另一个开发者没有push过得commit。
l 如果下网准确恢复项目的历史到某个时间点,用gitreset—hard<SHA>
l 如果希望重建工作目录里的一个或多个文件,让它们恢复到某个时间点的状态,用git checkout <SHA> -- <filename>
l 如果希望把这些commit里的某一个重新提交到代码库,用git cherry-pick <SHA>
六、利用分支的另一种做法
场景:进行了一些提交,然后意识到开始check out的是master分支。希望提交到另一个分支(feature)。
方法:git branchfeature,git reset –-hard origin/master,and git checkoutfeature
原理:gitcheckout –b <name>创建新的分支,这是创建新分支并马上check out的流行捷径,但是如果不希望马上切换分支。这里。git branch feature创建一个叫做feature的新分支并指向最近的commit,但还是checkout在master分支上。下一步,在提及任何新的commit之前,用git reset –-hard把master分支倒回到origin/master。不过那些commit还在feature中。最后,用git checkout切换到新的feature分支,并且让你最近所有的工作都完好无损。
七、在master繁殖的基础上创建了feature分支,但master分支已经滞后origin/master很多。现在master分支已经和origin/master同步,你希望在feature上的提交从现在开始,而不是从滞后很多的地方开始。
方法:git checkoutfeature和git rebase master
原理:要达到这个效果,你本来可以通过git reset (不加,--hard,这样可以在磁盘上保留修改)和git checkout –b <new branch name>然后再重新提交修改,不过这样做的话就会失去提交历史。
git rebase master会做如下事情:
Ø 首先他会找到你当前check out的分支和master分支的共同祖先。
Ø 然后它reset当前check out的分支到那个共同祖先,在一个临时保存区存放所有之前的提交。
Ø 然后它把当前check out的分支提交到master的末尾部分,并从临时保存区重新把存放的commit提交到master分支的最后一个commit之后。
八、大量的撤销/恢复
场景:进行了很多次提交,但是发现只需要其中一部分,其他提交需要舍弃。
方法:git rebase–i <earlier SHA>
原理:-i 参数让rebase进入“交互模式”。它开始类似于前面讨论的rebase,但在重新进行提交之前,它会暂停下来并允许详细修改每个提交。
rebase –I 会打开你的缺省文本编译器,里面列出候选的提交。前面两列是键:第一个是选定命令,对应第二列里的SHA确定的commit。缺省情况下,rebase–i假定每个commit都要通过pick命令。
要丢弃一个commit,只要在编辑器里删除那一行就可以了。如果你需要commit的内容,而是对commit消息进行编辑,可以使用reword命令。把第一列里的pick替换为reword(或者直接用r)。有人会觉得这里直接重写commit消息就行了,但是这样不管用rebase –i会忽略SHA列前面的任何东西,它后面的文本只是来帮助我们记住这个commit是来干嘛的。当你完成rebase –i的操作之后,你会被提示输入需要编写的任何commit消息。
如果比需要把两个commit合并到一起,可以使用squash或者fixup命令。Squash和fixup会向上合并,带有这两个命令的commit会被合并它的前一个commit里。如果选择squash,git会提示给新合并的commit一个新的commit消息;fixup则会把合并清单里第一个commit的消息直接给新合并的commit。当你保存并退出编辑器时,git会按从顶部到底部的顺序运用你的commit。可以通过在保存前修改commit顺序来改变运用的顺序。
九、停止追踪一个文件
场景:偶然把application.log加到代码库里了,现在每次运行应用,git都会报告在application.log里有未提交的修改。你把*.login放到了.gitignore文件里,可文件还是在代码库里,怎么才能告诉git撤销对这个文件的追踪呢?
方法:git rm –cachedapplication.log
原理:虽然.gitignore会阻止git追踪文件的修改,甚至不关心文件是否存在,但这只是针对于那些以前从来没有追踪过得文件。一旦有个文件被加入提交,git就会持续关注该文件的改变。如果你希望从git的追踪对象中删除那个本应忽略的文件,git rm –-cached会从追踪对象中删除它,但让文件在磁盘上保持原封不动。因为现在它已经被忽略了,你再git status里就不会再看见这个文件,也不会再偶然提交该文件的修改了。
- python 中__setattr__, __getattr__,__getattribute__, __call__使用方法
- 量子技术与人工智能:同时进化的双生子
- TCP协议三次握手与四次挥手通俗解析
- Silverlight/aspx/ajax/mvc的UI自动化测试
- Office Open XML学习(1)-创建excel文档,并向单元格中插入字符串
- PyMC3和Theano代码构建贝叶斯深度网络,61页PPT探索贝叶斯深度学习以及实现
- 男程序员是不是都不会和女生表达交流?程序员的回答歪了
- Silverlight Telerik控件学习:主题Theme切换
- Silverlight自定义类库实现应用程序缓存
- Silverlight Telerik控件学习:TreeView数据绑定并初始化选中状态、PanelBar的Accordion效果、TabPanel、Frame基本使用
- 这或许是对小白最友好的python入门了吧——4,列表
- 每个人都应该知道的十个机器学习常识
- 重新带你了解React.js
- WebService又一个不爽的地方
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SQL 中判断条件的先后顺序,会引起索引失效么?
- Maven工程java -jar时提示xxx-SNAPSHOT.jar中没有主清单属性
- Kotlin 1.4 版本正式发布:新功能一覽
- 聊聊java中的哪些Map:(二)HashMap中的TreeNode
- 用innodb_ruby分析InnoDB的页管理
- react获取运行环境是开发还是生产环境。
- 函数节流与函数防抖
- antd3.x中的form
- 使用RAP2模拟假数据实现前后端分离
- Redis 事件驱动分析
- JDK1.8 新特性 (八):还在重复写空指针检查代码?
- 使用Angular HTTP client对数据模型进行update操作
- Nodejs中OS模块
- 使用Angular HTTP client对数据模型进行创建操作
- 使用Angular HTTP client对数据模型进行删除操作