存檔錯了如何處理?
接上一篇從存檔的多版本推進聊聊Git分支,假設我們最終使用了cherry-pick進行了存檔的合併,那現在我們得到的存檔結果是這樣的。
m00 / \ m01 m00-1 / \ m02 m00-2 \ m00-3
但是,假設我們合併完了,發現合併錯了,該怎麼辦呢?或者另外一個場景,我們在從m00-2存檔到m00-3存檔到遊戲過程中,發現中途漏掉了某個蘑菇沒有吃。我們想從m00-2存檔重新進行遊戲,把那個蘑菇給吃了,該怎麼處理呢?
一種方式是忽略。我們可以重新讀取m00-2的存檔,從此處重新開始一個新流程。
git checkout 5eab37973211a
進行遊戲後,我們啟動一個新流程,並儲存。這裡不再贅述,請參考從遊戲存檔聊聊Git版本管理。
git switch -c load-01git add player。txtgit commit -m ‘m00-4’
此時的存檔變成了這樣:
m00 / \ m01 m00-1 / \ m02 m00-2 / \ m00-3 m00-4
不過這個m00-3看著挺煩人的。git提供了兩種方式來進行回滾操作:
第一種方式是reset
另外一種是revert
reset
我們一個個來演示 ,先看reset。直接執行如下命令:
git reset HEAD^ ——hard
執行完成後,你就會發現存檔又回到了合併前的樣子了,然後你就可以繼續玩遊戲了。
m00 / \ m01 m00-1 / \ m02 m00-2
我們對上面的命令做一個簡單的解釋:
HEAD可以理解為一個指標,它指向了當前分支(流程)中最新的一次提交(存檔)
後面的^表示向前退一步,即指向前一次提交(存檔)。如果要退兩步,那就是HEAD^^;退三步就是HEAD^^^;如果推10步呢?可以使用HEAD~10。
—hard表示目錄中的存檔也需要變化。如果你不新增—hard,你會發現player。txt檔案的內容並沒有變化。你還需要再執行一下
git restore player。txt
還記得快速理解Git中提到的概念模型嗎?工作區、索引區和本地/遠端倉庫。針對不同的區域,reset支援多種模式的重置,上面的—hard就是其中之一:
soft
:將HEAD回滾到指定的commit處,對索引和工作區沒有影響。主要用於對最後一次提交的修改。比如:你commit了修改後發現這個commit裡漏掉了一個檔案,你可以再提交一次。也可以回滾此次提交,然後將漏掉的檔案新增到索引後再次提交。
mixed
:預設reset操作。以目前HEAD所指向的commit為基準,重置索引區,不重置工作區。舉個例子:假設你修改了a。txt檔案,並將其新增到索引區。如果此時執行reset,則新增索引區的操作被回滾,而a。txt檔案的修改還保留。
hard
:以目前HEAD所指向的commit為基準,重置索引區和工作區。舉個例子:假設你修改了a。txt檔案,並將其新增到索引區。如果此時執行reset,則新增索引區的操作被回滾,同時a。txt也被回滾到修改前的狀態。
revert
除了使用reset,我們也可以使用revert來進行回滾操作。
首先我們還是先恢復到下面的存檔結構(回憶一下我們是怎麼操作的):
m00 / \ m01 m00-1 / \ m02 m00-2 \ m00-3
恢復完之後,player。txt中的內容如下所示: ******** ************ ####。。。。#。 #。。###。。。。。##。。。。 ###……。###### ……。。。。。 ##*####### 1 - 3 ####*******###### 。。。#***。****。*###。。。。 。。。。**********##。。。。。 。。。。**** *****。。。。 #### #### ###### ######
我們執行如下命令進行恢復:
git revert HEAD
執行完之後,會出現一個類似下面的提示
Revert “m00-3”This reverts commit d1b1ccaedaa919e45dcf77960b19948216d86ca9。# Please enter the commit message for your changes。 Lines starting# with ‘#’ will be ignored, and an empty message aborts the commit。## On branch load-00# Changes to be committed:# modified: player。txt
你可以修改一下文字,也可以直接:wq退出。操作完成後,player。txt中的內容恢復為:
******** ************ ####。。。。#。 #。。###。。。。。##。。。。 ###……。###### ……。。。。。 ##*####### 1 - 1 ####*******###### 。。。#***。****。*###。。。。 。。。。**********##。。。。。 。。。。**** *****。。。。 #### #### ###### ######
兩者的差異
如上所示,reset和revert都可以恢復前一次的提交,那兩者的差異是什麼的?
對於reset來說,就是對指定的提交進行了撤回。當執行了reset後,整個存檔就恢復到了提交前的狀態
而revert並不是,它是打了一個patch,將前一次的提交進行了抵消。什麼意思呢?我們執行一下
git log
就能比較清晰的看出差異了。
commit 45c8dc8fecffc4935d38484100d1f6b548cc35ba (HEAD -> load-00)Author: 一瑜一琂Date: Fri Mar 18 22:49:38 2022 +0800 Revert “m00-3” This reverts commit d1b1ccaedaa919e45dcf77960b19948216d86ca9。commit d1b1ccaedaa919e45dcf77960b19948216d86ca9Author: 一瑜一琂Date: Fri Mar 18 22:26:40 2022 +0800 m00-3commit 5eab37973211a466cc692999b93c16561cc2a157Author: 一瑜一琂Date: Thu Mar 17 14:19:49 2022 +0800 m00-2commit 79bd5c56e020eeb47919be29b29928e7397c1929Author: 一瑜一琂Date: Wed Mar 16 15:46:39 2022 +0800 m00-1commit b0d5581b592f3d5faaca744e88eed604f2289904Author: 一瑜一琂Date: Wed Mar 16 14:05:19 2022 +0800 m00```
可以發現,我們多了一個存檔,就是上面顯示的Revert “m00-3”。這個提交就是m00-3的逆操作,它抵消了m00-3的修改。整個存檔看起來像這樣:
m00
/ \
m01 m00-1
/ \
m02 m00-2
\
m00-3
\
Revert “m00-3”
為什麼需要revert呢?或者revert的使用場景是什麼呢?
假設你現在想抵消掉m00-1的記錄,那麼你就可以使用revert!此時如果你使用了reset,那麼m00-2和m00-3這兩個提交就都消失了。
總結
本文簡單梳理了Git回滾的方式。
到目前為止,我們都只是在操作本地倉庫,下面我們來聊一聊遠端倉庫。