回滾是 Git 的殺手鐗,是程序員的後悔藥。那如何進行回滾呢?答案是 git revert
。接下來進行一步步演示:git
git init
建立倉庫vi a.txt
建立一個文件,第一行寫上 a
,提交 gc -am 'feat: first commit'
vi a.txt
建立一個文件,第二行寫上 b
,提交 gc -am 'fix: add b'
vi a.txt
建立一個文件,第二行寫上 c
,提交 gc -am 'fix: add c'
vi a.txt
建立一個文件,第二行寫上 d
,提交 gc -am 'fix: add d'
好了,此時 a.txt 的內容以下:程序員
a
b
c
d
複製代碼
用 git log
查看歷史提交記錄:shell
commit 3ced7b954ec5023b827ba685a96f836bf1acefde (HEAD -> two, one)
fix: add d
commit 873c8bdb57149fabbd533caa7c4b6ec9ac3adb6a
fix: add c
commit 93ea0f972d591d54b07edba40a51b28486bbf9fd
fix: add b
commit c58aa1bbb6d22f6ba19b89252a352abfea8d92c4
feat: first commit
複製代碼
到目前爲止,你的提交長這樣:markdown
是否是還挺好看的呢!咱們把 commit 鏈描述以下:spa
A -> B -> C -> D
複製代碼
假如如今你想把最後一次提交 D 給回滾掉,應該如何操做呢?很簡單:3d
$ git revert HEAD
複製代碼
這個時候,會自動生成一次提交,默認內容爲:code
Revert "fix: add d"
This reverts commit 3ced7b954ec5023b827ba685a96f836bf1acefde.
複製代碼
固然,這個是能夠改的,咱們先保持不動,用 :wq
保存並退出。會發現多了一次新的提交,該提交的做用就是把最後一次的提交給撤銷了。orm
那若是不是撤銷最後一次提交呢,中間任何一次均可以的,假如咱們要回滾 add b 那次提交,能夠用:string
git revert 93ea0f972d591d54b07edba40a51b28486bbf9fd
複製代碼
這個時候,你指望發生什麼呢?是否是 a.txt 的內容變成了:it
a
c
d
複製代碼
然而並不是如此,而是出現了衝突:
$ git revert 93ea0f972d591d54b07edba40a51b28486bbf9fd
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
error: could not revert 93ea0f9... fix: add b
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
複製代碼
會變成了這樣:
revert B 那一次操做會以 A 的狀態爲參考基準,即比較當前的狀態和 A 狀態的區別,發現衝突就會提示讓用戶本身去解決。
若是要撤銷連續的提交,能夠用一個範圍來表示:
git revert 93ea0f972d591d54b07edba40a51b28486bbf9fd^..HEAD
複製代碼
這個時候你會發現記錄變成下面這個樣子了:
也就是說把 93ea0f972 和 HEAD 之間的全部提交都給按照順序撤回了,這就是所謂的 range revert 語法:
git revert B^..D
複製代碼
這樣就把 B,C,D 都給revert了,變成:
A-> B ->C -> D -> D'-> C' -> B'
複製代碼
這種方式,每次回滾都會生成一次新的提交。其實咱們能夠加個 -n
參數把屢次合併成一次:
git revert -n 93ea0f972d591d54b07edba40a51b28486bbf9fd^..HEAD
複製代碼
再看提交記錄:
是否是看起來就清爽多了,再複習一下語法:
git revert -n OLDER_COMMIT^..NEWER_COMMIT
git commit -m "revert OLDER_COMMIT to NEWER_COMMIT"
複製代碼