Git的點(diǎn)點(diǎn)滴滴,附帶Android Studio中的操作(四):用Git進(jìn)行協(xié)同開發(fā)

在協(xié)同開發(fā)中,為了項(xiàng)目管理的方便,會(huì)采用各種各樣的工作流,有關(guān)工作流方面的內(nèi)容,可以到開頭提供的第三個(gè)網(wǎng)址里學(xué)習(xí)。這里只簡(jiǎn)單介紹兩個(gè)實(shí)用的技巧。

01 一個(gè)干凈的push!

在Git中,我們很少會(huì)改變中央倉(cāng)庫(kù)的已有的提交歷史。因?yàn)槟菢訒?huì)使所有的開發(fā)者的本地倉(cāng)庫(kù)和中央倉(cāng)庫(kù)處在不一致的狀態(tài),所有開發(fā)者都需要因?yàn)檫@個(gè)改動(dòng)調(diào)整自己的本地倉(cāng)庫(kù)來與中央倉(cāng)庫(kù)保持一致。如果改動(dòng)很大,調(diào)整將會(huì)很復(fù)雜。只要不是及其嚴(yán)重的事情,我們都不會(huì)去調(diào)整中央倉(cāng)庫(kù)的提交歷史。所以,推送上去是什么樣的,以后就會(huì)是什么樣的,對(duì)于中央倉(cāng)庫(kù)來說,第一印象會(huì)伴隨一生。

所以,就像女生出門前要化妝一樣,在推送本地分支到中央倉(cāng)庫(kù)前,要把本地分支整理干凈。一般,我們會(huì)給每個(gè)功能新建一個(gè)分支,在功能開發(fā)完成后,可以用git rebase -i命令刪去那些無關(guān)緊要的提交,并將提交歷史書寫成我們邏輯中的樣子。

比如我們接到了生產(chǎn)車門的任務(wù),現(xiàn)在我們把它完成了,開發(fā)歷史如下。

在我們把它推送到中央倉(cāng)庫(kù)前,我們用git rebase -i <commitID>整理一下它的提交歷史,commitID參數(shù)用來指定我們要從哪個(gè)提交開始修改。由于我們是從BetterWheelCompleted這個(gè)提交開始開發(fā)車門的,所以commitID參數(shù)應(yīng)該是這個(gè)提交的版本號(hào),為99c7ed1578c0a16a0f1de58548883a8d6e8eeb8a。執(zhí)行以下指令。

$ git rebase -i 99c7ed1578c0a16a0f1de58548883a8d6e8eeb8a

之后,在命令行中會(huì)顯示vi文本編輯窗口。

在最前面的是各個(gè)提交,每個(gè)提交的前面是要對(duì)該提交執(zhí)行的命令,默認(rèn)是pick采用提交,我們主要會(huì)用到squash命令,squash命令可以讓我們把對(duì)應(yīng)提交合并到上一次提交中,舉個(gè)栗子,給69218a4提交加上squash命令就可以把它合并到f7a6770提交上。我們開發(fā)車門主要有三個(gè)階段,設(shè)計(jì)車架,設(shè)計(jì)車窗,加入手勢(shì)開門功能,所以我們要分別合并第二、三、四次提交。我們把它編輯如下,然后保存并退出編輯窗口。

之后在合并第二、三、四次提交時(shí),Git又會(huì)彈出一個(gè)文本編輯窗口,讓我們合并三次提交的提交信息。

因?yàn)檫@一次合并提交的信息應(yīng)該為“設(shè)計(jì)了車窗”,剛好是第二個(gè)提交的提交信息,所以我們?cè)诓灰男畔⑶凹?code>#把他們忽略即可。合并完成后,我們的提交歷史就變成了如下模樣。

然后就可以把他們推送到遠(yuǎn)端,由其他人檢查代碼,然后合并或者變基到主分支上了。如果在開發(fā)完后就已經(jīng)決定要這條分支變基到主分支上,那也可以直接用git rebase -i <branch_name>來修改提交歷史并變基。

很多時(shí)候,我們會(huì)把一個(gè)功能的實(shí)現(xiàn)分為好幾個(gè)功能點(diǎn),然后給功能點(diǎn)新建一條分支,然后在這個(gè)功能點(diǎn)開發(fā)完后把修改整合回功能分支。這樣做的好處是可以保持功能分支的整潔,不會(huì)在功能分支上生成很多備份代碼的提交,但是如果用普通的merge操作的話,合并生成的提交除了指向主功能分支外,也會(huì)指向功能點(diǎn)分支,那樣還是會(huì)把功能點(diǎn)分支上的提交歷史混合進(jìn)來。

這時(shí)我們可以使用git merge --squash <branch_name>,在merge指令中加入--squash后會(huì)把branch_name分支上的所有提交壓縮成一個(gè)加入到當(dāng)前分支上來,并且這個(gè)提交不會(huì)指向被合并的分支。舉個(gè)栗子,在上次我們把車門的分支推送上去給老大檢查后,老大說要再加一個(gè)手勢(shì)關(guān)門的功能!然后我們?yōu)榱酥鞣种У恼麧崳o這個(gè)小功能新建了一個(gè)分支進(jìn)行開發(fā)。接著,經(jīng)過了不懈努力,我們終于開發(fā)完了,現(xiàn)在提交歷史如下。

我們用以下指令把feature-CloaseDoorwithGesture分支的上的提交壓縮成一個(gè)一條放到produceDoor分支上。

$ git checkout produceDoor
$ git merge --squash feature-CloseDoorwithGesture
$ git commit -m "給車門加上了手勢(shì)關(guān)門的功能"

執(zhí)行完成后我們的提交歷史就變成了下圖所示模樣。

可以看到新建的提交并沒有指向feature-CloaseDoorwithGesture分支。在合并完后,我們可以刪除feature-CloaseDoorwithGesture分支。

$ git branch -D feature-CloseDoorwithGesture

OK。老大說干的不錯(cuò),讓我們把分支合并到主分支上,然后推送到中央倉(cāng)庫(kù)來結(jié)束這個(gè)功能的開發(fā)。

$ git merge --no-ff produceDoor -m "車門生產(chǎn)完成"
$ git push origin master

執(zhí)行完成后,提交歷史如下。

Android Studio中的相應(yīng)操作
VCS->Git->Merge Changes下的合并操作,并選中squash commit選項(xiàng),即可完成git merge --squash <branch_name>操作。

git rebase -i <commitID>可以用VCS->Git->Rebase完成。點(diǎn)擊后會(huì)彈出如下對(duì)話框,選中Interactive選項(xiàng),在Branch選項(xiàng)中選中要變基的分支,在Onto選項(xiàng)中,填寫新基點(diǎn)(會(huì)從這個(gè)提交開始修改歷史)。

點(diǎn)擊Rebase之后,會(huì)彈出如下對(duì)話框, 在這里你可以選擇要對(duì)每個(gè)提交執(zhí)行的命令。選完命令之后,按下Start Rebasing就會(huì)開始變基。

02 push失?。?/strong>

·我們把前面開發(fā)車門那個(gè)同學(xué)叫做小明,在小明開發(fā)車門,引擎和輪子的同時(shí),還有一個(gè)叫小剛的同學(xué)在開發(fā)制動(dòng)系統(tǒng)。小剛現(xiàn)在剛把制動(dòng)系統(tǒng)開發(fā)完畢,他現(xiàn)在的提交歷史如下。

現(xiàn)在他要把master分支推送到中央倉(cāng)庫(kù)上。小剛運(yùn)行了如下指令。

$ git push origin master

但是Git告訴他,push被拒絕了,因?yàn)橹醒雮}(cāng)庫(kù)的master分支里有本地還沒有的改動(dòng),并讓我們把改動(dòng)集成到本地倉(cāng)庫(kù)中再進(jìn)行push。

所以在每次push前,應(yīng)該先抓取中央倉(cāng)庫(kù)上的更新,然后集成到本地,再提交。抓取更新的指令是git fetch <remote_name> <branch_name>。現(xiàn)在小明用以下指令拉取了中央倉(cāng)庫(kù)上的更新。

$ git fetch origin master

拉取后,本地的提交歷史變成了這樣。其中,origin/master表示的就是遠(yuǎn)程倉(cāng)庫(kù)上的master分支,遠(yuǎn)程分支是只讀的,不能修改。

現(xiàn)在小明要把遠(yuǎn)程倉(cāng)庫(kù)的master分支上的改動(dòng)集成到本地的master上。根據(jù)之前學(xué)的知識(shí),有兩種方法,rebasemerge。

如果使用merge,把本地origin/master分支的內(nèi)容合并到master上,合并后提交歷史如下。很亂,而且因?yàn)楹喜⒍律闪艘粋€(gè)節(jié)點(diǎn)。

如果用rebase,把本地master分支的內(nèi)容變基到origin/master上,合并后提交歷史如下。清楚了很多,而且看起來像是串行開發(fā)的一樣。一般把遠(yuǎn)端更新整合到本地會(huì)用rebase指令。

注意: rebase操作會(huì)把可以快進(jìn)的合并記錄刪掉,最后rebase結(jié)果就像是合并時(shí)使用了快進(jìn)一樣。如果要保留合并記錄,可以加入--preserve-merges參數(shù)。

上面提到過git pull <remote_name> <branch_name>操作,它其實(shí)是git fetch <remote_name> <branch_name>git merge的結(jié)合。當(dāng)然也可以轉(zhuǎn)化為rebase版本,在中間加個(gè)參數(shù),git pull --rebase <remote_name> <branch_name>。

其實(shí)上面的操作有更好的處理方法。在功能開發(fā)完成后,可以先把遠(yuǎn)端的更新用git pull --rebase拉取下來,并把本地分支的更新變基到上面去。之后,把功能分支rebase到主分支上,這個(gè)時(shí)候遠(yuǎn)端的更新就全部整合進(jìn)功能分支了,這個(gè)時(shí)候我們可以測(cè)試一下合并之后代碼還正不正確。最后再把功能分支合并到主分支并推送上去。

Android Studio中的相應(yīng)操作
在Android Studio中,可以選擇用merge版本還是rebase版本的pull操作。按下下圖中的按鈕。

在彈出的對(duì)話框中,選擇拉取方式。右邊的選項(xiàng)是存儲(chǔ)當(dāng)前工作區(qū)修改的方式。選擇完成后,點(diǎn)擊ok即可開始拉取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容