Git如何回滾程式碼?
- 2019 年 12 月 31 日
- 筆記
摘要: 多年以後,你面對一個需要回滾的Git倉庫,準會想起這篇部落格。

某一天,用戶跟我回饋,他不能分配任務了。我去看了一下Fundebug捕獲的報錯資訊:

可知,出錯原因是前端發送的請求參數有問題。這個悲傷的故事是這樣的:後端同時修改了多個介面,但是前端沒有及時修改對應的介面調用。
這個問題不難解決,回滾程式碼就好了,但是,Git如何回滾程式碼呢?我花了點時間研究了一下。
測試倉庫:Fundebug/git-rollback
我寫了一個非常簡單的測試倉庫,master分支只有3個commit,每個commit只是添加一個文件,因此一共有3個文件:01.txt, 02.txt, 03.txt。
git log commit b39476b9c730d312266fe9bc7f63e795f9ba856f Author: kiwenlau <[email protected]> Date: Thu Jan 18 14:58:06 2018 +0800 3個文件 commit 3821210392184432de18b596cee58ab7924e39f9 Author: kiwenlau <[email protected]> Date: Thu Jan 18 14:57:38 2018 +0800 2個文件 commit 55d3012564e94a39f6686c0e532c0459ddc41ec4 Author: kiwenlau <[email protected]> Date: Thu Jan 18 14:56:41 2018 +0800 1個文件
本文介紹的所有回滾程式碼的命令,都會在一個新的分支執行,方便大家理解:
示例 |
分支 |
說明 |
命令 |
---|---|---|---|
1 |
test01 |
撤銷最近1次commit |
git revert HEAD |
2 |
test02 |
撤銷某個commit |
git revert 3821210392184432de18b596cee58ab7924e39f9 |
3 |
test03 |
撤銷多個連續commit |
git revert b39476b9c730d312266fe9bc7f63e795f9ba856f 3821210392184432de18b596cee58ab7924e39f9 |
4 |
test04 |
撤銷多個非連續commit |
git revert b39476b9c730d312266fe9bc7f63e795f9ba856f 3821210392184432de18b596cee58ab7924e39f9 |
5 |
test05 |
重置為某個commit(不保存程式碼) |
git reset –hard 55d3012564e94a39f6686c0e532c0459ddc41ec4 |
6 |
test6 |
重置為某個commit(保存程式碼) |
git reset –soft 55d3012564e94a39f6686c0e532c0459ddc41ec4 |
git revert : 撤銷特定commit
Git的每一個commit都對應著某些程式碼改動,那萬一改錯了呢?這時可以使用git reset來撤銷某一次commit的改動。所謂撤銷,就是把修改了的程式碼再改回來。
示例1
最簡單的一個場景,就是撤銷最近的1次commit:
git revert HEAD
最近1次commit是新增03.txt,撤銷這個commit之後,test01分支就只剩下2個文件了:01.txt, 02.txt。
示例2
有時,可能需要撤銷某個特定commit,比如,當我需要撤銷第2個commit時,指定對應ID即可:
git revert 3821210392184432de18b596cee58ab7924e39f9
最近1次commit是新增02.txt,撤銷這個commit之後,test02分支就只剩下2個文件了:01.txt, 03.txt。
由這個示例可知,使用git revert撤銷commit時,僅僅針對所撤銷的commit,與任何其他commit無關。
示例3
假設我們再做某個功能時,進行了多次commit,需要全部撤銷。我們當然可以一個個commit依次revert,這樣比較麻煩,其實可以一次性搞定:
git revert b39476b9c730d312266fe9bc7f63e795f9ba856f 3821210392184432de18b596cee58ab7924e39f9
撤銷了後面2個commit,test03分支就只剩下1個文件了:01.txt。
示例4
示例3中所撤銷的2個commit是連續的,其實,因為revert操作只與單個commit相關,我們也可以撤銷多個非連續的commit:
git revert b39476b9c730d312266fe9bc7f63e795f9ba856f 55d3012564e94a39f6686c0e532c0459ddc41ec4
撤銷了第1個和第3個commit,test04分支就只剩下1個文件了:02.txt。
git reset:重置為特定commit
示例5
在示例3中,撤銷了兩個連續的commit,這樣做等價於將程式碼重置為第1個commit的狀態:僅有01.txt這1個文件。使用git revert命令有些麻煩,我們可以直接使用git reset命令來實現:
git reset --hard 55d3012564e94a39f6686c0e532c0459ddc41ec4
將倉庫強制重置為第1個commit,這樣test05分支就只剩下1個文件了:01.txt。git reset –hard與git revert效果看起來一樣,但是不同點在於,前者直接刪除了後面2個commit及其程式碼,沒有保存commi歷史,因此這個操作是不可逆的!使用時應該特別小心。
如果你的本地倉庫與遠程倉庫在reset之前是同步過的,reset之後,兩者的commit不一致,本地倉庫的commit落後與遠程倉庫,這樣會導致push失敗:
git push To [email protected]:Fundebug/git-rollback.git ! [rejected] test05 -> test05 (non-fast-forward) error: failed to push some refs to '[email protected]:Fundebug/git-rollback.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
這是需要使用–force選項,這樣遠程倉庫會被強制覆蓋:
git push --force
示例6
reset時使用–hard選項是一個很危險的操作,因為它把commit以及程式碼全刪了,沒法恢復。如果你只希望刪除commit,而保留修改過的程式碼的話,可以使用–soft選項。
git reset --soft 55d3012564e94a39f6686c0e532c0459ddc41ec4
這時,後面2個commit也被刪除了,當前commit為第1個commit。但是,02.txt與03.txt並沒有被刪除。
git status On branch test06 Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: 02.txt new file: 03.txt
這就意味著,當你的commit的程式碼有一些小問題時,可以重置commit,修改一下程式碼,如何重新commit即可。
參考
版權聲明
轉載時請註明作者 Fundebug以及本文地址: https://blog.fundebug.com/2018/01/24/git-rollback-tutorial/