[譯] 修改 Git 錯誤的高明方法
在軟體開發的世界,有 無窮無盡 的方法能夠把事情搞得一團糟:錯刪東西,程式碼混亂,提交資訊寫錯了字,這些都僅僅是冰山一角。
幸運的是,當我們使用版本控制時,Git 提供給我們了一個很完美的安全網。當然啦,不是咱倆需要它,因為我們從來不犯錯的,對吧?嗯嗯當然當然。但是為了他人的利益,我們還是一起來看看那些可以拯救我們的 Git “撤回”工具。
修改最後提交
搞砸一次提交非常容易。經典的場景包括:提交資訊裡寫了錯字。其他的?還有忘記將修改新增到臨時區(staging area)。還有很多時候,我們忽然意識到程式碼中有錯誤 —— 但是當然是在點選了提交的確認鍵之後。
幸運的是,Git 讓修改最後一次提交這件事出乎意料的簡單。假如我們剛剛確認了下面這個命令:
git commit -m "Massage full of typohs" 複製程式碼
並且(好像這個拼寫錯誤還沒那麼糟糕)假如我們還忘記了新增某個已經修改的檔案到臨時區。我們可以使用如下兩行命令修正這兩個錯誤:
git add forgotten-changes.js git commit --amend -m "A sensible message" 複製程式碼
神奇之處就在於 --amend
標識:當我們跟著 commit 命令使用它的時候,Git 將會修改最後一次提交 —— 新增臨時區的修改,並替換為新的說明資訊。
但是有一點需要提示:只能在沒有推送到遠端倉庫的提交上使用 --amend
。原因是 Git 會用修改了的版本 取代原來的 ,有錯誤的提交。這之後,看上去就像是原來的提交從來沒有過。是的,這種方式用來處理錯誤很好,但是必須是當我們還沒有將過這個錯誤 釋出 到遠端倉庫的時候。
撤銷本地修改
每個人都有類似的經歷:用了一早晨的時間尋找解決辦法,但是最後只好承認這幾個小時就是在浪費時間。必須從頭開始了,並且要撤銷大部分(或者所有)的程式碼。
但是這其實是使用 Git 的初衷之一 —— 它能讓你不用害怕破壞了什麼,而可以隨意的嘗試不同的方法。
讓我們來看一個例子:
git status modified: about.html deleted:imprint.html modified: index.html 複製程式碼
現在我們假設,這些修改就是在前文說的浪費時間的場景。我們需要撤銷 about.html 的修改並且恢復已經刪除的 imprint.html。我們現在想要的就是, 丟棄 這些檔案當前的更改 —— 但是保留 index.html 中的超讚的已經寫好的程式碼。這時, git checkout
命令就能夠有所幫助。但是,我們需要像這樣指明是哪些檔案:
git checkout HEAD about.html imprint.html 複製程式碼
這行命令將 about.html 和 imprint.html 恢復到了最後提交的狀態。哎,我們可以不用熬夜來撤銷它們了!
我們可以更進一步,可以在一個修改過的檔案裡 僅丟棄特定幾行程式碼 ,而不是恢復整個檔案!我必須承認,在命令列完成這項任務比較複雜,但使用 像 Tower 這樣的 Git 桌面客戶端 則是一個很好的方法:

在程式碼 真的 糟透了的時候,我們就想掏出一把大槍:
git reset --hard HEAD 複製程式碼
這次我們不是僅僅使用 checkout
恢復 指定的 檔案,而是重置了 所有修改過的副本 。換句話說, reset
將所有專案檔案恢復到了最後一次提交的狀態。和 --amend
類似,使用 checkout
和 reset
的時候需要牢記:使用這些命令丟棄的本地修改無法恢復!它們還從來沒有被提交到倉庫中,所以不能被恢復也是合理的。請確認你真的想要刪除它們,因為刪除了就沒法找回了!
撤銷並還原更早的提交
很多情況下,我們一段時間後才意識到程式碼的錯誤,而它已經被提交到倉庫裡很久了。

我們如何才能刪除掉這個錯誤的提交呢?答案是在大多數場景下,我們其實不應該這樣做。就算是“撤銷”內容的時候,通常情況下 Git 並沒有真的刪除資料。它 通過新增新的資料來修正內容 。用這個例子,我們來看看它是如何工作的:
git revert 2b504bee 複製程式碼
通過對這個提交執行 git revert
,我們並沒有刪除任何東西。相反的是:

Git 自動建立了一個 新的 提交來 撤銷 錯誤提交所造成的修改。所以,如果我們一開始有三個提交,然後試圖修正中間的那個,那麼我們就會有四個提交了,新增的那個用來修改 revert
的目標提交。
恢復專案之前的版本
另一個情境是我們希望恢復到專案之前的版本。我們不是僅僅撤銷提交歷史中的一個特定的版本,而是想讓時間倒流,直接退回到這個版本。
在下面的場景中,我們宣告“C2”之後的所有提交都是 不需要的 。我們想要回到“C2”這次提交的狀態,它之後的提交統統刪除:

根據我們已經講述過的內容,我想你已經(至少部分)熟悉了所需的命令:
git reset --hard 2b504bee 複製程式碼
這個命令通知了 git reset
我們想要返回的提交的 SHA-1 雜湊值。C3 和 C4 提交將會從專案歷史中消失。 如果你在使用 Git 客戶端,例如 Tower,提交專案的右鍵選單中的 git revert
和 git reset
兩者都可以使用:

刪除提交,恢復刪除的分支,處理衝突等等
當然,軟體專案中還有很多其他會把事情搞砸的方式。但是幸運的是,Git 提供了很多工具來撤銷錯誤。
如果你想要學習本篇文章提到的場景中的更多的內容,或者其他題目,例如如何在分支之間移動提交,刪除舊提交,恢復刪除的分支,或者優雅的處理衝突,看一下專案"Git 急救包",它是我和其他一些 Tower 團隊的人建立的。這是一份完全免費的教程,包括了 17 個視訊以及一份很方便的備忘單,你可以下載並儲存到你的裝置上。

同時,祝你撤銷得愉快!
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為掘金 上的英文分享文章。內容覆蓋 Android 、 iOS 、 前端 、 後端 、 區塊鏈 、 產品 、 設計 、 人工智慧 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃 、官方微博、 知乎專欄 。