Git:如何还原一个已经同步到远程仓库的Commit?
来源:互联网 发布:小q书桌类似软件 编辑:程序博客网 时间:2024/06/06 04:34
本文译自git howto: revert a commit already pushed to a remote repository - Christoph Rüegg
你刚刚将你本地的分支推送到了远程仓库中,但是却突然发现到其中的一个Commit错了,或者有一些很严重的拼写错误。当然,这没什么大不了的,你能解决。但是你必须手脚快一点,在别人同步这些Commit前解决它,否则被坑了的同事会画小圈圈诅咒你的:)
首先,有两个备选方案可以让你的历史记录完好无损:
备选方案一:在一个新的Commit中改正错误
最简单的方法就是将错误的文件修复好后作为一个新的Commit提交,并同步到远程仓库中。这是一种很直观、也很安全的修复方式,在99%的情况下你都应该使用这种方法,除非这个错的Commit中包含敏感信息。
备选方案二:完全恢复(Revert)这个Commit
有时候你会希望撤销一个Commit的全部更改,幸运的是你可以告诉Git去恢复这个Commit而不用手动地去做这件事。恢复的时候甚至可以不必是最后一个Commit。恢复一个Commit意味着你会撤销这个错误的Commit中的所有更改。就像刚刚的例子中,这个错误的Commit的记录仍然存在,只不过它不再影响当前工作的分支和任何后续的Commit了。
$ git revert dd61ab32
关于历史重写
一般来说我们会避免重写提交的Commit历史,一个很重要的原因就是它会使其他Clone过或Fork过你代码的人和你岔出不同的分支,导致他们不再能pull你重写了的历史记录和后续Commit。如果他们在本地做了一些更改想同步到远程仓库上,需要一些高级的Git知识来理解怎样让Git正常进行工作。
然而有时候你确实就像重写历史记录,无论是因为泄露了敏感信息还是想清除一些本不应该在代码中的非常庞大的文件,亦或者你仅仅就是想要一个干净的历史记录(当然我确实这么做过)。
我平常迁移Subversion或Mercurial项目到Git中时也做过大量的重写历史记录的工作,无论是为了统一LF行结束符,修改提交者的名字、邮箱地址,还是为了从版本库中彻底删除那些大文件。最近我也因为一个大的版本库中一个很早的Commit引起了越来越来多错误而重写了版本库历史。
是的,如果可能的话你应该重写那些已经扩散到了其他fork代码中的历史记录,即使你这样做了也不会世界末日。比如,你仍然可以用Cherry-pick在历史记录中来移动Commit来处理那些在旧历史记录中的Pull请求。
请记住,在开源项目中重写历史记录前先联系版本库的管理者。有的管理者一般情况下不允许任何重写历史,并且会拉黑那些这么做的人,而另外一些管理者倾向于他们自己来做重写。
情形1:删除最后一次Commit
删除最后一次Commit是最简单的一种情况。例如,我们现在有一个拥有master
分支的远程仓库mathnet
,它现在处于最新的Commitdd61ab32
下。我们希望移除这个最新的Commit,或者用Git语言说,我们想force
远程仓库mathnet
的master
分支到dd61ab32
的父Commit上。
$ git push mathnet +dd61ab32^:master
在Git命令中,x^
代表x
的父节点,+
代表一个强制的非快速推送(forced non-fastforward push)。如果你在本地已经处于master分支下了,你也可以通过两个简单的步骤来实现同样的效果:先回退到父Commit,然后强制推送给远程仓库。
$ git reset HEAD^ --hard$ git push mathnet -f
情形2:删除倒数第二个Commit
现在我们假设需要删除的Commit没有在历史记录的顶部,而是一个稍旧一点的Commit,比如倒数第二个。我们希望删除它同时保留其后的所有Commit,换句话说我们希望重写历史记录然后将重写强制应用到mathnet
的master
分支上。重写历史的最简单的方法是对错误的Commit做一个互相的变基:
$ git rebase -i dd61ab32^
这个命令会打开一个vi编辑窗口,显示了从我们想删除的Commit以来的所有Commit。
pick dd61ab32pick dsadhj278
简单地删除我们想删除的Commit信息,在这里我们删除第一行即可(在vi中删除当前行的命令为dd
)。保存退出编辑器(在vi中输入:wq然后按回车键),然后解决一下有可能的冲突,然后强制推送到远程仓库就大功告成了:
$ git push mathnet -f
情形3:修复一个Commit中的拼写错误
这种情形下的操作与情形2
十分相似,但不是删除Commit信息,而是将pick
和edit
换一下位置然后保存退出即可。然后变基时,操作将会停在那个Commit上,这时你可以对这个索引做任何你想做的操作。完成后Commit改动然后继续变基(如果你想的话Git会告诉你如何保持Commit的附加信息),然后继续按情形2
进行推送。用同样的方法可以将一个Commit分成很多小的Commit,或者将很多Commit合并到一起。
本文首发http://www.dss886.com,转载请注明
- Git:如何还原一个已经同步到远程仓库的Commit?
- git撤销已经push到远程的commit
- git 撤回已经push到远程仓库的修改
- 本地Git仓库同步到Bitbucket 远程Git仓库
- git的使用方法:回退本次commit,提交代码到另一个远程仓库,修改远程仓库地址
- git如何同步到某次commit
- 常用git命令(包含从一个远程仓库拉取更新同步到另外一个远程仓库)
- 本地git仓库同步到github远程仓库
- git 还原到某次commit
- Xcode9如何push到远程git仓库
- 如何使用git命令同步代码到github或提交到多个远程仓库
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- ZOJ 2987
- 同步、异步、阻塞和非阻塞是几种基本的sockets
- 抓取网页所有url的简单Python爬虫源码
- mysql分页原理和sqlserver里面序列的用法
- 城市理论发展理论
- Git:如何还原一个已经同步到远程仓库的Commit?
- 浅谈单线程模型中Message、Handler、Message Queue、Looper之前的关系
- 查看main函数的返回值
- 三元运算符的使用方法
- Mac OSX:Powerline风格的zsh配置
- 最近的
- 开心果
- 又一大坑
- 详解java类的生命周期(笔者按自己知识量有少量添加)