倉庫
? 在項(xiàng)目的開始到結(jié)束,我們會(huì)有兩種倉庫。一種是源倉庫(origin),一種是開發(fā)者倉庫。
源倉庫
? 在項(xiàng)目的開始,項(xiàng)目的發(fā)起者構(gòu)建起一個(gè)項(xiàng)目的最原始的倉庫,我們把它稱為origin,例如我們的PingHackers網(wǎng)站,origin就是這個(gè)PingHackers/blog了。源倉庫的有兩個(gè)作用:
- 匯總參與該項(xiàng)目的各個(gè)開發(fā)者的代碼
- 存放趨于穩(wěn)定和可發(fā)布的代碼
? 源倉庫應(yīng)該是受保護(hù)的,開發(fā)者不應(yīng)該直接對(duì)其進(jìn)行開發(fā)工作。只有項(xiàng)目管理者(通常是項(xiàng)目發(fā)起人)能對(duì)其進(jìn)行較高權(quán)限的操作。
開發(fā)者倉庫
? 上面說過,任何開發(fā)者都不會(huì)對(duì)源倉庫進(jìn)行直接的操作,源倉庫建立以后,每個(gè)開發(fā)者需要做的事情就是把源倉庫的“復(fù)制”一份,作為自己日常開發(fā)的倉庫。這個(gè)復(fù)制,也就是github上面的fork。
? 每個(gè)開發(fā)者所fork的倉庫是完全獨(dú)立的,互不干擾,甚至與源倉庫都無關(guān)。每個(gè)開發(fā)者倉庫相當(dāng)于一個(gè)源倉庫實(shí)體的影像,開發(fā)者在這個(gè)影像中進(jìn)行編碼,提交到自己的倉庫中,這樣就可以輕易地實(shí)現(xiàn)團(tuán)隊(duì)成員之間的并行開發(fā)工作。而開發(fā)工作完成以后,開發(fā)者可以向源倉庫發(fā)送pull request,請(qǐng)求管理員把自己的代碼合并到源倉庫中,這樣就實(shí)現(xiàn)了分布式開發(fā)工作,和最后的集中式的管理。
分支
? 分支是git中非常重要的一個(gè)概念。在其他集中式版本管理工具(SVN/CVS)把分支定位為高級(jí)技巧, 而在git中,分支操作則是每個(gè)開發(fā)人員日常工作流。利用git的分支,可以非常方便地進(jìn)行開發(fā)和測(cè)試。
? 每個(gè)開發(fā)者的倉庫都有自己的分支路線,而這些分支路線會(huì)通過代碼匯總映射到源倉庫中去。
我們?yōu)間it定下一種分支模型,在這種模型中,分支有兩類,五種。
永久性分支
-
master branch:主分支 -
develop branch:開發(fā)分支
? 永久性分支是壽命無限的分支,存在于整個(gè)項(xiàng)目的開始、開發(fā)、迭代、終止過程中。永久性分支只有兩個(gè)master和develop。
master
? 主分支從項(xiàng)目一開始便存在,它用于存放經(jīng)過測(cè)試,已經(jīng)完全穩(wěn)定代碼;在項(xiàng)目開發(fā)以后的任何時(shí)刻當(dāng)中,master存放的代碼應(yīng)該是可作為產(chǎn)品供用戶使用的代碼。所以,應(yīng)該隨時(shí)保持master倉庫代碼的清潔和穩(wěn)定,確保入庫之前是通過完全測(cè)試和代碼reivew的。master分支是所有分支中最不活躍的,大概每個(gè)月或每兩個(gè)月更新一次,每一次master更新的時(shí)候都應(yīng)該用git打上tag,說明你的產(chǎn)品有新版本發(fā)布了。
develop
? 開發(fā)分支,一開始從master分支中分離出來,用于開發(fā)者存放基本穩(wěn)定代碼。每個(gè)開發(fā)者的倉庫相當(dāng)于源倉庫的一個(gè)鏡像,每個(gè)開發(fā)者自己的倉庫上也有master和develop。開發(fā)者把功能做好以后,是存放到自己的develop中,當(dāng)測(cè)試完以后,可以向管理者發(fā)起一個(gè)pull request,請(qǐng)求把自己倉庫的develop分支合并到源倉庫的develop中。
? 所有開發(fā)者開發(fā)好的功能會(huì)在源倉庫的develop分支中進(jìn)行匯總,當(dāng)develop中的代碼經(jīng)過不斷的測(cè)試,已經(jīng)逐漸趨于穩(wěn)定了,接近產(chǎn)品目標(biāo)了。這時(shí)候,我們就可以把develop分支合并到master分支中,發(fā)布一個(gè)新版本。
? 注意,任何人不應(yīng)該向master直接進(jìn)行無意義的合并、提交操作。正常情況下,master只應(yīng)該接受develop的合并,也就是說,master所有代碼更新應(yīng)該源于合并develop的代碼。
臨時(shí)性分支
-
feature branch:功能分支 -
release branch:預(yù)發(fā)布分支 -
hotfix branch:bug修復(fù)分支
? 暫時(shí)性分支和永久性分支不同,暫時(shí)性分支在開發(fā)過程中是一定會(huì)被刪除的。所有暫時(shí)性分支,一般源于develop,最終也一定會(huì)回歸合并到develop。
feature
? 功能性分支,是用于開發(fā)項(xiàng)目的功能的分支,是開發(fā)者主要戰(zhàn)斗陣地。開發(fā)者在本地倉庫從develop分支分出功能分支,在該分支上進(jìn)行功能的開發(fā),開發(fā)完成以后再合并到develop分支上,這時(shí)候功能性分支已經(jīng)完成任務(wù),可以刪除。功能性分支的命名一般為feature-*,*為需要開發(fā)的功能的名稱。
? 舉一個(gè)例子,假設(shè)我是一名PingHackers網(wǎng)站的開發(fā)者,已經(jīng)把源倉庫fork了,并且clone到了本地。現(xiàn)在要開發(fā)PingHackers網(wǎng)站的“討論”功能。我在本地倉庫中可以這樣做:
step 1: 切換到develop分支
>>> git checkout develop
step 2: 分出一個(gè)功能性分支
>>> git checkout -b feature-discuss
step 3: 在功能性分支上進(jìn)行開發(fā)工作,多次commit,測(cè)試以后...
step 4: 把做好的功能合并到develop中
>>> git checkout develop # 回到develop分支
>>> git merge --no-ff feature-discuss # 把做好的功能合并到develop中
>>> git branch -d feature-discuss # 刪除功能性分支
>>> git push origin develop # 把develop提交到自己的遠(yuǎn)程倉庫中
? 這樣,就完成一次功能的開發(fā)和提交。
release
? 預(yù)發(fā)布分支,當(dāng)產(chǎn)品即將發(fā)布的時(shí)候,要進(jìn)行最后的調(diào)整和測(cè)試,這時(shí)候就可以分出一個(gè)預(yù)發(fā)布分支,進(jìn)行最后的bug fix。測(cè)試完全以后,發(fā)布新版本,就可以把預(yù)發(fā)布分支刪除。預(yù)發(fā)布分支一般命名為release-*。
hotfix
? 修復(fù)bug分支,當(dāng)產(chǎn)品已經(jīng)發(fā)布了,突然出現(xiàn)了重大的bug。這時(shí)候就要新建一個(gè) hotfix 分支,繼續(xù)緊急的bug修復(fù)工作,當(dāng)bug修復(fù)完以后,把該分支合并到master和develop以后,就可以把該分支刪除。修復(fù)bug分支命名一般為hotfix-*。
工作流程
源倉庫的構(gòu)建
Step 1:源倉庫的構(gòu)建
? 這一步通常由項(xiàng)目發(fā)起人來操作,我們這里把管理員設(shè)為PingHackers,假設(shè)PingHackers已經(jīng)為我們建立起了一個(gè)源倉庫PingHackers/git-demo,并且已經(jīng)初始化了兩個(gè)永久性分支master和develop。
開發(fā)者fork源倉庫
Step 2:開發(fā)者fork源倉庫
? 源倉庫建立以后,每個(gè)開發(fā)就可以去復(fù)制一份源倉庫到自己的github賬號(hào)中,然后作為自己開發(fā)所用的倉庫。假設(shè)我是一個(gè)項(xiàng)目中的開發(fā)者,我就到PingHackers/git-demo項(xiàng)目主頁上去fork:
fork完以后,我就可以在我自己的倉庫列表中看到一個(gè)和源倉庫一模一樣的復(fù)制品。
clone
Step 3:把自己開發(fā)者倉庫clone到本地
? 這一步應(yīng)該不用教,git clone
構(gòu)建功能分支進(jìn)行開發(fā)
Step 4:構(gòu)建功能分支進(jìn)行開發(fā)
? 進(jìn)入倉庫中,按照前面說所的構(gòu)建功能分支的步驟,構(gòu)建功能分支進(jìn)行開發(fā)、合并,假設(shè)我現(xiàn)在要開發(fā)一個(gè)“討論”功能:
>>> git checkout develop # 切換到`develop`分支
>>> git checkout -b feature-discuss # 分出一個(gè)功能性分支
>> touch discuss.js # 假裝discuss.js就是我們要開發(fā)的功能
>> git add .
>> git commit -m 'finish discuss feature' # 提交更改
>>> git checkout develop # 回到develop分支
>>> git merge --no-ff feature-discuss # 把做好的功能合并到develop中
>>> git branch -d feature-discuss # 刪除功能性分支
>>> git push origin develop # 把develop提交到自己的遠(yuǎn)程倉庫中
這時(shí)候,你上自己github的項(xiàng)目主頁中develop分支中看看,已經(jīng)有discuss.js這個(gè)文件了。
pull request
Step 5:向管理員提交pull request
? 假設(shè)我完成了“討論”功能(當(dāng)然,你還可能對(duì)自己的 develop進(jìn)行了多次合并,完成了多個(gè)功能),經(jīng)過測(cè)試以后,覺得沒問題,就可以請(qǐng)求管理員把自己倉庫的develop分支合并到源倉庫的develop分支中,這就是傳說中的pull request。
? 提交后,開發(fā)者就可以就可以靜靜地等待管理員對(duì)你的提交的評(píng)審了。
測(cè)試、合并
Step 6 管理員測(cè)試、合并
? 接下來就是管理員的操作了,作為管理員的PingHackers登陸github,便看到了我對(duì)源倉庫發(fā)起的 pull request。
? 這時(shí)候PingHackers需要做的事情就是:
對(duì)我的代碼進(jìn)行review。github提供非常強(qiáng)大的代碼review功能。
-
在他的本地測(cè)試新建一個(gè)測(cè)試分支,測(cè)試我的代碼:
>> git checkout develop # 進(jìn)入他本地的develop分支 >> git checkout -b livoras-develop # 從develop分支中分出一個(gè)叫l(wèi)ivoras-develop的測(cè)試分支測(cè)試我的代碼 >> git pull https://github.com/livoras/git-demo.git develop # 把我的代碼pull到測(cè)試分支中,進(jìn)行測(cè)試 -
判斷是否同意合并到源倉庫的develop中,如果經(jīng)過測(cè)試沒問題,可以把我的代碼合并到源倉庫的
develop中:>> git checkout develop >> git merge --no-ff livoras-develop >> git push origin develop
? 注意,PingHakers一直在操作的倉庫是源倉庫。所以我們經(jīng)過上面一系列操作以后,就可以在源倉庫主頁中看到。
? 經(jīng)過輾轉(zhuǎn)曲折的路程,我們的discuss.js終于從我的開發(fā)倉庫的功能分支到達(dá)了源倉庫的develop分支中。以上,就是一個(gè)git & github協(xié)同工作流的基本步驟。