本節主要知識點:
回滾相關命令
git add
命令用於把工作目錄的文件放入暫存區域git commit
命令用於把暫存區域的文件提交到 Git 倉庫git reset
命令用於把 Git 倉庫的文件還原到暫存區域git checkout
命令用於把暫存區域的文件還原到工作目錄
reset 回滾快照三步曲
- 移動 HEAD 的指向(–soft)
- 將快照回滾到暫存區域([–mixed],默認)
- 將暫存區域還原到工作目錄(–hard)
回滾指定快照
在命令行中將路徑切換至文件夾中,然後使用命令
git reset + 具體的快照 ID(一般5位就行)'
回滾個別文件
在命令行中將路徑切換至文件夾中,然後使用命令
git reset 快照 文件名/路徑 '
reset 不僅是一個“復古”的命令,它不僅可以回到過去,還可以去到“未來”。不僅可以往回滾,還可以往前滾!
失去了以前版本的ID
在命令行中將路徑切換至文件夾中,然後使用命令
git reflog'
上一講無意中接觸到了兩個有關回退的命令:reset 和 checkout
現在幾個命令應該相當清晰了:
git add
命令用於把工作目錄的文件放入暫存區域git commit
命令用於把暫存區域的文件提交到 Git 倉庫git reset
命令用於把 Git 倉庫的文件還原到暫存區域git checkout
命令用於把暫存區域的文件還原到工作目錄
前邊兩個命令我有信心你已經相當熟悉了,但後邊兩個千萬別說你已懂,因爲它們是 Git 裏邊最複雜的命令(它們的功能可不止上邊文字描述的這麼簡單
先給大家重點講解 reset 命令,checkout 命令在分支管理中再細講。
先執行 git log
命令查看歷史提交:
這裏記錄了我們之前的 3 次提交(排序是按時間從近到遠的),Author 後邊是提交者,Date 後邊是提交日期,下邊是當次提交的說明。那……草黃色的那個 commit +“亂碼”是 Git 爲每次提交計算出來的 ID,它其實一個完整的 SHA-1 校驗和(儘管你的文件內容可能跟我的完全一致,但這個值卻不一樣,這是因爲賬號、時間不同而導致),在任何時候都是唯一的,通過這個 ID,你就可以找到對應的那個版本。
根據 log 記錄,現在我們將 Git 倉庫如果可視化,應該是這樣子:
回滾快照
注:快照即提交的版本,每個版本我們稱之爲一個快照。
現在我們利用 reset 命令回滾快照,並看看 Git 倉庫和三棵樹分別發生了什麼。
執行 it reset HEAD~
命令:
注:HEAD 表示最新提交的快照(31f46),而 HEAD~ 表示 HEAD 的上一個快照(d19e3)
然後執行 git status
命令查看現在的狀態:
現在我們的快照(d19e3)回滾到 第二棵樹(暫存區域)!
有些朋友可能會持不同意見:不應該是回滾到第一棵樹(工作目錄)嗎?你看,Git 不是寫得很清楚嗎 -> Changes not staged for commit,它還好心提醒我們使用 add 命令將修改添加到暫存區域丫!
其實真相是這樣的:我們執行 git reset HEAD~
命令之後,快照(d19e3)回滾到暫存區域,此時工作目錄裏存放的卻是最新的文件(31f46)。由於 Git 會跟蹤文件的變化,所以執行 git status
命令時,git 發現工作目錄中的文件比暫存區域的要新(對比日期),所以纔有這樣的提示……
好了,現在執行完 git reset HEAD~
命令之後,Git 倉庫應該是這樣子:
三棵樹現在應該是下面醬紫:
這裏有一點要補充的:HEAD~ 表示 HEAD 的上一個快照(d19e3),HEAD~~(00c29)則表示 HEAD 的上上一個快照,如果希望表示上 上 上 上 上 上 上 上 上 上一個快照(數了一下,這裏有 10 個“上” ),那麼可以直接用 HEAD~10 來表示。
git reset HEAD~
命令其實是 git reset --mixed HEAD~
的縮寫,因爲 --mixed 選項是默認的,所以我們可以偷懶。
我們發現,git reset HEAD~
命令其實影響了兩棵樹:首先是移動 HEAD 的指向,將其指向上一個快照(HEAD~);然後再將該位置的快照回滾到暫存區域。
爲了靈活地操縱這三棵樹,Git 還爲 reset 命令安排了 --soft 和 --hard 選項,
–soft 選項
加上 --soft 選項的結果是使得 reset 變“軟”了,也就沒有原來那麼持久……
So, git reset --soft HEAD~
命令就相當於只移動 HEAD 的指向,但並不會將快照回滾到暫存區域。
這個選項有什麼作用呢?
事實它就是相當於撤消了上一次的提交(commit)。
一不小心提交了,後悔了,那麼你就執行 git reset --soft HEAD~ 命令即可(此時執行 git log 命令,也不會再看到已經撤消了的那個提交)。
–hard 選項
加上 --hard 選項的結果是使得 reset 變“硬”……
你猜的不錯,加上 --hard 選項,reset 不僅移動 HEAD 的指向,將快照回滾動到暫存區域,它還將暫存區域的文件還原到工作目錄。
來,上點圖吧!
剛纔執行完 git reset HEAD~ 命令後,Git 倉庫裏的數據是這樣:
三棵樹是這樣:
那麼在這種狀態下,我再執行 git reset --hard HEAD~
命令:
Git 倉庫中就剩下最後一個快照了:
還原案發現場,Git 倉庫現在應該是這樣:
而三棵樹現在應該都被迴歸到第一個版本(00c2929):
不信?自己瞧瞧你的文件夾:
最後總結一下:reset 回滾快照三部曲
-
移動 HEAD 的指向(–soft)
-
將快照回滾到暫存區域([–mixed],默認)
-
將暫存區域還原到工作目錄(–hard)
回滾指定快照
如果快照比較多,你又懶得去數有多少個“上”,那麼你可以通過指定具體的快照 ID 來回滾該快照。
比如 git reset 00c2929
如上,你不必把辣麼長的 ID 號都給輸入進去,一般只要輸入前幾位(5 位或以上吧)就可以了。
回滾個別文件
reset 不僅可以回滾指定快照,還可以回滾個別文件。
命令格式爲 git reset 快照 文件名/路徑
這樣,它就會將忽略移動 HEAD 的指向這一步(因爲你只是回滾快照的部分內容,並不是整個快照,所以 HEAD 的指向不應該發生改變),直接將指定快照的指定文件回滾到暫存區域。
不僅可以往回滾,還可以往前滾!
這裏需要強調的是:reset 不僅是一個“復古”的命令,它不僅可以回到過去,還可以去到“未來”。
唯一的一個前提條件是:你需要知道指定快照的 ID 號。
現在執行 git log 命令只剩下一個最原始的提交了:
但是將命令行窗口向上拉,我們可以喵到之前提交的幾個版本 ID 號
所以我們可以執行 git reset --hard 31f46be
命令:
再次執行 git log 命令:
我們又回到了最新的版本!
是的,我們就這樣在歷史的長河裏滾來滾去……
但是……故事還沒完,如果某天你 reset --hard 將工作目錄回滾到了某個版本,但特麼的隔天你就後悔了(有封寫給小花的情書也放裏邊)!此時命令行窗口早已關閉,你又沒用小本本把每次 commit 的 ID 號給記下來,這可腫麼辦纔好?
reflog 命令可以拯救你!
執行 git reflog
命令,告訴我,你看到了什麼:
Git 偷偷記錄下了你每一次的操作(無恥小人),第一列就是每次執行完命令,HEAD 指向的版本 ID 號啦~