參考
https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86
https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
https://git-scm.com/docs/git-reset
https://www.liaoxuefeng.com/wiki/896043488029600/897013573512192
從歷史記錄中刪除 參考 https://www.cnblogs.com/studywithallofyou/p/11772684.html https://www.cnblogs.com/studywithallofyou/p/11772844.html
前言
在使用git的時候,我們一般提倡是不允許回滾。對於問題的追蹤和項目的發展歷程而言歷史記錄都是有用的。並且為了節省一點存儲空間而丟失寶貴的代碼信息是不值當的。但是我們開發中,肯定會遇到特殊情況需要回退。比如確實操作錯了一步歷史提交,導致倉庫混亂污染或是內容丟失,我們需要回退到干凈的一次提交,重新操作。
在git等所有的版本管理軟件中,刪除操作,只是增加一次記錄,內容並不會被刪掉,我們可以大膽的操作,這也符合版本倉庫的邏輯。只有特殊情況才需要真正的刪除,做這種操作的時候需要特別注意,因為一旦失誤,無法挽回。
工作流程
要想理解git reset,那么就要搞清楚git倉庫管理流程:
我們修改完內容后,這些記錄單單是保存在我們本地目錄下,也就是工作目錄。如果丟了,就是丟了,無法找回。與普通磁盤上的文件一樣,除非到回收站找回。
這時,如果運行了add,那么內容就被記錄到本地的暫存倉庫,也就是index。這時如果刪除文件,在暫存區的內容還存在,並沒有丟失。
如下圖,我們創建了一個文件4,這時文件4在本地。我們add到暫存倉庫,然后刪掉文件4,我們發現又多了一條記錄刪除記錄,原來的4還存在,我們可以commit。原來的文件4並沒有丟失。
運行commit之后,修改的內容就被保存到了倉庫,修改了HEAD(HEAD就是指向當前倉庫在哪一個提交歷史,不特殊修改,都指向最新的一次提交)。這時運行git status發現目錄是干凈的。git里面需要提交倉庫,暫存倉庫和本地目錄內容都完全一致,才是干凈的,任何一個不一致都會有不同的提示。
比如上面的圖,提交的倉庫中沒有文件4,暫存倉庫中增加了4,所以顯示綠色的提示內容,add了文件但是還沒有commit。但是本次又刪除了文件,本地目錄中的內容與暫存倉庫也不一樣,所以提示紅色的內容,因為算是警告,沒有add的內容是會丟失的。
修改
add
commit
git reset的三個選擇
理解了上面的流程,就可以理解git reset了。git reset就是分別逆向操作,也就是把HEAD(提交的倉庫)回退到一個指定歷史,把HEAD、index(暫存倉庫)都回退到指定歷史,把HEAD、index和本地目錄的內容都回退到一個指定歷史。
git reset --soft就是把HEAD回退到指定歷史。運行后結果如下
也就相當於我們add了修改的文件,本地目錄和暫存倉庫都已經一致了,就等待commit。如果我們commit,可以再次填寫commit記錄,也就實現了git commit --amend的功能。
git reset --mixed就是把HEAD和index都回退到指定的歷史。這個也是運行git reset不加參數時的默認規則。運行結果如下
相當於我們僅僅修改了文件,還沒做任何處理。
git reset --hard這個是把HEAD、index和本地目錄的內容都回退到指定的歷史記錄。做這一步操作的時候一定要小心,最好把所有的內容都提交,並且push到遠程或是拷貝一份。因為這個操作會重置本地的內容到一個指定歷史。
我們先運行git log,看到有三個提交歷史
運行git reset --hard HEAD~
我們發現倉庫是干凈的,並且原來的3文件沒了,運行git log參看
提交的歷史記錄也沒有了。
這次是真的回退到了指定歷史,所有的記錄都不見了,我們可以開心的(真的嗎?)在原來一個干凈的分支上繼續寫代碼了。
git reset --hard的后悔葯
世上有沒有后悔葯我不知道,但是git作為一個先進的分布式管理器,卻有無限可能。如果你一不小心,腦袋發熱,運行了git reset --hard,但是發現不是你想要的,原來的記錄也沒了。怎么辦?大腦瞬間充血,一片空白。不要慌,首先冷靜下來,然后運行git reflog,這個命令是告訴你你的每一次對倉庫操作的歷史記錄,如下
看一下最上面的幾條,第一條告訴你當前在e86d948這個提交記錄,通過reset切換過來的。對照上面的git log,可以發現這個是第二個提交歷史,也就是我們git reset --hard HEAD~的時候回退的分支。第二條記錄告訴我們當前是fc9fbc6分支,通過reset回退到這個分支的,我們可以參考上面的git log記錄,這個就是我們想要回去的分支。好了,有了記錄的哈希值,我們只需再運行一次git reset --hard,如下
查看一下git log
回來了。
git不會刪除任何已經提交到版本庫的內容,除非你非要專門特殊這樣做,並且為了再給你一次機會,像git reset這樣,就算你明確說明不要了,它也不會立馬刪除,除非超過一定時間或是你主動運行git gc等操作,把無用的,沒有關聯的內容刪掉。不然,那條記錄還是在本地倉庫,只不過它沒有被載入歷史的長河中。