背景
在利用git实现多人合作开发程序的过程中,有时会出现错误提交的情况,此时希望能撤销提交操作,让程序回到提交前的样子,本文总结了两种方法:reset(重置)、revert(恢复)。
先简单说一下,在提交到远程库之前我们使用git reset 命令完全可以满足我们 撤销操作的需求,如果操作已经提交到远程库,那只好使用 git revert 来提交一个新的撤销操作 撤销 需要撤销的那次commit。
git的工作流
工作区:即自己当前分支所修改的代码,git add xx 之前的!不包括 git add xx 和 git commit xxx 之后的。
暂存区:已经 git add xxx 进去,且未 git commit xxx 的。
本地分支:已经git commit -m xxx 提交到本地分支的。
在将文件提交至远程端时,文件的提交需要经过git add、git commit及git push三个过程才能提交至git远程仓库。我们平时修改文件在工作目录中,提交时先使用git add提交至暂存区,再通过git commit提交至本地仓库,最后才能使用git push提交至远程仓库。
- 在工作区的代码
1 | git checkout -- a.txt # 丢弃某个文件,或者 |
注意:git checkout – . 丢弃全部,也包括:新增的文件会被删除、删除的文件会恢复回来、修改的文件会回去。这几个前提都说的是,回到暂存区之前的样子。对之前保存在暂存区里的代码不会有任何影响。对commit提交到本地分支的代码就更没影响了。当然,如果你之前压根都没有暂存或commit,那就是回到你上次pull下来的样子了。
- 代码git add到缓存区,并未commit提交
1 | git reset HEAD . 或者 |
这个命令仅改变暂存区,并不改变工作区,这意味着在无任何其他操作的情况下,工作区中的实际文件同该命令运行之前无任何变化
- git commit到本地分支、但没有git push到远程
1 | git log # 得到你需要回退一次提交的commit id |
- git push把修改提交到远程仓库
1)通过git reset是直接删除指定的commit
1 | git log # 得到你需要回退一次提交的commit id |
2)通过git revert是用一次新的commit来回滚之前的commit
1 | git log # 得到你需要回退一次提交的commit id |
开发过程中,你肯定会遇到这样的场景:
场景一:
糟了,我刚把不想要的代码,commit到本地仓库中了,但是还没有做push操作!
场景二:
彻底完了,刚线上更新的代码出现问题了,需要还原这次提交的代码!
场景三:
刚才我发现之前的某次提交太愚蠢了,现在想要干掉它!
撤销
上述场景一,在未进行git push前的所有操作,都是在“本地仓库”中执行的。我们暂且将“本地仓库”的代码还原操作叫做“撤销”!
情况一:文件被修改了,但未执行git add操作(working tree内撤销)
1 | git checkout fileName |
情况二:同时对多个文件执行了git add操作,但本次只想提交其中一部分文件
1 | $ git add * |
情况三:文件执行了git add操作,但想撤销对其的修改(index内回滚)
1 | # 取消暂存 |
情况四:修改的文件已被git commit,但想再次修改不再产生新的Commit
1 | # 修改最后一次提交 |
reset
git reset中有三个命令(–hard、–soft与–mixed);主要用于工作区、暂存区、本地仓库三个区域的文件提交撤回
- git reset –hard xxx
hard (修改版本库,修改暂存区,修改工作区)
–hard HEAD~1 (或是版本号)意为将版本库回退1个版本,但是不仅仅是将本地版本库的头指针全部重置到指定版本,也会重置暂存区,并且会将工作区代码也回退到这个版本
git reset –soft xxx
soft (修改版本库,保留暂存区,保留工作区)
–soft HEAD~1 意为将版本库软回退1个版本,所谓软回退表示将本地版本库的头指针全部重置到指定版本,且将这次提交之后的所有变更都移动到暂存区。
revert
- git revert xxx
– git revert 也是撤销命令,区别在于reset是指向原地或者向前移动指针,git revert是创建一个commit来覆盖当前的commit,指针向后移动。
git revert 和 git reset的区别
- git revert是用一次新的commit来回滚之前的commit,此次提交之前的commit都会被保留;
- git reset是回到某次提交,提交及之前的commit都会被保留,但是此commit id之后的修改都会被删除
- git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
- 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
- git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。