4

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

 2 years ago
source link: https://my.oschina.net/liboware/blog/5156420
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

预备知识

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

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

  • git log:该命令显示从最近到最远的提交日志。
commit e620a6ff0940a8dff91e0d252f30e4d138ec37be
Author: TangShengqin <[email protected]>
Date: Wed Jan 3 10:35:44 2018 +0800

commit 33342d9870f104719d351539a15e74a1382407ea
Author: TangShengqin <[email protected]>
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 HEAD
git 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都是默认创建的,所以可以这样省略。

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK