原文:https://blog.csdn.net/azureternite/article/details/76154807
情景
有的時(shí)候會(huì)遇到這種問(wèn)題,比如說(shuō)有兩個(gè)人,在同一個(gè)分支進(jìn)行開(kāi)發(fā),假設(shè)是我自己,跟我的同伴;現(xiàn)在,我寫(xiě)了一部分代碼,準(zhǔn)備push到遠(yuǎn)程了,于是我執(zhí)行g(shù)it add、git commit,一切ok,沒(méi)問(wèn)題,然后git push,這下問(wèn)題來(lái)了,git告訴我說(shuō)我的push被rejected了,原來(lái),我的同伴在我執(zhí)行push之前,已經(jīng)push了若干個(gè)commit到遠(yuǎn)程,因此我不能直接push,而是需要先把他的commits拉到我本地的repo才行。git的提示如下圖。

好,git的提示已經(jīng)很清楚了,rejected的原因通常是遠(yuǎn)程有了另外的push,詢(xún)問(wèn)了同伴,我們知道,就是ta先進(jìn)行了push。那么,根據(jù)git的提示,我們可能想要先把遠(yuǎn)程的改變進(jìn)行整合,再來(lái)push。那怎么整合呢,rejected那行告訴我們,要“fetch first”,而下面的e.g.說(shuō),我們可以用git pull來(lái)整合。也就是說(shuō),我們可以用git fetch,也可以用git pull來(lái)整合遠(yuǎn)程的改變到我們本地倉(cāng)庫(kù)中。
由于我本人對(duì)fetch不太了解,看著pull好像跟push是反義詞比較親切,那就用它吧。于是我執(zhí)行了git pull,然后git push。emmmm,好像沒(méi)什么問(wèn)題,但是…在source tree里面看著分支的圖譜怎么怪怪的?

圖譜里面顯示,我提交了兩個(gè)commit,但實(shí)際上我改動(dòng)的地方只進(jìn)行了一次提交。我們看看多出來(lái)的commit的描述,寫(xiě)著“Merge branch ‘master’ of github.com:ChuChencheng/test”。
嗯?意思是這個(gè)提交做的改動(dòng)是把遠(yuǎn)端的master分支進(jìn)行合并。
Google了一番git pull,發(fā)現(xiàn)git pull做的事情其實(shí)相當(dāng)于git fetch跟git merge,那,我之前一直沒(méi)用到的git fetch做的事情是什么呢?
git fetch這個(gè)命令會(huì)把遠(yuǎn)程的commits拉取到本地的repo中,但是,它不是直接把commits接在分支的最后面,而是從你最后一次push的那個(gè)commit節(jié)點(diǎn),再拉取一個(gè)新的分支出來(lái),類(lèi)似這樣:
????????* git fetch拉下來(lái)的節(jié)點(diǎn),建立在一個(gè)新的分支上
*? ?/? 你還沒(méi)push的節(jié)點(diǎn)
|/
* 你最后一次push的節(jié)點(diǎn)
|
*
那merge呢?git pull在拉取完之后,就會(huì)將新建的分支跟你原來(lái)的分支進(jìn)行合并,所以圖就變成了這樣:
*? 新建的分支merge進(jìn)原本的分支,這個(gè)節(jié)點(diǎn)就是merge xxx那個(gè)多出來(lái)的節(jié)點(diǎn)| \|? * git fetch拉下來(lái)的節(jié)點(diǎn),建立在一個(gè)新的分支上* /? 你還沒(méi)push的節(jié)點(diǎn)|/* 你最后一次push的節(jié)點(diǎn)|*
* 新建的分支merge進(jìn)原本的分支,這個(gè)節(jié)點(diǎn)就是merge xxx那個(gè)多出來(lái)的節(jié)點(diǎn)
| \
|? ? ?* git fetch拉下來(lái)的節(jié)點(diǎn),建立在一個(gè)新的分支上
*? ?/ 你還沒(méi)push的節(jié)點(diǎn)
|/
* 你最后一次push的節(jié)點(diǎn)
|
*
現(xiàn)在,我們知道了,這種情況下執(zhí)行g(shù)it pull,分支的圖譜就會(huì)變得很難看,但又必須把遠(yuǎn)程的commits拉取下來(lái),那有沒(méi)有辦法讓分支圖譜保持一條直線而不分叉呢?
這個(gè)時(shí)候,我們還需要一個(gè)以前也很少用(我真的很菜)的命令,git rebase。
git rebase的作用是,把一個(gè)分支的修改合并到另一個(gè)分支。聽(tīng)起來(lái)有點(diǎn)熟悉?沒(méi)錯(cuò),它跟merge的功能有點(diǎn)像。不同的是,merge的做法比較粗暴,直接把兩個(gè)分支再各自拉出一條線,連在一起就完了;而rebase則比較細(xì)心,它會(huì)把當(dāng)前分支跟你要合并的分支中不同的commits取消掉,臨時(shí)保存起來(lái),然后在要合并的分支中再把保存起來(lái)的commits patch上去,變成新的commits,當(dāng)然,commitId也是新的,這樣,最后的效果就是只剩合并后的分支,而且是一條直線,沒(méi)有分叉,沒(méi)有“Merge branch xxx of xxx”這種多余的提交。

知道了是什么,為什么,最后就是怎么做了。
步驟如下:
git fetch
git rebase
解決沖突
git add 沖突文件
git rebase –continue
git push
其中,3、4、5點(diǎn),如果沒(méi)遇到?jīng)_突就不用進(jìn)行,直接push上去。
當(dāng)遇到?jīng)_突時(shí),git會(huì)提示patch failed,并要我們解決問(wèn)題了再執(zhí)行g(shù)it rebase --continue

此時(shí)的圖譜:

解決沖突后,通過(guò)git status可以看到rebase in progress,也就是說(shuō)現(xiàn)在還是在rebase的過(guò)程中:

然后我們把解決后的沖突文件add進(jìn)來(lái),并執(zhí)行g(shù)it rebase --continue繼續(xù)patch(也可以執(zhí)行–skip跳過(guò)這個(gè)patch,或–abort放棄rebase),可以看到分支是清晰的一條直線:

最后push,完成。