除了獨具特色的“Fork + Pull”的分布式工作模式,GitHub同樣支持傳統的集中式協同工作模式。
## 4.2.1\. 版本庫授權
GitHub可以通過多種途徑為版本庫授權,讓版本庫成為多人共享的版本庫,從而讓項目管理者圍繞項目創建一個核心開發團隊。下面以gotgithub賬號下的helloworld版本庫為例,介紹如何設置版本庫的多人共享。
進入gotgithub/helloworld項目的管理界面,點擊左側導航條中的“Collaborators”,可以查看及添加項目的合作者,如圖4-17所示。
[](https://box.kancloud.cn/2015-07-09_559de3b2167d2.png)
圖4-17:添加項目合作者
圖4-17為項目添加了兩個合作者:supergirl和incredible。添加到項目當中的合作者會收到通知郵件,告知已經被加入到相應的項目當中。當新加入的項目合作者,如incredible,登錄GitHub,在儀表板的版本庫列表中會看到源自gotgithub用戶的版本庫,如圖4-18所示。
[](https://box.kancloud.cn/2015-07-09_559de3b46988d.png)
圖4-18:合作者項目列表
從圖4-18可以看出GitHub用戶incredible自己創建的項目托管在自己的空間下,而作為合作者參與的項目仍然托管在原創建者(gotgithub)的空間下,這一點明顯和派生(Fork)而來的項目不同。圖4-19是以incredible登錄GitHub訪問gotgithub/helloworld的界面。
[](https://box.kancloud.cn/2015-07-09_559de3bab97ed.png)
圖4-19:以合作者身份訪問項目
用戶incredible對版本庫gotgithub/helloworld擁有寫入權限。和gotgithub用戶稍有區別的是沒有管理員權限。
## 4.2.2\. 與傳統集中式工作模式的異同
傳統的集中式版本控制系統,如CVS、SVN,所有用戶都訪問同一個版本庫。采用集中式工作模式的GitHub用戶也同樣是訪問同一版本庫。
對于由用戶gotgithub創建的helloworld版本庫,添加了合作者supergirl和incredible,三個人克隆版本庫使用如下命令。
* 用戶 gotgithub 克隆版本庫。
~~~
gotgithub$ git clone https://gotgithub@github.com/gotgithub/helloworld.git
~~~
* 用戶 supergirl 克隆版本庫。
~~~
supergirl$ git clone https://supergirl@github.com/gotgithub/helloworld.git
~~~
* 用戶 incredible 克隆版本庫。
~~~
incredible$ git clone https://incredible@github.com/gotgithub/helloworld.git
~~~
傳統集中式版本控制系統,所有的提交歷史數據都在唯一的版本庫中,各個提交是順序進行的。為了防止多用戶在提交時相互覆蓋,集中式版本控制系統發明了很多方法 。有的采用編輯鎖的形式(如VSS),更改文件前對文件鎖定,其他人禁止對文件進行訪問(甚至無法讀取),完成修改并提交后,文件解鎖。有的如SVN,允許多人同時編輯同一文件,但只有先進行提交的才能成功,后提交的會遇到“過時”錯誤,必須先獲取版本庫中的新增提交并和本地修改進行合并。即傳統集中式版本控制系統,提交時必須和唯一的版本庫所在的服務器保持連接,而且提交有可能會失敗。
對于像Git這樣的分布式版本控制系統,提交總是會成功,這是因為提交并不涉及和共享服務器的交互,是針對本地克隆版本庫進行的本地操作。采用集中式的工作模式,共享版本庫作為各個用戶各自本地版本庫數據交換、溝通的中介,只有在本地克隆版本庫需要和共享版本庫同步的時候才要和服務器建立連接。例如將本地所做的一個或多個提交推送到共享服務器,或者將服務器上新的提交獲取到本地克隆版本庫。
實際上無論采用分布式還是集中式的工作模式,Git都好像工作在一個獨立的分支上(克隆即分支),即使共享版本庫和本地克隆版本庫的分支名都叫做master。如圖4-20,三個用戶克隆gitgithub/helloworld版本庫后,各自在本地執行了一次或多次提交。
[](https://box.kancloud.cn/2015-07-09_559de3c7342f4.png)
圖4-20:在本地版本庫中的提交
三個用戶各自的提交都會非常順利,但是一旦決定將本地提交推送到共享服務器時就可能遇到麻煩。用戶 gotgithub 先執行推送,會非常順利。如圖4-21所示。
~~~
gotgithub$ git push
~~~
[](https://box.kancloud.cn/2015-07-09_559de3d282ab3.png)
圖4-21:用戶gotgithub完成推送
而其他人就沒有這么幸運了,會報告錯誤:遇到非快進式推送。Git的推送操作就像SVN等集中式版本控制系統的提交操作那樣,先執行者成功,后執行者糟糕(要解決沖突,自動或手動)。
## 4.2.3\. 合并后推送
當用戶gotgithub完成推送后,共享版本庫以及三個用戶的本地版本庫如圖4-21所示。其中共享版本庫變得和gotgithub用戶的本地版本庫相一致。此時如果用戶supergirl執行推送,會遇到錯誤:非快進式推送。
~~~
supergirl$ git push
To https://supergirl@github.com/gotgithub/helloworld.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://supergirl@github.com/gotgithub/helloworld.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again. See the
'Note about fast-forwards' section of 'git push --help' for details.
~~~
GitHub并不對強制推送進行限制,但是用戶supergirl不要用git?push?-f命令強制推送,因為那樣會覆蓋掉共享版本庫中用戶gotgithub的推送,正確的做法是獲取共享版本庫中新提交,并在本地版本庫中和本地提交合并。即執行:
~~~
supergirl$ git fetch
supergirl$ git merge
~~~
獲取和合并操作過程如圖4-22所示。
[](https://box.kancloud.cn/2015-07-09_559de3dd73137.png)
圖4-22:合并操作示意圖
實際上用戶supergirl只需執行一條命令便可完成所有的操作:
~~~
supergirl$ git pull
~~~
即:git?pull?=?git?fetch?+?git?merge。
但是合并操作并不總是會成功,如果自動合并失敗,會在暫存區對合并前后文件進行標識,工作區進入沖突解決狀態,在沖突解決完成之前不能提交。Git支持多種圖形工具幫助完成沖突解決,執行如下命令,即可自動調用已安裝的沖突解決工具。
~~~
supergirl$ git mergetool
~~~
沖突解決完畢,執行提交即完成沖突解決。如果在沖突解決過程把本地文件搞得一團糟,隨時可以取消合并操作。執行命令git?reset?--hard會取消沖突的合并讓本地版本庫回到合并之前的狀態。
成功完成合并后將本地版本庫中的提交推送到共享版本庫:
~~~
supergirl$ git push
~~~
完成推送后的版本庫示意圖如圖4-23所示。
[](https://box.kancloud.cn/2015-07-09_559de3df8d8d4.png)
圖4-23:完成合并后推送
## 4.2.4\. 合并還是變基
合并并非多個開發者的工作成果融合的唯一選擇,有時甚至并非最佳選擇。一方面合并會產生除了合并雙方(或多方)所有提交外的一個新提交,增加了代碼審核的負擔,另一方面本地多個提交混雜一起與遠程分支合并會更困難。在特定情況下,變基是合并之外的另一個選擇。
圖4-24展示用戶incredible采用合并和變基兩種不同解決方案的操作結果。圖中右上是合并操作后的結果,右下是變基操作后的結果。
[](https://box.kancloud.cn/2015-07-09_559de3e13b28d.png)
圖4-24:合并和變基結果比較
若用戶 incredible 選擇變基操作,執行命令如下:
* 獲取遠程版本庫的提交到本地的遠程分支。
~~~
incredible$ git fetch origin
~~~
* 執行變基操作,將本地master分支的提交變基到新的遠程分支中。
~~~
incredible$ git rebase origin/master
~~~
如果一切順利,變基后推送到共享版本庫。
~~~
incredible$ git push
~~~
推送后的版本庫狀態如圖4-25所示。
[](https://box.kancloud.cn/2015-07-09_559de3e2b8a4f.png)
圖4-25:變基后推送
如果希望在執行git?pull時自動使用git?rebase取代默認的git?merge操作,可以在git?pull命令行添加參數--rebase如下:
~~~
$ git pull --rebase
~~~
或者通過配置變量設置當前分支使用變基策略,即每次執行git?pull命令時對于master分支,采用變基操作取代默認的合并操作。
~~~
$ git config branch.master.rebase true
~~~
如果希望本地所有克隆版本庫在執行git?pull時都改變默認行為,將變基作為首選,則如下設置全局變量。
~~~
$ git config --global branch.autosetuprebase true
~~~
- 前言
- 1. 探索GitHub
- 1.1. 什么是GitHub
- 1.2. GitHub亮點
- 1.3. 探索GitHub
- 2. 加入GitHub
- 2.1. 創建GitHub賬號
- 2.2. 瀏覽托管項目
- 2.3. 社交網絡
- 3. 項目托管
- 3.1. 創建新項目
- 3.2. 操作版本庫
- 3.3. 公鑰認證管理
- 3.4. 版本庫鉤子擴展
- 3.5. 建立主頁
- 4. 工作協同
- 4.1. Fork + Pull模式
- 4.2. 共享版本庫
- 4.3. 組織和團隊
- 4.4. 代碼評注
- 4.5. 缺陷跟蹤
- 4.6. 維基
- 5. 付費服務
- 5.1. GitHub收費方案
- 5.2. GitHub企業版
- 6. GitHub副產品
- 6.1. GitHub:Gist
- 6.2. 其他版本控制工具支持
- 6.3. 客戶端工具
- 6.4. 其他
- 7. 附錄:輕量級標記語言
- 貢獻者列表