git:rebase的原理
前提:
- 在最近的項目中,我碰到這樣一個情況:第一版app上線之后,團隊緊接着進行第二版本的開發,由於團隊成員對git使用不熟悉,所以開發的每一次提交都是往遠端master分支上提交。
- 第一版本打包上線之后,我想讓后續的開發中master分支保持代碼高可用性,於是在遠端建立新的分支
second_version
用於第二版本的開發,到時候再合並到master分支上,奈何有的團隊成員不會提交遠程其他分支,導致master被污染(如下圖)
由於團隊成員對git的熟練程度不同,有的使用可視化工具提交,有的使用命令行(比如我),當使用merge的時候會出現如上圖所示的問題,點線圖錯綜復雜,原因是在merge時會將本地的提交與拉取的提交融合成新的提交,也就是如圖所示的Merge remote-tracking branch...
,並且會將所有的提交顯示在點線圖上,十分混亂。但是使用rebase的時候,點線圖則會很優雅:
點線圖是一條直線。網上有很多關於rebase和merge的區別解釋,以下分享的是我自己對rebase的觀點,希望可以幫助大家理解。
rebase原理
首先大家在開發過程中肯定會經常碰到這樣的情況:當你執行git push
時出現錯誤信息:
這是因為跟你當前分支相關聯的遠端分支上已經有別人提交了新的代碼,或者說你想push的commit的基點已經變更(后面會說明什么是基點)。
-
問題引出:這里涉及到本地分支與遠端分支關聯的問題,使用
git branch -vv
查看關聯關系:
本地master默認與origin/master相關聯,當你執行git push
或git push origin master
時,其完整命令是git push origin master:master
,前一個master
是你本地的master,后一個master
是遠端master。所以如果沒有特別指定,無論你在本地的哪個分支,git push
命令都只會將你本地master分支上的代碼進行提交。當你在本地新建其他分支git checkout -b test
,默認是不會與遠程分支相關聯的。所以當你在該分支上進行git push
時會有如下問題出現
根據提示,使用git push --set-upstream origin test
可以與遠端分支test進行關聯,這里的test要換成自己的分支名。
回到正題
rebase,故名思意re-base,重新定義基點,當你的代碼push不上去的時候,你可以使用git pull -r
或是git pull --rebase
拉取並合並遠端分支,然后執行git status
查看是否出現沖突,以下是沖突情況:
紅框字的翻譯大致是:以'1f618a1'為基點重新定義分支master。1f618a1可以看作是每一次提交的唯一標識碼。
我將以下圖來講述rebase的原理:
不同的字母分別代表不同的提交,圖中從左到右分別以時間從小到大進行排列。每個commit都以前一個commit作為基點進行開發,例如D是以C為基點進行開發。當我開發完D后,准備push到遠端master時,git會進行檢查:遠端master的最新節點是否是節點D的基點,即檢查遠端master的基點是否是節點C,如果是,則可以直接push,如果不是,也就是上圖的情況:在你push之前遠端master已經被他人提交了E和F節點,這時可以執行git pull -r
git會以F節點作為新的基點,與D節點的代碼進行融合,如果此時出現沖突,那么你就會被移到臨時解沖突的分支,需要人工解沖突,解完后執行git add -A
保存操作,再執行git rebase --continue
繼續后續操作,你可能會遺漏某一處沖突,這個完全不同擔心,git rebase --continue
會幫你檢查是否解決完成,如果沒有完成則不會讓你回到正常分支。
下圖是沖突解決完且順利執行git rebase --continue
的情況:
可以看到,此時我再執行git push
,就可以順利將D節點提交到遠端master上去了:
可以看到,遠端master保持了一條直線,讓人看起來非常舒服,這就是rebase的好處,而不像文章開頭使用merge那樣雜亂、讓人迷惑。