Git提交錯(cuò)了不用慌,這三招幫你修改記錄
大家好,今天我們來(lái)聊聊git當(dāng)中一個(gè)很重要的功能——歷史記錄的修改。
有的時(shí)候我們會(huì)突然發(fā)現(xiàn)某個(gè)地方需要修改,最常見(jiàn)的某個(gè)不應(yīng)該被提交的文件被提交了進(jìn)來(lái)。我們希望它不只是在后續(xù)的版本當(dāng)中不再出現(xiàn),而是希望整個(gè)從git倉(cāng)庫(kù)當(dāng)中移除掉。這個(gè)時(shí)候我們就需要修改git之前的歷史記錄。這個(gè)時(shí)候應(yīng)該怎么辦呢?
不要著急,git當(dāng)中有很多的手段可以修改之前的歷史提交記錄。
修改最后一次提交
這一點(diǎn)我們?cè)谥暗奈恼庐?dāng)中曾經(jīng)提到過(guò),如果我們只是想要修改最后一次的提交記錄,這是比較簡(jiǎn)單的。我們只需要直接修改我們想要修改的部分,在提交的時(shí)候加上一個(gè)參數(shù)--amend即可。
- git commit --amend
amend的意思是補(bǔ)丁,它可以把我們這一次的修改合并到上一條歷史記錄當(dāng)中,而不會(huì)產(chǎn)生一個(gè)新的commit記錄。運(yùn)行之后,它會(huì)打開(kāi)一個(gè)vim編輯器,我們還可以修改上一次commit時(shí)輸入的提示信息。
我們使用git log檢查的話,會(huì)發(fā)現(xiàn)歷史記錄的修改時(shí)間還是上一次的時(shí)間??雌饋?lái)就好像什么也沒(méi)有發(fā)生過(guò)一樣,悄無(wú)聲息地就改掉了。
修改多個(gè)信息
--amend雖然好用,但是它只能修改最后一次的提交信息,如果我們想要修改的提交記錄在那之前,我們應(yīng)該怎么辦呢?
git當(dāng)中并沒(méi)有提供直接的工具來(lái)實(shí)現(xiàn)這一點(diǎn),不過(guò)我們可以使用rebase來(lái)達(dá)成。我們可以加上-i進(jìn)行交互式地變基,我們可以在任何想要的修改完成之后停止,也可以添加文件或者是做其他想要做的事情。但是我們變基的目標(biāo)不是某一個(gè)分支而是當(dāng)前分支的某一個(gè)歷史節(jié)點(diǎn),所以我們需要提供一個(gè)具體的commitid或者是指針位置。
git rebase -i的功能非常強(qiáng)大,我們幾乎可以使用它來(lái)完成所有一切我們想要完成的事情。
比如我們想要修改倒數(shù)第二次提交,我們可以執(zhí)行g(shù)it rebase -i HEAD~3。也就是以倒數(shù)第三個(gè)節(jié)點(diǎn)作為基準(zhǔn)節(jié)點(diǎn)執(zhí)行變基,這時(shí)候git會(huì)進(jìn)入一個(gè)vim窗口,在這個(gè)窗口當(dāng)中我們可以看到最近的三次提交記錄。
首先我們可以看到上面的三行就是我們可以修改的三個(gè)commit,分別展示的是要執(zhí)行的操作以及commitid以及commit message。這里的操作默認(rèn)的是pick,也就是使用該commit。關(guān)于我們可以執(zhí)行的操作git在下方也給了充分的提示,其中比較常用的有pick、edit以及squash。
這一次我們想要做的是修改提交記錄,所以我們應(yīng)該執(zhí)行edit,我們把想要修改的commit前的pick改成edit。比如這樣:
退出之后,git會(huì)自動(dòng)帶我們回到我們選擇edit的分支提交之后的版本。我們進(jìn)行我們想要的修改,這里我在第15篇文章當(dāng)中加上了一行:嘗試rebase。之后再使用git add以及git commit --amend進(jìn)行修改提交結(jié)果。
再之后我們執(zhí)行g(shù)it rebase --continue,把剩下要應(yīng)用的變更應(yīng)用完成。
一切都結(jié)束之后,我們可以使用一下git show命令查看一下我們修改的bee9ce3這個(gè)commit的記錄??梢钥吹揭呀?jīng)多了這一行,說(shuō)明我們的修改成功了。
順序變更、合并、拆分
順序變更
我們不僅可以修改某一次commit當(dāng)中的內(nèi)容,還可以修改這些commit的相對(duì)順序,以及可以讓它們合并以及拆分。
修改順序其實(shí)很簡(jiǎn)單,我們只需要人為地修改rebase -i之后彈出的vim文件即可。比如說(shuō)原本的記錄是:
- pick A change A
- pick B change B
- pick C change C
如果我們想要更換順序,我們只需要修改這個(gè)文件即可。比如變成:
- pick B change B
- pick A change A
- pick C change C
那么當(dāng)我們?cè)谕顺鰒im的時(shí)候,git會(huì)首先應(yīng)用B commit的變更,再應(yīng)用A最后應(yīng)用C。
合并
除此之外,我們還可以合并多個(gè)commit記錄成一個(gè)。操作的方法也很簡(jiǎn)單,就是我們只需要把pick修改成squash。git會(huì)自動(dòng)把所有squash的commit記錄合并在一起。
- pick A change A
- squash B change B
- squash C change
拆分
有的時(shí)候一個(gè)commit非常巨大,我們可能也會(huì)想要將它拆分,其實(shí)操作也很簡(jiǎn)單。比如我們想要把commit B拆分成兩條,首先,我們?cè)趓ebase的時(shí)候?qū)ommit B前面的pick修改成edit。
- pick A change A
- edit B change B
- pick C change C
當(dāng)我們退出的時(shí)候,我們會(huì)進(jìn)入到B commit剛剛提交完的狀態(tài)。由于我們要做的是拆分B這個(gè)提交,所以我們需要執(zhí)行g(shù)it reset HEAD^,把上一次提交重置。然后再分別add我們想要拆分開(kāi)來(lái)提交的文件。
整個(gè)操作如下:
- git reset HEAD^
- git add test/*
- git ci -m 'add test'
- git add code/*
- git ci -m 'update code'
- git rebase --continue
這樣我們就把commit B拆分成了兩個(gè)commit插入到了歷史記錄當(dāng)中了。
最后的最后,大家需要注意,雖然這些手段在修改記錄的時(shí)候非常好用。但是如果這些commit已經(jīng)被提交到了遠(yuǎn)程,我們是不可以直接git push同步的。因?yàn)間it會(huì)校驗(yàn)我們提交的hash值,發(fā)現(xiàn)對(duì)不上之后會(huì)禁止我們的提交。所以如果想要提交到遠(yuǎn)程的話,只能使用git push -f強(qiáng)制覆蓋。但是這是一個(gè)非常非常危險(xiǎn)的操作,如果你git push -f了,沒(méi)有人會(huì)知道你到底修改了什么,只建議在自己獨(dú)有的分支上如此操作,一定一定要謹(jǐn)慎使用。
本文轉(zhuǎn)載自微信公眾號(hào)「TechFlow」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系TechFlow公眾號(hào)。