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编辑框,

git-reset-revert-10

按照图示将 “commit eee file” 左侧的pick改为d或者drop后,会丢掉对应的commit。从而达到撤销的目的。

git-reset-revert-11

用 git rebase 实现撤销和 git reset --hard 的效果类似,即「删除已撤销commit的代码变更,撤销git add,工作空间回到上一次commit状态」。如果被撤销commit的代码还有用,使用时须谨慎。

撤销已push的文件

主要思路就是在本地分支撤销了commit之后,将变更推送到远端。但必须用git push -f强制提交,否则会提交失败,原因是:本地的版本号低于远端的版本号。

git-reset-revert-12

需要注意的是,如果test分支不只是你自己一个人维护,别人也在向这个分支上push代码,在进行强制推送之前就要注意下了,有可能会把别人的提交撤销掉。

如果你是项目的owner,在本地master分支使用git rebase 或者 git reset撤销了一些commit之后,想要强制推送到远端,以使远端的记录也撤销掉。你会使用git push origin master -f,但可能会遇到下面的错误。

覆盖远端失败

意思就是master分支是“protected branch”,不允许强制变更。解决方法是登录GitLab,进入项目的设置页面,选择Repository,找到Protected Branches,对分支进行「Unprotect」即可。

unprotected-maste

风险问题大家根据项目情况自行评估。

「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-reset-revert-14

git revert 后面一般跟commitId, 是你想回退的commit的id。例如在上图示例中,我想回退eee的提交,则commitId即是「d9a16cc」。

git revert 执行后会自动生成一个类似「Revert “commit message”」的新的commit。该commit的内容和需要revert的内容相反。若回退前新增了一个文件,revert后会将该文件删除;若会提前删除了一个文件的一行代码,revert后会将该文件的该行代码补回来。

如果需要将撤销更新到远端,push 即可,不需要 push -f 。

总结

  1. git rebase (drop) 相当于 get reset --hard,不会保留要撤销commit的代码变更。

  2. git reset 和 git rebase (drop) 都是通过删除之前commit的方式,达到撤销操作的目的,而 git revert 则是通过自动的反向操作完成这一目的。不同于前两个指令,git revert的HEAD指针是继续前进的。

  3. 根据要撤销commit所在分支的情况,选择适当的命令。

    一般来说,git revert 更安全,但也会生成新的revert commit,如果撤销的commit很多的话,git log 不是很好看(当然,也有办法优化,可以通过git rebase 将多个revert commit 合并成一个。见总结2)。

    如果要撤销的commit还没被推到远端,不妨使用 git rebase (drop) 或者 git reset。如果已经被推送到和他人共同维护的远端分支,或者已经被merge到主分支,最好使用git revert。

参考

链接: git撤销commit,回退已经push的文件_星辰和夕月的博客-CSDN博客