Git操作檔案的時候手賤了,怎麼恢復?

TechFlow2019發表於2020-10-23

我們在使用git的過程當中很難避免的一點就是手賤,因為人嘛總有犯錯疏忽的時候,有時候一不小心就操作錯了。我也經常遇到這種情況,所以這時候對git的瞭解和掌握就非常重要,即使操作錯了,我們也可以通過git還原到我們希望它變成的狀態。下面我們來看幾個例子,來實際體驗一下git的強大。

不小心add錯了

這是一個非常非常容易出現的問題,我自己也經常遇到。有時候編譯出了二進位制檔案,明明知道是不應該新增進git管理的。因為新增進來之後會使得整個repo變得非常大,別人clone和pull都非常費勁。而且前面也說過了,一旦commit之後,即使你刪除了,這份檔案依然還是會儲存在git倉庫當中。

所以如果我們發現不小心把一個我們的測試檔案也一起add進來了,我們commit了之後才發現。這個時候應該怎麼辦?

我們來實際操作一下,比如我們建立了一個叫做a.test的檔案用來測試。結果測試完成之後忘記了刪除,直接commit了。這個時候我們要把它刪除,應該怎麼做呢?

我們要做的就是把它刪除,有人會說我們直接rm -rf刪除不行嗎?我們試試看就知道了。

這樣刪除了之後你會發現它會提示你,說這個改動沒有被commit,因為我們只是刪除了作業系統當中的檔案,並沒有刪除git倉庫當中已經儲存的檔案。所以只是這樣刪除了之後,即使我們再次commit提交,git會記錄成一次對這個檔案的刪除操作。雖然我們看不到這個檔案了,但是它仍然在git當中佔據空間。

所以要刪除只能使用git rm命令來進行,它會將檔案從git版本管理以及檔案系統當中一起移除。當我們提交之後,從下一個提交開始,這個檔案就不會被儲存一份了。

這裡有一個小問題是為什麼會從下一個版本開始?因為我們做的事情只是從git中刪除掉檔案,而不是撤銷add檔案的操作。所以git當中會記錄兩條,一條是記錄了新增檔案,一條是刪除了檔案。比如說我們在add file的commit當中提交了檔案,在delete file的commit當中刪除了檔案,在delete以及之後的提交當中,是沒有這個檔案的記錄的,但是在add file這個commit當中這個記錄仍然存在。

所以問題來了,如果我就想把這個檔案從git倉庫當中完全刪除,一點記錄都不留下呢?其實也簡單,我們只需要在commit的時候加上--amend引數即可。--amend表示不提交新的commit而是在當前的commit上修補,這樣相當於add file和delete file的commit合併成了一個,那麼這個檔案的記錄也就不存在了。

不過使用--amend需要小心,如果記錄已經push過遠端,會導致和遠端的記錄不吻合。這個時候需要使用git push -f來強行push。但是強行push會覆蓋遠端的commit,可能導致其他人程式碼的混亂,是一個非常危險的操作,請一定謹慎

只想撤銷,不想刪除

除了我們不小心提交了本該要刪除的內容,還有一種很常見的情況是我們的檔案是很重要的,但是我們不想提交到git。比如我們編譯出來的二進位制檔案,它們都是要用到的,只是不應該被push到git而已。我們在add了之後才發現add錯了檔案,於是我們想要撤銷,有辦法嗎?

比如這個時候我們已經add了檔案,但是還沒有commit,我們想要把這個a.test檔案從暫存區刪除,這樣就不會被記錄下來了。我們應該怎麼做呢?

其實很簡單,也是通過git rm命令。因為這個時候還沒有commit,也就是說這個檔案還沒有被提交進git倉庫當中,我們只需要把它從暫存區移除就可以了。如果使用git rm命令,它既會從暫存區移除,也會從本地刪除檔案。我們不想刪除本地的檔案,這個時候我們只需要加上一個引數--cached,表示我們只想移除已經快取在git暫存區的內容。

我們發現這個檔案回到了被add之前的狀態。

但假如我們不小心已經commit了,已經提交進git倉庫了之後才發現,這個時候應該怎麼辦?

這個時候我們需要做的是撤銷這個commit,給我們一次重新來過的機會。我們使用的命令是git reset --soft HEAD^,git reset命令非常危險,我們操作的時候需要謹慎。如果不小心用了--hard引數會回滾所有的操作,直接恢復到某一個commit時的狀態。比如說我們當前在version3,我們回到了version1,如果使用--hard操作的話,version2和version3的所有改動都會丟失。因此一定謹慎使用--hard,最好使用--mixed或者是--soft,它不會修改本地的檔案。關於這兩個的區別,我們將會以後在介紹git reset命令的時候詳細介紹。

這裡的HEAD指的是當前git節點的指標,HEAD^表示的是上一個版本。當然我們也可以用commitid來代替。

我們發現一切都恢復到了illustrate unstage commit這個提交之前的狀態,那麼我們只需要從快取當中刪除a.test,再次提交即可。

這麼操作完了之後你會發現在git log當中illustrate unstage commit這個提交不見了。的確如此,因為它被我們撤銷了,同樣,reset操作也會導致本地和遠端狀態不一樣。如果要push的話也需要-f強制進行,這也是一個危險的操作,一定要謹慎。

撤銷修改

加入我們想要撤銷的不是一個檔案,而是一次修改呢?就比如我們git add了之後才發現某一個檔案的修改錯了,我們想要把它恢復到之前的狀態,這時候應該怎麼操作呢?

我們在第五篇里加上了一行廢話,但是等我們git add了之後才發現第五篇裡有這麼一個無用的改動。這時候應該怎麼操作呢?

這個時候我們想要做的是撤銷這個檔案的修改,如果我們只是要把它從暫存區中移除來恢復到git add之前的狀態,我們可以使用git reset,但是這個檔案當中的修改依然還是存在。這個時候我們可以用一個命令叫做checkout,這個命令有很多種用途,我們先介紹其中的一種。

我們可以使用git checkout -- filename來回滾某一個檔案的改動,注意這個也是一個危險操作,它會直接將檔案恢復到之前提交的狀態。中間的改動會全部丟失,因此一定要想好了再操作。在git當中有一個原則,只要是提交過的內容幾乎都是可以找回的,而沒有提交的內容丟失之後就很難找回了,因此對於這種改變沒有提交內容的命令,我們一定要小心。

最後我們來看下效果,我們checkout之後,第五篇文章當中的改動真的消失了。不僅是從暫存區消失了,就連檔案本身當中的改動也不見了。

到這裡我們常見的幾種需要撤銷改動的場景以及對應的方法就逗介紹完了,對於新手來說,這些命令應該是非常常用的。雖然其中的一些操作說起來危險,但是隻要我們想清楚了再操作,三思而後行,是可以避免悲劇發生的。而且操作危險的命令我感覺更加提升我們的能力,因為小心謹慎會逼迫你加深理解。

好了,今天的文章就到這裡,衷心祝願大家每天都有所收穫。如果還喜歡今天的內容的話,請來一個三連支援吧~(點贊、關注、轉發

原文連結,求個關注

本文使用 mdnice 排版

- END -

{{uploading-image-146490.png(uploading...)}}

相關文章