預備知識
-
一個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的用法:
- reset: push前。
- 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都是預設建立的,所以可以這樣省略。
注意:本地分支回滾後,版本將落後遠端分支,必須使用強制推送覆蓋遠端分支,否則無法推送到遠端分支