背景
最近我們組幾個同事都投入到了一個新專案,互相之間的功能耦合比較緊密,因此,是打算從master上新拉一個分支,可以理解為我們幾個人的開發分支,以develop代替。
一開始,我們是打算像svn那樣用的,幾個人就把這個新分支develop當做唯一的主幹分支,幾個人互相快速提交/拉取,回到了用svn的快樂日子。
不過,大家用svn也知道,經常呢,我們為了保證程式碼不丟,會經常性地往分支提交,即使某個功能寫了一半,一個功能,n次commit記錄,且和同事的commit交錯在一起;另外,我們提交的程式碼,有時候會導致同事那裡跑不起來。
簡而言之,就是commit有點碎;另外,可能阻塞其他同事。
我們組長提了另外一種思路,就是,每個人基於這個開發分支develop,再自己單獨拉取一個分支出來,如develop-zhangsan,develop-lisi。每個人在自己的單獨的分支上開發,開發了一個較為完整的功能後,再提一個pull request給develop,此時,可以對這個較完整的功能做程式碼review,review通過後,即合併到develop分支。但此時,怎麼才是最佳實踐呢,且能保證開發分支develop的提交歷史成為優雅的一條線呢?
這裡假設有張三、李四兩個人,基於gitlab、github、gitee等進行開發,最終,主要有以下幾個分支:
遠端 | 本地 |
---|---|
origin/master | master |
origin/develop | develop |
origin/develop-zhangsan | develop-zhangsan |
origin/develop-lisi | develop-lisi |
實戰環境準備
我這邊已經準備好了實戰案例,已經把上面的幾個分支都拉好了。
https://gitee.com/ckl111/git-rebase-test
假設我先在遠端,把這幾個分支先建好,我是在gitee操作的。
目前,zhangsan、lisi分支,是基於develop拉出來的,所以最新提交都是一樣的。
模擬張三開發
大家看上圖,張三來了一頓操作,切到了自己的分支,改了點東西,做了一次提交,不過提交還沒推送到遠端自己的分支。
模擬李四開發
修改、推送
李四也是個猛人啊,上來一頓cv,commit、push一氣呵成。
遠端狀態
此時,可以看到,遠端分支裡,只有lisi這娃兒的分支狀態有變化。此時,按照標準流程,李四需要在遠端發起一個到develop的pull request。
發起pr
此時,是可以檢視這次pr的內容,包括提交內容,檔案修改差異。具體每個平臺不一樣,但是功能應該類似。
此時,假設經過程式碼review,認為沒有問題,那麼可以合併到develop去了。
合併後,develop的情況
可以看到,除了把lisi分支的commit拿過來了,還加了個表示本次合併的commit。
ok,李四的工作,第一階段就算結束了。
模擬張三拉取李四程式碼
張三一看,李四這小夥子太快了,cv666。假設張三就依賴李四程式碼,此時,應該要把李四程式碼拉下來。
其實,這裡有個操作上的問題,當前張三在自己的分支上,他現在需要做的是:拉取develop程式碼最新程式碼,然後將develop的程式碼合到自己這裡來。
這個步驟的話,其實有些工具做得比較好,我用的intelj idea就有相關功能。這一步如果工具不趁手的話,非常要命。因為我們可能開發到一半,要去切換到其他分支,結果本分支有程式碼沒提交,還得先提交或者stash,切過去到develop,pull最新程式碼。然後再切回來自己分支。
很累人。
這塊回頭我講講idea裡面的實戰操作,其他ide工具大家可以自行探索。
這次先只介紹命令列版本,我先用笨辦法,切過去,pull,再切回來的方式吧。
模擬張三合併/rebase李四程式碼
要保證develop的commit保持線性,這裡有個重點,我們要以rebase的方式去合併develop的程式碼,而不是merge的方式。
rebase呢,這裡簡單說下,
這裡就是rebase的大體流程圖,其實,我剛有個想法,最近拿起了以前的電視劇,新三國。裡面呂布不就換了幾位義父嗎,這裡的rebase,換的也是parent啊,感覺rebase也是相當神似。
當然了,忘了一點,進行rebase那些的commit,hashcode會發生變化,和以前不一樣了。
我們這邊實際操作,看看效果:
這裡主要幾個操作,
1 git rebase develop -------因為和lisi改了同一行,需要解決衝突
2 我這邊習慣用小烏龜git,解決衝突
3 git add .
4 git rebase --continue
形象一點,也就是前面那個圖,不過新的rebase後的commit的hash變了
模擬張三push程式碼到遠端,遠端發起pull request
push
pull req
遠端develop log檢視
可以看看,遠端的develop分支,log是非常好看的。
第二輪開始
可以看到,第一輪已經差不多結束了,張三李四各提交了一次。假設現在輪到李四了,李四發現張三有push程式碼,就準備拉下來,就像之前的張三一樣。
李四切換到develop,拉取最新develop程式碼,並rebase
然後,我們基於develop,進行rebase(也就是,以develop為base)。本來為了模擬效果,是應該先本地搞點提交,再rebase的,我搞忘了。不過不重要,過程和前面張三差不多。
李四修改程式碼、commit、push
李四遠端發起pull request
檢查遠端develop分支的commit 記錄
依然是漂亮的commit記錄。
張三在此期間,已經做了修改、commit、push
張三這期間,暫時不依賴李四程式碼,就自己commit、push了(為啥push,怕程式碼丟嘛,多個備份)
張三切換到develop、拉取最新develop、rebase
張三此時終於準備合併李四的程式碼。
省略了張三這次解決了衝突的過程,我依然用了小烏龜。
張三此時的log情況
張三,由於rebase,導致自己本地之前的那次commit,被rebase了。rebase後,hashcode也變了。
此時,張三的本地分支,和張三遠端分支之間,出現了分叉。
張三rebase後,面臨分叉,強行push,覆蓋遠端分支
強制push後,張三遠端分支的log
張三遠端發起pull request
遠端develop分支log,線性日誌
總結
兩輪實戰結束。大家學會了沒?
2點要點:
1、總是rebase的方式去合併develop分支
2、rebase的時候,就是會面臨分叉的情況,此時強制push遠端分支,讓遠端分支的log和本地一致。