?「推薦收藏」【Git實戰專題】程式碼提交錯誤怎麼辦?教你如何回退版本!

李浩宇Alex發表於2021-07-31

預備知識

  • 一個commit對應這一個版本,有一個commit id,40位的16進位制數字,通過SHA1計算得到,不同的檔案計算出來的SHA1值不同(有很小的機率相同,可忽略),這樣每一個提交都有其獨特的id。每提交一個新版本,實際上Git服務就會把它們自動串成一條時間線。

  • 在Git中,HEAD表示當前版本,例如:HEAD版本屬於:e620a6ff0940a8dff…,那麼HEAD^表示上一個版本,HEAD^^表示上上一個版本,往上100個版本可以寫成HEAD加連續100個^,也可以寫成:HEAD~100

  • git log:該命令顯示從最近到最遠的提交日誌。
commit e620a6ff0940a8dff91e0d252f30e4d138ec37be
Author: TangShengqin <15527733782@163.com>
Date: Wed Jan 3 10:35:44 2018 +0800

commit 33342d9870f104719d351539a15e74a1382407ea
Author: TangShengqin <15527733782@163.com>
Date: Wed Jan 3 10:34:03 2018 +0800
複製程式碼

git結構和各操作之間的關係

  • git log --pretty=oneline 檢視已提交的版本

回退版本(三種方式)

git reset commit_id(撤銷commit和add操作)

git reset預設是--mixed模式

git reset --mixed commit_id撤銷commit和add操作
複製程式碼
  • 回退一個版本,且會將暫存區的內容和本地已提交(commit)的內容全部恢復到未暫存的狀態,不影響原來本地檔案(未提交的也不受影響)

  • 會保留原始碼,只是將git commit和index資訊回退到了某個版本

git reset --soft commit_id(撤銷commit操作)

  • *回退一個版本,不清空暫存區,將已提交的內容恢復到暫存區,不影響原來本地的檔案(未提交的也不受影響)

  • 保留原始碼,只回退commit資訊到某個版本,不涉及index的回退,如果還需要提交,直接commit即可

git reset --hard commit_id(慎用)

git reset –hard commit_id 或則是 git reset –hard HEAD^

  • 撤銷commit和add操作,並將本地版本置回上一版本

  • 回退一個版本,清空暫存區,將已提交的內容的版本恢復到本地,本地的檔案也將被恢復的版本替換

  • 原始碼也會回退到某個版本,commit和index都會回退到某個版本.(注意這種方式是改變原生程式碼倉庫原始碼)

hard選項,表示徹底將工作區、暫存區和版本庫記錄恢復到指定的版本庫

reset和revert的用法:

  1. reset: push前。
  2. revert: push後。
git revert <commit_id..> 
複製程式碼

回滾到置頂的版本,執行後需要git push

reset與revert區別:

寫到了git reset指令,就不得不說下它與git revert的區別:

  • git reset是把HEAD向後移動了一下,而git revert是HEAD繼續前進,只是新的commit的內容和要revert的內容正好相反,能夠抵消要被revert的內容。

  • git revert是用一次新的commit來回滾之前的commit,git reset是直接刪除指定的commit。

  • 在回滾這一操作上看,效果差不多。但是在日後繼續merge以前的老版本時有區別。因為git revert是用一次逆向的commit“中和”之前的提交,因此日後合併老的branch時,導致這部分改變不會再次出現,但是git reset是直接把某些commit在某個branch上刪除,因而和老的branch再次merge時,這些被回滾的commit應該還會被引入。


實際案例

快取區程式碼覆蓋工作區程式碼

  • 場景:快取區存有上次改動程式碼,即之前有執行:git add

  • 當前工作區間程式碼想廢棄, 可將快取區中程式碼覆蓋之:

對應指令:

  • 快取區某一檔案程式碼 覆蓋本地工作區: git checkout -- testReset.txt
  • 將匹配的檔案覆蓋:git checkout -- *.txt
  • 將所有檔案覆蓋:git checkout -- .

本地倉庫程式碼覆蓋快取區程式碼

  • 場景:發現之前add的檔案不需要了,又不想工作區間重新改回去。

對應指令:

  • 將本地倉庫某一檔案覆蓋快取區: git reset HEAD testReset.txt
  • 將匹配的檔案覆蓋快取區:git reset HEAD *.txt
  • 將所有檔案覆蓋快取區:git reset HEAD .

注意:改變的是快取區程式碼,工作區間程式碼不變(編輯器程式碼不會改變)

本地倉庫程式碼覆蓋工作區程式碼(常用)

上述兩場景在實際開發中沒那麼常用,接下來 本地倉庫 程式碼 覆蓋 工作區間 程式碼 則經常會用到。

場景:當前工作區間程式碼混亂(一般更新或合併分支後),廢棄當前改動;

對應指令:

  • 將本地倉庫某一檔案程式碼 覆蓋本地工作區: git checkout HEAD testReset.txt

  • 將本地倉庫所有檔案程式碼 覆蓋本地工作區:(謹慎操作):git checkout HEAD .

我們知道本地倉庫中有一個commit列表, 記錄了所有commit的記錄, 檢視commit列表指令:

  • 檢視commit id, 檢視提交記錄(git commit的記錄)
git log 
git log --pretty=oneline 
複製程式碼
  • 檢視以往提交歷史(包括 撤銷回退 記錄)
git reflog 
複製程式碼

 

根據commit列表,工作區間程式碼能實現更靈活的回退:

  • 本地工作區間程式碼 回退到上一次版本、上上次、前10個版本
git reset --hard HEAD^ 
git reset --hard HEAD^^ 
git reset --hard HEAD~10 
複製程式碼
  • 本地工作區間程式碼 回退到指定版本(“d362816”為commit id)
git reset --hard d362816 
複製程式碼

遠端倉庫程式碼覆蓋本地倉庫程式碼(清除 未push 的commit)

場景: 有時候合併分支、切換分支、更新程式碼會導致提交絮亂的問題(沒使用--rebase方式),具體體現在自動生成了commit且工作區間 程式碼很多衝突。使工作區間程式碼跟線上程式碼一致且刪除新生成的commit。

對應指令:

  • 本地工作區間程式碼回退到遠端版本
git reset –-hard origin/master 
複製程式碼

遠端倉庫程式碼回滾(線上程式碼回滾)

場景: 提交了一個commit(該提交包含很多檔案), 發現有問題, 需要回滾, 將線上分支(master)回滾到上一次commit;

合理一些的是使用 git reset或git revert方式進行回滾;

git reset方式圖解:

git revert方式圖解:

我們可以使用git revert將新的commit替換掉;(不用git reset而用git revert的原因是保留commit方便後續程式碼恢復)

對應指令:
// 替換掉上次提交的程式碼檔案(上次的commit記錄會保留)
git revert HEAD
git commit -m "回滾上次commit"
git push origin master
複製程式碼
  • git revert HEAD:撤銷最近的一次提交,如果你最近一次提交是用revert命令產生的,那麼你再執行一次,就相當於撤銷了上次的撤銷操作,換句話說,你連續執行兩次revert HEAD命令,就跟沒執行是一樣的

總結案例

git log --pretty=oneline
複製程式碼

如果你在本地做了錯誤提交,那麼回退版本的方法很簡單

先用下面命令找到要回退的版本的commit id:

git reflog
複製程式碼

接著回退版本:

git reset --hard a7e1d279a7e1d279
複製程式碼

就是你要回退的版本的commit id的前面幾位。

遠端分支版本回退的方法

如果你的錯誤提交已經推送到自己的遠端分支了,那麼就需要回滾遠端分支了。

首先要回退本地分支:

git reflog 
git reset --hard Obfafd
複製程式碼

緊接著強制推送到遠端分支:

git push -f origin master 
複製程式碼
  • origin就是一個名字,它是在你clone一個託管在Github上程式碼庫時,git為你預設建立的指向這個遠端程式碼庫的標籤,origin指向的是repository,master只是這個repository中預設建立的第一個branch。

  • 當你git push的時候因為origin和master都是預設建立的,所以可以這樣省略。

注意:本地分支回滾後,版本將落後遠端分支,必須使用強制推送覆蓋遠端分支,否則無法推送到遠端分支

相關文章