軟件開發,無論經驗多豐富,都難免出錯。但優秀程序員與普通程序員的區別在於,他們知道如何撤銷錯誤!
如果你使用 Git 作為版本控制系統,那麼你已經擁有了一套強大的“撤銷工具”。本文將向你展示五種強大的 Git 撤銷錯誤的方法!
git restore
命令完成,該命令會將文件重置為其最後一次提交的狀態。為了更精細的控制,可以使用 -p
標誌在補丁級別丟棄更改。 git log
命令可用於將特定文件恢復到特定版本。用戶可以識別文件損壞的“錯誤提交”,然後使用 git checkout
命令將文件恢復到錯誤提交之前的版本。 Reflog
工具可用於恢復丟失的版本或已刪除的分支。 Reflog
記錄本地存儲庫中所有 HEAD 指針的移動,允許用戶返回到以前的狀態並恢復丟失的數據。 git cherry-pick
命令將提交移動到不同的分支。如果提交到錯誤的分支,用戶可以檢出正確的分支,將提交移動過去,然後使用 git reset
從原始分支中刪除不需要的提交。 編碼過程通常很混亂。有時,感覺像是兩步前進,一步後退。換句話說:你編寫的一些代碼很棒……但有些則不然。這就是 Git 可以幫助你的地方:它允許你保留好的部分,並丟棄不再需要的更改。
讓我們來看一個包含一些“本地”更改(即尚未提交的更改)的示例場景。
注意:為了更好的概述和更清晰的可視化,我在一些屏幕截圖中使用了 Tower Git 桌面客戶端。你不需要 Tower 就可以學習本教程。
讓我們先解決 general.css
中的問題。我們所做的更改完全朝著錯誤的方向發展。讓我們撤銷所有更改,並重新創建該文件的最後一次提交狀態:
$ git restore css/general.css
請注意,或者,我也可以使用 git checkout
命令來達到相同的結果。但是因為 git checkout
有很多不同的用途和含義,所以我更傾向於使用稍微更新一些的 git restore
命令(它只專注於這些類型的任務)。
我們在 index.html
中的第二個問題有點棘手。我們在這個文件中做的一些更改實際上是很好的,而只有一部分需要撤銷。
同樣,git restore
命令可以解決問題——但這次要使用 -p
標誌,因為我們要深入到“補丁”級別:
$ git restore css/general.css
然後,Git 會引導你,並詢問你——對於該文件中的每一塊更改——你是否要丟棄它。
你會注意到,我對第一塊更改輸入了“n”(為了保留它),對第二塊更改輸入了“y”(為了丟棄它)。該過程完成後,你會看到只有第一塊有價值的更改保留了下來——就像我們想要的那樣!
有時,你可能想要將特定文件恢復到特定版本。例如,你知道 index.html
在之前的某個時間點工作正常,但現在不行了。這時你想要倒退時間,但只針對這個特定文件,而不是整個項目!
我們首先需要找出我們想要恢復的哪個確切版本。使用正確的參數集,你可以讓 git log
命令顯示你單個文件的歷史記錄:
$ git restore -p index.html
這只會顯示 index.html
被更改的提交,這對於查找導致問題出現的“壞蘋果”版本非常有用。
如果你需要更多信息,並想要查看這些提交的內容,你可以讓 Git 使用 -p
標誌顯示這些提交中的實際更改:
$ git log -- index.html
一旦我們找到了導致我們可愛的小文件損壞的錯誤提交,我們就可以繼續修復錯誤了。我們將通過恢復錯誤提交之前版本的該文件來做到這一點!這很重要:我們不想恢復引入錯誤的提交中的文件,而是恢復最後一個良好狀態——該提交之前的那個提交!
$ git log -p -- index.html
將 ~1
附加到錯誤提交的哈希值將指示 Git 執行以下操作:轉到引用的提交之前的一個版本。
執行該命令後,你會發現 index.html
在你的本地工作副本中被修改了:Git 為我們恢復了該文件的最後一個良好版本!
Git 急救包中的另一個強大的撤銷工具是“Reflog”。你可以把它想像成一個日誌,Git 在其中記錄本地存儲庫中發生的所有 HEAD 指針移動——例如提交、檢出、合併和變基、cherry-pick 和重置。所有更重要的操作都會在這裡被很好地記錄下來!
當然,這樣的日誌非常適合那些事情進展不順利的情況。因此,讓我們先製造一個小災難——然後我們可以用 Reflog 來修復它。
假設你確信你最近的幾次提交都不好:你想擺脫它們,因此使用了 git reset
來返回到之前的版本。結果,“錯誤”提交從你的提交歷史中消失了——正如你想要的那樣。
但正如生活有時那樣,你注意到這是一個壞主意:最終,這些提交並沒有那麼糟糕!但壞消息是,你剛剛將它們從你的存儲庫的提交歷史中刪除了! ?
這是 Git 的 Reflog 工具的經典案例!讓我們看看它如何拯救你:
$ git restore css/general.css
讓我們逐一分解:
git reflog
就足夠了。 為了恢復此先前狀態,我們可以再次使用 git reset
,或者簡單地創建一個新分支:
$ git restore -p index.html
正如我們可以高興地驗證的那樣,我們的新分支包含了我們認為通過意外的 git reset
故障而丟失的提交!
Reflog 也可在其他情況下派上用場。例如,當你無意中刪除了一個你真的不應該刪除的分支時。讓我們來看一下我們的示例場景:
$ git log -- index.html
讓我們假設我們的客戶/團隊負責人/項目經理告訴我們,我們一直在開發的漂亮的分析功能不再需要了。我們井井有條,當然會刪除相應的 feature/analytics
分支!
上面你可以看到,在我們的示例場景中,我們當前檢出了該分支:feature/analytics
是我們當前的 HEAD 分支。為了能夠刪除它,我們必須首先切換到另一個分支:
$ git restore css/general.css
Git 告訴我們我們即將做一些非常嚴重的事情:由於 feature/analytics
包含在其他地方不存在的唯一提交,因此刪除它將破壞一些(可能是有價值的)數據。好吧……既然不再需要該功能,我們可以繼續:
$ git restore -p index.html
你可能已經預料到接下來會發生什麼:我們的客戶/團隊負責人/項目經理高興地告訴我們,該功能又回來了! ? 他們畢竟想要繼續進行! ?
同樣,我們面臨一個糟糕的情況,我們可能丟失了寶貴的數據!因此,讓我們看看 Reflog 是否可以再次拯救我們:
$ git log -- index.html
如果你仔細觀察,好消息就會顯而易見。在我們(災難性地)能夠刪除我們的分支之前,我們必須執行 git checkout
以切換到其他分支(因為 Git 不允許你刪除當前分支)。當然,此檢出也記錄在 Reflog 中。為了恢復我們已刪除的分支,我們現在可以簡單地將之前的狀態作為新分支的起點:
$ git log -p -- index.html
瞧:我們的分支起死回生了! ???
如果你碰巧使用的是 Tower 等桌面 GUI,撤消此類錯誤通常就像按下 CMD Z 一樣簡單。
最後,讓我們再來看一個“哦,不!”部門的經典案例:在錯誤的分支上提交。
今天,許多團隊都制定了一條規則,禁止直接提交到長期分支,如“main”、“master”或“develop”。通常,新的提交應該只通過合併/變基到達這些分支。然而,我們有時會忘記並直接提交……
讓我們以以下場景為例。
我們應該在 feature/newsletter
上提交,但無意中在 master
分支上觸發了提交。讓我們一步一步地看看解決方案。
首先,我們必須確保這次我們在正確的分支上,所以我們正在檢出 feature/newsletter
:
$ git checkout <bad-commit-hash>~1 -- index.html
現在我們可以使用 cherry-pick
命令安全地將該提交移動過去:
$ git reflog
我們可以查看 feature/newsletter
,將會看到該提交現在也存在於這裡。
到目前為止,一切順利。但是 cherry-pick
沒有從 master
分支(它永遠不應該在那裡)刪除提交。因此,我們也必須在那裡清理我們的爛攤子:
$ git restore css/general.css
我們切換回 master
,然後使用 git reset
從歷史記錄中刪除(這裡)不需要的提交。
最後,一切又恢復正常了——所以你現在可以開始你的快樂舞蹈了! ???
我以前說過,而且不幸的是我們都知道這是真的:我們無法避免錯誤!無論我們多麼優秀的程序員,我們都會不時地搞砸。因此,問題不在於我們是否犯錯,而在於我們如何有效地處理它們並解決問題?
如果你想了解更多關於 Git 撤銷工具的信息,我強烈推薦“Git 急救包”。這是一個(免費的)簡短視頻合集,向你展示如何在 Git 中清理和撤消錯誤。
祝你開發順利,勇於嘗試,當然也要善於修復!
git reset
和 git revert
有什麼區別? git reset
和 git revert
是兩個幫助你撤消 Git 存儲庫中更改的命令,但它們的工作方式不同。 git reset
將你的 HEAD 指針移動到特定的提交。這意味著它實際上“忘記”了你在重置到的提交之後的所有提交。這是一個破壞性操作,應該謹慎使用。另一方面,git revert
創建一個新的提交來撤消特定提交中所做的更改。這是一個安全的操作,因為它不會更改現有歷史記錄。
git add
操作? 如果你已經使用 git add
暫存了更改,並且想要撤消此操作,可以使用 git reset
命令。例如,如果你想要取消暫存特定文件,可以使用命令 git reset <file></file>
。如果你想要取消暫存所有更改,可以使用 git reset
而不指定文件。
git commit
嗎? 是的,你可以使用 git reset
或 git revert
命令撤消 git commit
。 git reset
將你的 HEAD 指針移回到你想要撤消的提交之前的提交,有效地擦除不需要的提交。另一方面,git revert
將創建一個新的提交來撤消不需要的提交中所做的更改。
如果你已經對特定文件進行了更改,並且想要撤消這些更改,可以使用 git checkout
命令。例如,git checkout -- <file></file>
將丟棄指定文件的本地工作目錄中的更改。
git stash
是什麼? git stash
是一個允許你臨時保存你不想立即提交的更改的命令。如果你需要切換到不同的分支,但不想提交當前更改,這將非常有用。你可以稍後使用 git stash apply
應用暫存的更改。
你可以使用 git log
命令查看你的 Git 歷史記錄。這將向你顯示存儲庫中所有提交的列表,以及它們的提交消息。
git push
嗎? 是的,你可以撤消 git push
,但這比撤消本地更改要復雜一些。你需要使用帶有 -f
或 --force
選項的 git push
命令來用你的本地存儲庫覆蓋遠程存儲庫。要小心使用此命令,因為它可能會對正在處理同一存儲庫的其他人員造成問題。
如果你想要撤消多個提交,可以使用 git reset
命令以及 HEAD~<number></number>
語法。例如,git reset HEAD~3
將你的 HEAD 指針移回到三個提交之前。
軟重置將你的 HEAD 指針移動到特定的提交,但不會更改你的工作目錄和暫存區。這意味著你仍然會看到來自“已忘記”提交的更改作為未提交的更改。另一方面,硬重置將丟棄工作目錄和暫存區中的所有更改,有效地將你的存儲庫恢復到指定提交時的狀態。
是的,硬重置後可以恢復提交,但這並不簡單。 Git 會在 reflog 中保留所有 ref 更新(例如移動 HEAD 指針)的日誌。你可以使用 git reflog
命令找到你想要恢復的提交,然後使用 git branch
在該提交處創建一個新分支。
以上是用git撤消錯誤的5種方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!