写点什么

🏆「推荐收藏」【Git 实战专题】代码提交错误怎么办?教你如何回退版本!

发布于: 2021 年 07 月 31 日
🏆「推荐收藏」【Git实战专题】代码提交错误怎么办?教你如何回退版本!

预备知识

  • 一个 commit 对应这一个版本,有一个 commit id,40位的16进制数字,通过 SHA1 计算得到,不同的文件计算出来的 SHA1 值不同(有很小的几率相同,可忽略),这样每一个提交都有其独特的 id。每提交一个新版本,实际上 Git 服务就会把它们自动串成一条时间线。

  • 在 Git 中,HEAD表示当前版本,例如:HEAD 版本属于:e620a6ff0940a8dff…,那么HEAD^表示上一个版本,HEAD^^表示上上一个版本,往上 100 个版本可以写成 HEAD 加连续 100 个^,也可以写成:HEAD~100



  • git log:该命令显示从最近到最远的提交日志。


commit e620a6ff0940a8dff91e0d252f30e4d138ec37beAuthor: TangShengqin <15527733782@163.com>Date: Wed Jan 3 10:35:44 2018 +0800
commit 33342d9870f104719d351539a15e74a1382407eaAuthor: TangShengqin <15527733782@163.com>Date: Wed Jan 3 10:34:03 2018 +0800
复制代码

git 结构和各操作之间的关系


  • git log --pretty=oneline 查看已提交的版本



回退版本(三种方式)

git reset commit_id(撤销 commit 和 add 操作)

git reset 默认是--mixed 模式


git reset --mixed commit_id撤销commit和add操作
复制代码


  • 回退一个版本,且会将暂存区的内容和本地已提交(commit)的内容全部恢复到未暂存的状态,不影响原来本地文件(未提交的也不受影响)

  • 会保留源码,只是将 git commit 和 index 信息回退到了某个版本

git reset --soft commit_id(撤销 commit 操作)

  • *回退一个版本,不清空暂存区,将已提交的内容恢复到暂存区,不影响原来本地的文件(未提交的也不受影响)

  • 保留源码,只回退 commit 信息到某个版本,不涉及 index 的回退,如果还需要提交,直接 commit 即可

git reset --hard commit_id(慎用)

git reset –hard commit_id 或则是 git reset –hard HEAD^


  • 撤销 commit 和 add 操作,并将本地版本置回上一版本

  • 回退一个版本,清空暂存区,将已提交的内容的版本恢复到本地,本地的文件也将被恢复的版本替换

  • 源码也会回退到某个版本,commit 和 index 都会回退到某个版本.(注意这种方式是改变本地代码仓库源码)


hard 选项,表示彻底将工作区、暂存区和版本库记录恢复到指定的版本库

reset 和 revert 的用法:

  1. reset: push 前。

  2. revert: push 后。


git revert <commit_id..> 
复制代码


回滚到置顶的版本,执行后需要 git push

reset 与 revert 区别:

写到了 git reset 指令,就不得不说下它与 git revert 的区别:


  • git reset 是把 HEAD 向后移动了一下,而 git revert 是 HEAD 继续前进,只是新的 commit 的内容和要 revert 的内容正好相反,能够抵消要被 revert 的内容。



  • git revert 是用一次新的 commit 来回滚之前的 commit,git reset 是直接删除指定的 commit。

  • 在回滚这一操作上看,效果差不多。但是在日后继续 merge 以前的老版本时有区别。因为 git revert 是用一次逆向的 commit“中和”之前的提交,因此日后合并老的 branch 时,导致这部分改变不会再次出现,但是 git reset 是直接把某些 commit 在某个 branch 上删除,因而和老的 branch 再次 merge 时,这些被回滚的 commit 应该还会被引入。




实际案例

缓存区代码覆盖工作区代码

  • 场景:缓存区存有上次改动代码,即之前有执行:git add

  • 当前工作区间代码想废弃, 可将缓存区中代码覆盖之:


对应指令:

  • 缓存区某一文件代码 覆盖本地工作区: git checkout -- testReset.txt

  • 将匹配的文件覆盖:git checkout -- *.txt

  • 将所有文件覆盖:git checkout -- .

本地仓库代码覆盖缓存区代码

  • 场景:发现之前 add 的文件不需要了,又不想工作区间重新改回去。


对应指令:

  • 将本地仓库某一文件覆盖缓存区: git reset HEAD testReset.txt

  • 将匹配的文件覆盖缓存区:git reset HEAD *.txt

  • 将所有文件覆盖缓存区:git reset HEAD .


注意:改变的是缓存区代码,工作区间代码不变(编辑器代码不会改变)

本地仓库代码覆盖工作区代码(常用)

上述两场景在实际开发中没那么常用,接下来 本地仓库 代码 覆盖 工作区间 代码 则经常会用到。


场景:当前工作区间代码混乱(一般更新或合并分支后),废弃当前改动;


对应指令:

  • 将本地仓库某一文件代码 覆盖本地工作区: git checkout HEAD testReset.txt

  • 将本地仓库所有文件代码 覆盖本地工作区:(谨慎操作):git checkout HEAD .


我们知道本地仓库中有一个commit列表, 记录了所有commit的记录, 查看commit列表指令:


  • 查看 commit id, 查看提交记录(git commit 的记录)


git log git log --pretty=oneline 
复制代码


  • 查看以往提交历史(包括 撤销回退 记录)


git reflog 
复制代码



根据 commit 列表,工作区间代码能实现更灵活的回退:


  • 本地工作区间代码 回退到上一次版本、上上次、前 10 个版本


git reset --hard HEAD^ git reset --hard HEAD^^ git reset --hard HEAD~10 
复制代码


  • 本地工作区间代码 回退到指定版本(“d362816”为 commit id)


git reset --hard d362816 
复制代码

远程仓库代码覆盖本地仓库代码(清除 未 push 的 commit)

场景: 有时候合并分支、切换分支、更新代码会导致提交絮乱的问题(没使用--rebase 方式),具体体现在自动生成了 commit 且工作区间 代码很多冲突。使工作区间代码跟线上代码一致且删除新生成的 commit。


对应指令:

  • 本地工作区间代码回退到远程版本


git reset –-hard origin/master 
复制代码

远程仓库代码回滚(线上代码回滚)

场景: 提交了一个 commit(该提交包含很多文件), 发现有问题, 需要回滚, 将线上分支(master)回滚到上一次 commit;


合理一些的是使用 git reset 或 git revert 方式进行回滚;

git reset 方式图解:

git revert 方式图解:


我们可以使用git revert将新的 commit 替换掉;(不用git reset而用git revert的原因是保留 commit 方便后续代码恢复)

对应指令:
// 替换掉上次提交的代码文件(上次的commit记录会保留)git revert HEADgit commit -m "回滚上次commit"git push origin master
复制代码


  • git revert HEAD:撤销最近的一次提交,如果你最近一次提交是用 revert 命令产生的,那么你再执行一次,就相当于撤销了上次的撤销操作,换句话说,你连续执行两次 revert HEAD 命令,就跟没执行是一样的



总结案例

git log --pretty=oneline
复制代码


如果你在本地做了错误提交,那么回退版本的方法很简单

先用下面命令找到要回退的版本的 commit id:

git reflog
复制代码

接着回退版本:

git reset --hard a7e1d279a7e1d279
复制代码


就是你要回退的版本的 commit id 的前面几位。


远程分支版本回退的方法


如果你的错误提交已经推送到自己的远程分支了,那么就需要回滚远程分支了。

首先要回退本地分支:

git reflog git reset --hard Obfafd
复制代码

紧接着强制推送到远程分支:

git push -f origin master 
复制代码


  • origin 就是一个名字,它是在你 clone 一个托管在 Github 上代码库时,git 为你默认创建的指向这个远程代码库的标签,origin 指向的是 repository,master 只是这个 repository 中默认创建的第一个 branch。

  • 当你 git push 的时候因为 origin 和 master 都是默认创建的,所以可以这样省略。


注意:本地分支回滚后,版本将落后远程分支,必须使用强制推送覆盖远程分支,否则无法推送到远程分支

发布于: 2021 年 07 月 31 日阅读数: 9
用户头像

🏆2021年InfoQ写作平台-签约作者 🏆 2020.03.25 加入

👑【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 我们始于迷惘,终于更高水平的迷惘

评论

发布
暂无评论
🏆「推荐收藏」【Git实战专题】代码提交错误怎么办?教你如何回退版本!