天天看点

git push之后回滚(撤销)代码

问题描述:

首先,先说明一下,为什么会引发这次的话题,是这样的,我做完功能Agit push之后,2个月后需求部门要求不要功能A了,然后需要在没有功能A的基础上开发,怎么办?赶紧回滚代码呀。

然后我用git reset --hard 版本号,发现报错,提示我当前的分支落后于线上分支1个提交,怎么办?

于是,就有了今天的这个话题,git push 之后后悔了,怎么办?

总结了三种方法(可能不止以下三种方法)

一、git reset --hard 要回滚的版本号 ,再 git reset 最新的版本号

操作如下:

1、首先对a.txt文件进行三次修改,第一次写入1并提交,第二次写入2并提交,第三次写入3并提交,然后cat a.txt看一下a.txt当前的内容,然后现在我们需要回滚到主有内容1的基础上做开发

git push之后回滚(撤销)代码

2、git reset --hard 要回滚的版本号,查看当前的文件内容,主有内容1,确实是我们想要的了,但是git push之后发现,报错,提示我当前的分支落后于线上分支2个提交,怎么办?只能绕一下了达到我们想要的目的了。

git push之后回滚(撤销)代码

3、git reset 最新版本号,为什么这样做就可以到达我们想要的效果呢?这一步主要是将head移到最新的版本(和线上的head保持一致,内容还是保持主有内容1的内容)

git push之后回滚(撤销)代码

讲了那么多,估计你还是一头雾水,没关系,我们可以先来了解一下git reset的三种模式

首先,开始做几次提交

echo 1 > huangqiqi.txt
git add .
git commit -m 'first commit'
echo 2 >> huangqiqi.txt
git add .
git commit -m 'second commit'
echo 3 >> huangqiqi.txt
git add .
git commit -m 'third commit'
           

看下提交log

git push之后回滚(撤销)代码

查看当前提交的huangqiqi.txt

git push之后回滚(撤销)代码

1、首先来看第一种reset模式, git reset --mixed,即其默认的模式,即git reset 版本号。结果如下

git push之后回滚(撤销)代码
git push之后回滚(撤销)代码
git push之后回滚(撤销)代码
git push之后回滚(撤销)代码

看出什么了吗,git将提交回滚到了second commit, 同时清空了暂存区(也称stage或index,下文用stage代替暂存区),但是工作区仍然保留,所以git status时,显示时当前工作区相对于second commit的变动。使用这种模式不用害怕吧,他并不会清除你的工作区,你在third commit做的任何操作都不会消失。 

2. 看另一种方式,soft模式,git reset --soft 版本号

git push之后回滚(撤销)代码
git push之后回滚(撤销)代码

看到了吧,采用这种模式,git不回清除你的stage区,因此,git status时就显示了stage区相对于second commit的变化。此时工作区是clean 的,而stage区则有变化。 

3. 第三种方式 --hard,git reset --hard 版本号

git push之后回滚(撤销)代码

这时工作区,stage区都是干净的,然而huangqiqi.txt则残忍的回到了第二次提交是的状态。这说明了啥,采用这种模式,git回用second commit 的内容覆盖stage区和工作区,因此所有的内容都回到了second commit的状态。

实例做完了,开始总结吧  git reset –soft 不会改变stage区,仅仅将commit回退到了指定的提交  git reset –mixed 不回改变工作区,但是会用指定的commit覆盖stage 区,之前所有暂存的内容都变为为暂存的状态  git reset –hard 使用指定的commit的内容覆盖stage区和工作区。

git push之后回滚(撤销)代码

了解完git reset 的三种模式后,你再实操一下方法一,估计就懂为什么要这样做了。

二、git reset --hard 要回滚的版本号 再 git push -f  origin master命令去强制提交

这种强制提交的方法只有owner才可以执行,因为我只是开发者,所以直接pass掉这种方法

三、git revert 最新版本号 ... 要回滚的版本号(避免冲突,只能一步一步回滚到你想要的版本号)

接着,介绍一下git revert

开始做几次提交

echo 1 > a.txt
git add .git commit -m '增加1'
echo 2 >> a.txt
git add .git commit -m '增加2'
touch b.txt
git add .
git commit -m "增加b.txt"
echo 3 >> a.txt
git add .git commit -m '增加3'
           

看下提交log

git push之后回滚(撤销)代码

git revert 3a806223342f 结果是? 撤销“增加b.txt”操作,只剩下a.txt

git push之后回滚(撤销)代码

git revert 928abd8c8ff 结果是?报错,有冲突,为什么?因为“增加2”这个操作之后,我又在这个文件上做了个“增加3”的这个操作,如果直接撤销“增加2”这个操作,会有冲突,所以只能先撤销“增加3”这个操作,在撤销“增加2”这个操作

git push之后回滚(撤销)代码

git revert c61a875 9281bd 结果:撤销“增加2”“增加3”操作

git push之后回滚(撤销)代码

revert 注意是撤销某次操作,而不是恢复到

git revert用于反转提交,执行命令时要求工作树必须是干净的. git revert用一个新提交来消除一个历史提交所做的任何修改. revert 之后你的本地代码会回滚到指定的历史版本,这时你再 git push 既可以把线上的代码更新.(这里不会像reset造成冲突的问题)

git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit 看似达到的效果是一样的,其实完全不同. 第一: 上面我们说的如果你已经push到线上代码库, reset 删除指定commit以后,你git push可能导致一大堆冲突.但是revert 并不会. 第二: 如果在日后现有分支和历史分支需要合并的时候,reset 恢复部分的代码依然会出现在历史分支里.但是revert 方向提交的commit 并不会出现在历史分支里. 第三: reset 是在正常的commit历史中,删除了指定的commit,这时 HEAD 是向后移动了,而 revert 是在正常的commit历史中再commit一次,只不过是反向提交,他的 HEAD 是一直向前的.

git revert(撤消操作)的格式: 撤销某次操作,此次操作之前的commit都会被保留. git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区. 格式 git revert [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...git revert --continue git revert --quit git revert --abort 示例

  1. git revert HEAD~3:丢弃最近的三个commit,把状态恢复到最近的第四个commit,并且提交一个新的commit来记录这次改变。
  2. git revert -n master~5..master~2:丢弃从最近的第五个commit(包含)到第二个(不包含),但是不自动生成commit,这个revert仅仅修改working tree和index。

建议,你可以用git revert来撤销已经提交的更改,而git reset用来撤销没有提交的更改