Git 回退 commit、push 操作
git reset
git reset --soft HEAD~1
撤销最近一次的commit(撤销commit,不撤销git add)
git reset --mixed HEAD~1
撤销最近一次的commit(撤销commit,撤销git add)
git reset --hard HEAD~1
撤销最近一次的commit(撤销commit,撤销git add,工作区的代码改动将丢失。操作完成后回到上一次commit状态)
HEAD~1
的意思是最近一个版本,也可以写成HEAD^
如果需要撤回最近两次提交的commit,可以使用HEAD~2
,依次类推。
三种方式对工作空间的改动不一样。
- --soft 保留已撤销commit的代码变更,不会撤销git add,
- --mixed 保留已撤销commit的代码变更,撤销git add,
- --hard 删除已撤销commit的代码变更,撤销git add,工作空间回到上一次commit状态。
git rebase 撤销某个commit
git log --oneline --graph --all
git rebase -i commitId
用git rebase可以做到撤销某个commit。
如果要撤销“commit eee file”{cid:d9a16cc}这个提交,使用 git rebase -i 9df3805
,其中「9df3805」是eee的上一次提交的commitId。当然,也可以使用 git rebase -i HEAD~2
。
执行 git rebase -i 9df3805
之后,会出现下面的交互式vim编辑框,
按照图示将 “commit eee file” 左侧的pick改为d或者drop后,会丢掉对应的commit。从而达到撤销的目的。
用 git rebase 实现撤销和 git reset --hard 的效果类似,即「删除已撤销commit的代码变更,撤销git add,工作空间回到上一次commit状态」。如果被撤销commit的代码还有用,使用时须谨慎。
撤销已push的文件
主要思路就是在本地分支撤销了commit之后,将变更推送到远端。但必须用git push -f
强制提交,否则会提交失败,原因是:本地的版本号低于远端的版本号。
需要注意的是,如果test分支不只是你自己一个人维护,别人也在向这个分支上push代码,在进行强制推送之前就要注意下了,有可能会把别人的提交撤销掉。
如果你是项目的owner,在本地master分支使用git rebase 或者 git reset撤销了一些commit之后,想要强制推送到远端,以使远端的记录也撤销掉。你会使用git push origin master -f
,但可能会遇到下面的错误。
意思就是master分支是“protected branch”,不允许强制变更。解决方法是登录GitLab,进入项目的设置页面,选择Repository,找到Protected Branches,对分支进行「Unprotect」即可。
风险问题大家根据项目情况自行评估。
「Unprotect」之后 push -f
就可以成功了。
git revert 回退(推荐)
# 查找要回退的 commitId
git log --oneline --graph --all
# 执行回退指令
git revert commitId
# 推送代码到 git 仓库
git push
git revert 是一个很安全也很好用的命令,不同于git reset的重置,它是通过反向操作来完成撤销的。先来看用法。
需求:撤销“commit eee file”{cid:d9a16cc} 的变更。
git revert 后面一般跟commitId, 是你想回退的commit的id。例如在上图示例中,我想回退eee的提交,则commitId即是「d9a16cc」。
git revert 执行后会自动生成一个类似「Revert “commit message”」的新的commit。该commit的内容和需要revert的内容相反。若回退前新增了一个文件,revert后会将该文件删除;若会提前删除了一个文件的一行代码,revert后会将该文件的该行代码补回来。
如果需要将撤销更新到远端,push 即可,不需要 push -f 。
总结
git rebase (drop) 相当于 get reset --hard,不会保留要撤销commit的代码变更。
git reset 和 git rebase (drop) 都是通过删除之前commit的方式,达到撤销操作的目的,而 git revert 则是通过自动的反向操作完成这一目的。不同于前两个指令,git revert的HEAD指针是继续前进的。
根据要撤销commit所在分支的情况,选择适当的命令。
一般来说,git revert 更安全,但也会生成新的revert commit,如果撤销的commit很多的话,git log 不是很好看(当然,也有办法优化,可以通过git rebase 将多个revert commit 合并成一个。见总结2)。
如果要撤销的commit还没被推到远端,不妨使用 git rebase (drop) 或者 git reset。如果已经被推送到和他人共同维护的远端分支,或者已经被merge到主分支,最好使用git revert。