git撤销修改各种情况

标签: git撤销push撤销commit
1865人阅读 评论(1) 收藏 举报
分类:

如何在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里就不会再看见这个文件,也不会再偶然提交该文件的修改了。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:459071次
    • 积分:5542
    • 等级:
    • 排名:第4760名
    • 原创:100篇
    • 转载:2篇
    • 译文:0篇
    • 评论:341条
    微信公众号
      友情链接
      联系我:
    • 关注我的新浪微博,私信咨询。

    • 分享Android相关技术,旅行日志,fanfan程序媛。
    博客专栏
    博客流量统计
    最新评论
    关注微信公众号