起因
看到一則新聞赊级,美國(guó)某程序員槍擊同事案件亮航,很多網(wǎng)友猜測(cè)出了各種激怒碼農(nóng)同事的辦法
9月19日,一名程序員在美國(guó)某辦公樓向4名同事開(kāi)槍?zhuān)瑢?dǎo)致一人情況危機(jī)济丘,兩人傷情嚴(yán)重卦睹,一人被子彈擦傷畦戒。目前,兇手已死结序,身份被警方查明障斋。
目前,碼農(nóng)持槍殺人的動(dòng)機(jī)仍然是個(gè)謎。有人猜測(cè)道:“同事不寫(xiě)注釋?zhuān)蛔裱劮迕罚ㄌ?hào)換行邀层,最主要還天天 git push -f 等因素” 激怒了這名行兇者。
正常的流程是要在自己的本地解決掉所有的 merge conflict 之后才能 push 到 remote 的遂庄。魯莽的 push -f 確實(shí)很容易激怒別人寥院,同時(shí)也會(huì)很大風(fēng)險(xiǎn)把別人有價(jià)值的 commit 都覆蓋清空了。
push -f 自然是能不用就不用涛目,但也有一種清空是整個(gè)team決定要清一些 commit 把 master 分支回退到某個(gè)點(diǎn)上去秸谢,自然就想到了 push -f 會(huì)是一種非常便捷的做法了。那能不能更優(yōu)雅的去實(shí)現(xiàn)我們的回退操作呢霹肝,因?yàn)樽罴褜?shí)踐原則上 git 歷史記錄不應(yīng)該被覆蓋的估蹄。
解決辦法
直接在 stackoverflow 就能找到答案
https://stackoverflow.com/questions/1463340/how-to-revert-multiple-git-commits
當(dāng)前的情況如下圖:我想去掉 B,C,D 這三個(gè) commit,把 F 作為新的 master HEAD
A -> B -> C -> D (HEAD)
\
E --------> F
不覆蓋歷史記錄沫换,最終的效果應(yīng)該如下臭蚁,會(huì)用 commit G revert 代碼到和 A 一樣狀態(tài),然后把 F merge 回 master
A -> B -> C -> D -> G -> H (HEAD)
\ /
E ----------------> F
第一種方法:一步步的 revert
$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
當(dāng)要 revert 的 commit 數(shù)量很多的時(shí)候會(huì)很麻煩讯赏。
第二種方法:revert 一個(gè)區(qū)間的所有 commit
$ git revert --no-commit A..HEAD
第三種方法:使用 reset垮兑,這個(gè)屬于比較 “奧秘” 的用法
$ git reset --hard A
$ git reset --soft D # ( or ORIG_HEAD, or @{1} )
(or) $ git reset --mixed D
實(shí)踐對(duì)比
準(zhǔn)備了一個(gè)樣板模擬場(chǎng)景,我們想要把 master 分支的代碼回滾到 init base 那里漱挎,然后 merge fix-branch-A 的代碼成為 master 新的 HEAD
Let's git push -f (⊙⊙!)
首先是最初的 git log
然后我們可以直接 reset 到 init base 然后 push -f
$ git reset --hard d194ece
$ git push -f
最終效果就是 version 2 和 version 3 都消失了
大家不要慌系枪,其實(shí)這種破壞性的操作之后,仍然有“后悔藥”可以吃的磕谅,可以把丟失的 commit 搶救回來(lái)嗤无。
$ git reflog show --all
使用 git reflof 記錄了所有的操作,可以查看到我們之前是 ‘moving from b7e4fcc to d194ece’
$ git reset --hard b7e4fcc
這樣就可以找回遺失的 commit
Let's gracefully revert back
又準(zhǔn)備了一個(gè)干凈的模板
使用 revert 或者 reset 的方式生成一個(gè) rollback commit
然后 merge fix-branch-A
最終的 git 歷史記錄里面仍然會(huì)保留所有我們廢棄掉的 commit怜庸,更加優(yōu)雅。