天天看點

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用來撤銷沒有送出的更改