若是想與他人使用,除了使用Git來完成平常工做以外,還須要一個遠程的Git倉庫。儘管從技術上能夠從我的的倉庫裏推送和拉取修改內容,但並不鼓勵這樣作,由於一不留心就很容易弄混其餘人的進度。所以,更好的合做方式是創建一個你們均可以訪問的共享倉庫,從那裏推送和拉取數據。咱們將這個倉庫稱爲"Git服務器";代理一個Git倉庫只須要花費不多的資源,幾乎從不須要整個服務器來支持它的運行python
遠程倉庫一般只是一個裸倉庫(bare repository)——即一個沒有當前工做目錄的倉庫。由於該倉庫只是一個合做媒介,因此不須要從硬盤上取出最新版本的快照;倉庫裏存放的僅僅是Git的數據。簡單地說,裸倉庫就是你工做目錄中.git子目錄內的內容linux
本文將詳細介紹服務器上的Gitgit
Git可使用四種主要的協議來傳輸數據:本地傳輸,SSH協議,Git協議和HTTP協議。下面分別介紹一下哪些情形應該使用(或避免使用)這些協議github
值得注意的是,除了HTTP協議外,其餘全部協議都要求在服務器端安裝並運行Gitweb
【本地協議】正則表達式
最基本的就是本地協議(Local protocol),所謂的遠程倉庫在該協議中的表示,就是硬盤上的另外一個目錄。這常見於團隊每個成員都對一個共享的文件系統(例如NFS)擁有訪問權,或者比較少見的多人共用同一臺電腦的狀況。後面一種狀況並不安全,由於全部代碼倉庫實例都儲存在同一臺電腦裏,增長了災難性數據損失的可能性shell
$ git init ~/git-server --bare 將當前的倉庫初始化爲一個裸倉庫,裸倉庫的意思是沒有工做目錄。中央服務器並不須要工做目錄,它是一個被動的接收做用,若是有工做目錄的話,反而會形成錯亂vim
若是你使用一個共享的文件系統,就能夠在一個本地文件系統中克隆倉庫,推送和獲取。克隆的時候只須要將遠程倉庫的路徑做爲URL使用瀏覽器
$ git clone /opt/git/project.git
或者這樣:安全
$ git clone file:///opt/git/project.git
若是在URL開頭明確使用file://,那麼Git會以一種略微不一樣的方式運行。若是你只給出路徑,Git會嘗試使用硬連接或直接複製它所須要的文件。若是使用了file://,Git會調用它平時經過網絡來傳輸數據的工序,而這種方式的效率相對較低。使用file://前綴的主要緣由是當你須要一個不包含無關引用或對象的乾淨倉庫副本的時候——通常指從其餘版本控制系統導入的,或相似情形。咱們這裏僅僅使用普通路徑,這樣更快
要添加一個本地倉庫做爲現有Git項目的遠程倉庫,能夠這樣作
$ git remote add local_proj /opt/git/project.git
而後就能夠像在網絡上同樣向這個遠程倉庫推送和獲取數據了
基於文件倉庫的優勢在於它的簡單,同時保留了現存文件的權限和網絡訪問權限。若是你的團隊已經有一個全體共享的文件系統,創建倉庫就十分容易了。你只需把一份裸倉庫的副本放在你們都能訪問的地方,而後像對其餘共享目錄同樣設置讀寫權限就能夠了
這也是從別人工做目錄中獲取工做成果的快捷方法。假如你和你的同事在一個項目中合做,他們想讓你檢出一些東西的時候,運行相似git pull /home/john/project一般會比他們推送到服務器,而你再從服務器獲取簡單得多
這種方法的缺點是,與基本的網絡鏈接訪問相比,難以控制從不一樣位置來的訪問權限。若是你想從家裏的筆記本電腦上推送,就要先掛載遠程硬盤,這和基於網絡鏈接的訪問相比更加困難和緩慢
另外一個很重要的問題是該方法不必定就是最快的,尤爲是對於共享掛載的文件系統。本地倉庫只有在你對數據訪問速度快的時候才快。在同一個服務器上,若是兩者同時容許Git訪問本地硬盤,經過NFS訪問倉庫一般會比SSH慢
【SSH協議】
Git使用的傳輸協議中最多見的可能就是SSH了。這是由於大多數環境已經支持經過SSH對服務器的訪問—即使尚未,架設起來也很容易。SSH也是惟一一個同時支持讀寫操做的網絡協議。另外兩個網絡協議(HTTP和Git)一般都是隻讀的,因此雖然兩者對大多數人均可用,但執行寫操做時仍是須要SSH。SSH同時也是一個驗證受權的網絡協議;而由於其廣泛性,通常架設和使用都很容易
經過SSH克隆一個Git倉庫,能夠像下面這樣給出ssh://的URL:
$ git clone ssh://user@server/project.git
或者不指明某個協議——這時Git會默認使用SSH:
$ git clone user@server:project.git
若是不指明用戶,Git會默認使用當前登陸的用戶名鏈接服務器
使用SSH的好處有不少。首先,若是你想擁有對網絡倉庫的寫權限,基本上不可能不使用SSH。其次,SSH架設相對比較簡單——SSH守護進程很常見,不少網絡管理員都有一些使用經驗,並且不少操做系統都自帶了它或者相關的管理工具。再次,經過SSH進行訪問是安全的——全部數據傳輸都是加密和受權的。最後,和Git及本地協議同樣,SSH也很高效,會在傳輸以前儘量壓縮數據
SSH的限制在於你不能經過它實現倉庫的匿名訪問。即便僅爲讀取數據,人們也必須在能經過SSH訪問主機的前提下才能訪問倉庫,這使得SSH不利於開源的項目。若是你僅僅在公司網絡裏使用,SSH多是你惟一須要使用的協議。若是想容許對項目的匿名只讀訪問,那麼除了爲本身推送而架設SSH協議以外,還須要支持其餘協議以便他人訪問讀取
【Git協議】
接下來是Git協議。這是一個包含在Git軟件包中的特殊守護進程;它會監聽一個提供相似於SSH服務的特定端口(9418),而無需任何受權。打算支持Git協議的倉庫,須要先建立git-daemon-export-ok文件,它是協議進程提供倉庫服務的必要條件,但除此以外該服務沒有什麼安全措施。要麼全部人都能克隆Git倉庫,要麼誰也不能。這也意味着該協議一般不能用來進行推送。你能夠容許推送操做;然而因爲沒有受權機制,一旦容許該操做,網絡上任何一個知道項目URL的人將都有推送權限。不用說,這是十分罕見的狀況
Git協議是現存最快的傳輸協議。若是你在提供一個有很大訪問量的公共項目,或者一個不須要對讀操做進行受權的龐大項目,架設一個Git守護進程來供應倉庫是個不錯的選擇。它使用與SSH協議相同的數據傳輸機制,但省去了加密和受權的開銷
Git協議消極的一面是缺乏受權機制。用Git協議做爲訪問項目的惟一方法一般是不可取的。通常的作法是,同時提供SSH接口,讓幾個開發者擁有推送(寫)權限,其餘人經過git://擁有隻讀權限。Git協議可能也是最難架設的協議。它要求有單獨的守護進程,須要定製,須要設定xinetd或相似的程序,而這些工做就沒那麼輕鬆了。該協議還要求防火牆開放9418端口,而企業級防火牆通常不容許對這個非標準端口的訪問。大型企業級防火牆一般會封鎖這個少見的端口
【HTTP/S協議】
最後還有HTTP協議。HTTP或HTTPS協議的優美之處在於架設的簡便性。基本上,只須要把Git的裸倉庫文件放在HTTP的根目錄下,配置一個特定的post-update掛鉤(hook)就能夠搞定。此後,每一個能訪問Git倉庫所在服務器上web服務的人均可以進行克隆操做。下面的操做能夠容許經過HTTP對倉庫進行讀取:
$ cd /var/www/htdocs/ $ git clone --bare /path/to/git_project gitproject.git $ cd gitproject.git $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update
Git附帶的post-update掛鉤會默認運行合適的命令(git update-server-info)來確保經過HTTP的獲取和克隆正常工做。這條命令在你用SSH向倉庫推送內容時運行;以後,其餘人就能夠用下面的命令來克隆倉庫:
$ git clone http://example.com/gitproject.git
在本例中,咱們使用了Apache設定中經常使用的/var/www/htdocs路徑,不過你可使用任何靜態web服務——把裸倉庫放在它的目錄裏就行。 Git的數據是以最基本的靜態文件的形式提供的
經過HTTP進行推送操做也是可能的,不過這種作法不太常見,而且牽扯到複雜的WebDAV設定。經過HTTP推送的好處之一是你可使用任何WebDAV服務器,不須要爲Git設定特殊環境;因此若是主機提供商支持經過WebDAV更新網站內容,你也可使用這項功能
使用HTTP協議的好處是易於架設。幾條必要的命令就可讓全世界讀取到倉庫的內容。花費不過幾分鐘。HTTP協議不會佔用過多服務器資源。由於它通常只用到靜態的HTTP服務提供全部數據,普通的Apache服務器平均每秒能支撐數千個文件的併發訪問——哪怕讓一個小型服務器超載都很難
你也能夠經過HTTPS提供只讀的倉庫,這意味着你能夠加密傳輸內容;你甚至能夠要求客戶端使用特定簽名的SSL證書。通常狀況下,若是到了這一步,使用SSH公共密鑰多是更簡單的方案;不過也存在一些特殊狀況,這時經過HTTPS使用帶簽名的SSL證書或者其餘基於HTTP的只讀鏈接受權方式是更好的解決方案
HTTP還有個額外的好處:HTTP是一個如此常見的協議,以致於企業級防火牆一般都容許其端口的通訊
HTTP協議的消極面在於,相對來講客戶端效率更低。克隆或者下載倉庫內容可能會花費更多時間,並且HTTP傳輸的體積和網絡開銷比其餘任何一個協議都大。由於它沒有按需供應的能力,傳輸過程當中沒有服務端的動態計算,於是HTTP協議常常會被稱爲傻瓜(dumb)協議
開始架設Git服務器前,須要先把現有倉庫導出爲裸倉庫——即一個不包含當前工做目錄的倉庫。作法直截了當,克隆時用--bare選項便可。裸倉庫的目錄名通常以.git結尾,像這樣
$ git clone --bare my_project my_project.git Cloning into bare repository 'my_project.git'... done.
clone操做基本上至關於git init加git fetch,因此這裏出現的實際上是git init的輸出,先由它創建一個空目錄,而以後傳輸數據對象的操做並沒有任何輸出,只是悄悄在幕後執行。如今my_project.git目錄中已經有了一份Git目錄數據的副本
總體上的效果大體至關於:
$ cp -Rf my_project/.git my_project.git
但在配置文件中有若干小改動,不過對用戶來說,使用方式都同樣,不會有什麼影響。它僅取出Git倉庫的必要原始數據,存放在該目錄中,而不會另外建立工做目錄
【把裸倉庫移到服務器上】
有了裸倉庫的副本後,剩下的就是把它放到服務器上並設定相關協議。假設一個域名爲git.example.com的服務器已經架設好,並能夠經過 SSH 訪問,打算把全部 Git 倉庫儲存在 /opt/git 目錄下。只要把裸倉庫複製過去
$ scp -r my_project.git user@git.example.com:/opt/git
如今,全部對該服務器有SSH訪問權限,並可讀取/opt/git目錄的用戶均可以用下面的命令克隆該項目
$ git clone user@git.example.com:/opt/git/my_project.git
若是某個SSH用戶對/opt/git/my_project.git目錄有寫權限,那他就有推送權限。若是到該項目目錄中運行git init命令,並加上--shared選項,那麼Git會自動修改該倉庫目錄的組權限爲可寫
實際上,--shared能夠指定其餘行爲,只是默認爲將組權限改成可寫並執行g+sx,因此最後會獲得rws
$ ssh user@git.example.com $ cd /opt/git/my_project.git $ git init --bare --shared
值得注意的是,這的確是架設一個少數人具備鏈接權的Git服務的所有,只要在服務器上加入能夠用SSH登陸的賬號,而後把裸倉庫放在你們都有讀寫權限的地方
【小型安裝】
若是設備較少或者只想在小型開發團隊裏嘗試Git,那麼一切都很簡單。架設Git服務最複雜的地方在於帳戶管理。若是須要倉庫對特定的用戶可讀,而給另外一部分用戶讀寫權限,那麼訪問和許可的安排就比較困難
SSH鏈接
若是已經有了一個全部開發成員均可以用SSH訪問的服務器,架設第一個服務器將變得異常簡單,幾乎什麼都不用作。若是須要對倉庫進行更復雜的訪問控制,只要使用服務器操做系統的本地文件訪問許可機制就好了
若是須要團隊裏的每一個人都對倉庫有寫權限,又不能給每一個人在服務器上創建帳戶,那麼提供SSH鏈接就是惟一的選擇了。咱們假設用來共享倉庫的服務器已經安裝了SSH服務,並且你經過它訪問服務器
有好幾個辦法可讓團隊的每一個人都有訪問權。第一個辦法是給每一個人創建一個帳戶,直截了當但略過繁瑣。反覆運行adduser並給全部人設定臨時密碼可不是好玩的
第二個辦法是在主機上創建一個git帳戶,讓每一個須要寫權限的人發送一個SSH公鑰,而後將其加入git帳戶的~/.ssh/authorized_keys文件。這樣一來,全部人都將經過git帳戶訪問主機。這絲絕不會影響提交的數據,訪問主機用的身份不會影響提交對象的提交者信息
另外一個辦法是讓SSH服務器經過某個LDAP服務,或者其餘已經設定好的集中受權機制,來進行受權。只要每一個人都能得到主機的shell訪問權,任何可用的SSH受權機制都能達到相同效果
大多數Git服務器都會選擇使用SSH公鑰來進行受權。系統中的每一個用戶都必須提供一個公鑰用於受權,沒有的話就要生成一個。生成公鑰的過程在全部操做系統上都差很少。首先先確認一下是否已經有一個公鑰了。SSH公鑰默認儲存在帳戶的主目錄下的~/.ssh目錄
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
關鍵是看有沒有用something和something.pub來命名的一對文件,這個something一般就是id_dsa或id_rsa。有.pub後綴的文件就是公鑰,另外一個文件則是密鑰。假如沒有這些文件,或者乾脆連.ssh目錄都沒有,能夠用ssh-keygen來建立。該程序在Linux/Mac系統上由SSH包提供,而在Windows上則包含在MSysGit包裏:
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/Users/schacon/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/schacon/.ssh/id_rsa. Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub. The key fingerprint is: 43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local
它先要求你確認保存公鑰的位置(.ssh/id_rsa),而後它會讓你重複一個密碼兩次,若是不想在使用公鑰的時候輸入密碼,能夠留空
如今,全部作過這一步的用戶都得把它們的公鑰給你或者Git服務器的管理員(假設SSH服務被設定爲使用公鑰機制)。他們只須要複製.pub文件的內容而後發郵件給管理員。公鑰的樣子大體以下
$ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@agadorlaptop.local
如今咱們過一邊服務器端架設SSH訪問的流程。本例將使用authorized_keys方法來給用戶受權。咱們還將假定使用相似Ubuntu這樣的標準Linux發行版。首先,建立一個名爲'git'的用戶,併爲其建立一個.ssh目錄
$ sudo adduser git
$ su git
$ cd
$ mkdir .ssh
接下來,把開發者的 SSH 公鑰添加到這個用戶的 authorized_keys 文件中。假設你經過電郵收到了幾個公鑰並存到了臨時文件裏。重複一下,公鑰大體看起來是這個樣子:
$ cat /tmp/id_rsa.john.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq dAv8JggJICUvax2T9va5 gsg-keypair
只要把它們逐個追加到authorized_keys文件尾部便可:
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
如今能夠用--bare選項運行git init來創建一個裸倉庫,這會初始化一個不包含工做目錄的倉庫
$ cd /opt/git
$ mkdir project.git
$ cd project.git
$ git --bare init
這時,Join,Josie或者Jessica就能夠把它加爲遠程倉庫,推送一個分支,從而把第一個版本的項目文件上傳到倉庫裏了。值得注意的是,每次添加一個新項目都須要經過shell登入主機並建立一個裸倉庫目錄。咱們不妨以gitserver做爲git用戶及項目倉庫所在的主機名。若是在網絡內部運行該主機,並在DNS中設定gitserver指向該主機,那麼如下這些命令都是可用的:
# 在 John 的電腦上 $ cd myproject $ git init $ git add . $ git commit -m 'initial commit' $ git remote add origin git@gitserver:/opt/git/project.git $ git push origin master
這樣,其餘人的克隆和推送也同樣變得很簡單:
$ git clone git@gitserver:/opt/git/project.git $ cd project $ vim README $ git commit -am 'fix for the README file' $ git push origin master
用這個方法能夠很快捷地爲少數幾個開發者架設一個可讀寫的Git服務
做爲一個額外的防範措施,你能夠用Git自帶的git-shell工具限制git用戶的活動範圍。只要把它設爲git用戶登入的shell,那麼該用戶就沒法使用普通的bash或者csh什麼的shell程序。編輯/etc/passwd文件
$ sudo vim /etc/passwd
在文件末尾,你應該能找到相似這樣的行
git:x:1000:1000::/home/git:/bin/sh
把bin/sh改成/usr/bin/git-shell,或者用which git-shell查看它的實際安裝路徑。該行修改後的樣子以下
git:x:1000:1000::/home/git:/usr/bin/git-shell
如今git用戶只能用SSH鏈接來推送和獲取Git倉庫,而不能直接使用主機shell。嘗試普通SSH登陸的話,會看到下面這樣的拒絕信息
$ ssh git@gitserver fatal: What do you think I am? A shell? Connection to gitserver closed.
匿名的讀取權限該怎麼實現呢?也許除了內部私有的項目以外,你還須要託管一些開源項目。或者由於要用一些自動化的服務器來進行編譯,或者有一些常常變化的服務器羣組,而又不想成天生成新的SSH密鑰。總之,你須要簡單的匿名讀取權限
或許對小型的配置來講最簡單的辦法就是運行一個靜態web服務,把它的根目錄設定爲Git倉庫所在的位置,而後開啓post-update掛鉤。這裏繼續使用以前的例子。假設倉庫處於/opt/git目錄,主機上運行着Apache服務。重申一下,任何web服務程序均可以達到相同效果;做爲範例,咱們將用一些基本的Apache設定來展現大致須要的步驟
首先,開啓掛鉤:
$ cd project.git $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update
post-update掛鉤是作什麼的呢?其內容大體以下:
$ cat .git/hooks/post-update #!/bin/sh # # An example hook script to prepare a packed repository for use over # dumb transports. # # To enable this hook, rename this file to "post-update". # exec git-update-server-info
意思是當經過SSH向服務器推送時,Git將運行這個git-update-server-info命令來更新匿名HTTP訪問獲取數據時所須要的文件
接下來,在Apache配置文件中添加一個VirtualHost條目,把文檔根目錄設爲Git項目所在的根目錄。這裏咱們假定DNS服務已經配置好,會把對.gitserver的請求發送到這臺主機:
<VirtualHost *:80> ServerName git.gitserver DocumentRoot /opt/git <Directory /opt/git/> Order allow, deny allow from all </Directory> </VirtualHost>
另外,須要把/opt/git目錄的Unix用戶組設定爲www-data,這樣web服務才能夠讀取倉庫內容,由於運行CGI腳本的Apache實例進程默認就是以該用戶的身份起來的:
$ chgrp -R www-data /opt/git
重啓Apache以後,就能夠經過項目的URL來克隆該目錄下的倉庫了
$ git clone http://git.gitserver/project.git
這一招可讓你在幾分鐘內爲至關數量的用戶架設好基於HTTP的讀取權限。另外一個提供非受權訪問的簡單方法是開啓一個Git守護進程,不過這將要求該進程做爲後臺進程常駐
如今咱們的項目已經有了可讀可寫和只讀的鏈接方式,不過若是能有一個簡單的web界面訪問就更好了。Git自帶一個叫作GitWeb的CGI腳本,運行效果能夠到http://git.kernel.org這樣的站點體驗下
若是想看看本身項目的效果,不妨用Git自帶的一個命令,可使用相似lighttpd或webrick這樣輕量級的服務器啓動一個臨時進程。若是是在Linux主機上,一般都預裝了lighttpd,能夠到項目目錄中鍵入git instaweb來啓動。若是用的是Mac,Leopard預裝了Ruby,因此webrick應該是最好的選擇。若是要用lighttpd之外的程序來啓動git instaweb,能夠經過--httpd選項指定:
$ git instaweb --httpd=webrick [2009-02-21 10:02:21] INFO WEBrick 1.3.1 [2009-02-21 10:02:21] INFO ruby 1.8.6 (2008-03-03) [universal-darwin9.0]
這會在1234端口開啓一個HTTPD服務,隨之在瀏覽器中顯示該頁,十分簡單。關閉服務時,只需在原來的命令後面加上--stop選項就能夠了
$ git instaweb --httpd=webrick --stop
若是須要爲團隊或者某個開源項目長期運行GitWeb,那麼CGI腳本就要由正常的網頁服務來運行。一些Linux發行版能夠經過apt或yum安裝一個叫作gitweb的軟件包,不妨首先嚐試一下。咱們將快速介紹一下手動安裝GitWeb的流程。首先,你須要Git的源碼,其中帶有GitWeb,並能生成定製的CGI腳本
$ git clone git://git.kernel.org/pub/scm/git/git.git $ cd git/ $ make GITWEB_PROJECTROOT="/opt/git" \ prefix=/usr gitweb $ sudo cp -Rf gitweb /var/www/
注意,經過指定GITWEB_PROJECTROOT變量告訴編譯命令Git倉庫的位置。而後,設置Apache以CGI方式運行該腳本,添加一個VirtualHost配置:
<VirtualHost *:80> ServerName gitserver DocumentRoot /var/www/gitweb <Directory /var/www/gitweb> Options ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch AllowOverride All order allow,deny Allow from all AddHandler cgi-script cgi DirectoryIndex gitweb.cgi </Directory> </VirtualHost>
不難想象,GitWeb可使用任何兼容CGI的網頁服務來運行;若是偏向使用其餘web服務器,配置也不會很麻煩。如今,經過http://gitserver就能夠在線訪問倉庫了,在http://git.server上還能夠經過HTTP克隆和獲取倉庫的內容
把全部用戶的公鑰保存在authorized_keys文件的作法,只能湊和一陣子,當用戶數量達到幾百人的規模時,管理起來就會十分痛苦。每次改刪用戶都必須登陸服務器不去說,這種作法還缺乏必要的權限管理,每一個人都對全部項目擁有完整的讀寫權限
幸虧咱們還能夠選擇應用普遍的Gitosis項目。簡單地說,Gitosis就是一套用來管理authorized_keys文件和實現簡單鏈接限制的腳本。有趣的是,用來添加用戶和設定權限的並不是經過網頁程序,而只是管理一個特殊的Git倉庫。你只須要在這個特殊倉庫內作好相應的設定,而後推送到服務器上,Gitosis就會隨之改變運行策略,聽起來就很酷
Gitosis 的安裝算不上傻瓜化,但也不算太難。用Linux服務器架設起來最簡單。如下例子中,咱們使用裝有Ubuntu 8.10系統的服務器
Gitosis的工做依賴於某些Python工具,因此首先要安裝Python的setuptools包,在Ubuntu上稱爲python-setuptools
$ apt-get install python-setuptools
接下來,從Gitosis項目主頁克隆並安裝:
$ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install
這會安裝幾個供Gitosis使用的工具。默認Gitosis會把/home/git做爲存儲全部Git倉庫的根目錄,這沒什麼很差,不過咱們以前已經把項目倉庫都放在/opt/git裏面了,因此爲方便起見,咱們能夠作一個符號鏈接,直接劃轉過去,而沒必要從新配置:
$ ln -s /opt/git /home/git/repositories
Gitosis將會幫咱們管理用戶公鑰,因此先把當前控制文件更名備份,以便稍後從新添加,準備好讓Gitosis自動管理authorized_keys文件:
$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak
接下來,若是以前把git用戶的登陸shell改成git-shell命令的話,先恢復'git'用戶的登陸shell。改過以後,你們仍然沒法經過該賬號登陸,由於authorized_keys文件已經沒有了。不過不用擔憂,這會交給Gitosis來實現。因此如今先打開/etc/passwd文件,把這行:
git:x:1000:1000::/home/git:/usr/bin/git-shell
改回:
git:x:1000:1000::/home/git:/bin/sh
好了,如今能夠初始化Gitosis了。你能夠用本身的公鑰執行gitosis-init命令,要是公鑰不在服務器上,先臨時複製一份:
$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub Initialized empty Git repository in /opt/git/gitosis-admin.git/ Reinitialized existing Git repository in /opt/git/gitosis-admin.git/
這樣該公鑰的擁有者就能修改用於配置Gitosis的那個特殊Git倉庫了。接下來,須要手工對該倉庫中的post-update腳本加上可執行權限:
$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update
基本上就算是好了。若是設定過程沒出什麼差錯,如今能夠試一下用初始化Gitosis的公鑰的擁有者身份SSH登陸服務器,應該會看到相似下面這樣:
$ ssh git@gitserver PTY allocation request failed on channel 0 ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed.
說明Gitosis認出了該用戶的身份,但因爲沒有運行任何Git命令,因此它切斷了鏈接。那麼,如今運行一個實際的Git命令——克隆Gitosis的控制倉庫:
# 在你本地計算機上
$ git clone git@gitserver:gitosis-admin.git
這會獲得一個名爲gitosis-admin的工做目錄,主要由兩部分組成:
$ cd gitosis-admin $ find . ./gitosis.conf ./keydir ./keydir/scott.pub
gitosis.conf文件是用來設置用戶、倉庫和權限的控制文件。keydir目錄則是保存全部具備訪問權限用戶公鑰的地方——每人一個。在keydir裏的文件名(好比上面的scott.pub)應該跟你的不同——Gitosis會自動從使用gitosis-init腳本導入的公鑰尾部的描述中獲取該名字
看一下gitosis.conf文件的內容,它應該只包含與剛剛克隆的gitosis-admin相關的信息:
$ cat gitosis.conf [gitosis] [group gitosis-admin] members = scott writable = gitosis-admin
它顯示用戶scott——初始化Gitosis公鑰的擁有者——是惟一能管理gitosis-admin項目的人
如今咱們來添加一個新項目。爲此咱們要創建一個名爲mobile的新段落,在其中羅列手機開發團隊的開發者,以及他們擁有寫權限的項目。因爲'scott'是系統中的惟一用戶,咱們把他設爲惟一用戶,並容許他讀寫名爲iphone_project的新項目:
[group mobile] members = scott writable = iphone_project
修改完以後,提交gitosis-admin裏的改動,並推送到服務器使其生效:
$ git commit -am 'add iphone_project and mobile group' [master 8962da8] add iphone_project and mobile group 1 file changed, 4 insertions(+) $ git push origin master Counting objects: 5, done. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master
在新工程iphone_project裏首次推送數據到服務器前,得先設定該服務器地址爲遠程倉庫。但你不用事先到服務器上手工建立該項目的裸倉庫——Gitosis會在第一次遇到推送時自動建立:
$ git remote add origin git@gitserver:iphone_project.git $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master
請注意,這裏不用指明完整路徑(實際上,若是加上反而沒用),只須要一個冒號加項目名字便可——Gitosis會自動幫你映射到實際位置
要和朋友們在一個項目上協同工做,就得從新添加他們的公鑰。不過此次不用在服務器上一個一個手工添加到~/.ssh/authorized_keys文件末端,而只需管理keydir目錄中的公鑰文件。文件的命名將決定在gitosis.conf中對用戶的標識。如今咱們爲John,Josie和Jessica添加公鑰:
$ cp /tmp/id_rsa.john.pub keydir/john.pub $ cp /tmp/id_rsa.josie.pub keydir/josie.pub $ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub
而後把他們都加進'mobile'團隊,讓他們對iphone_project具備讀寫權限:
[group mobile] members = scott john josie jessica writable = iphone_project
若是你提交併推送這個修改,四個用戶將同時具備該項目的讀寫權限
Gitosis也具備簡單的訪問控制功能。若是想讓John只有讀權限,能夠這樣作:
[group mobile] members = scott josie jessica writable = iphone_project [group mobile_ro] members = john readonly = iphone_project
如今John能夠克隆和獲取更新,但Gitosis不會容許他向項目推送任何內容。像這樣的組能夠隨意建立,多少不限,每一個均可以包含若干不一樣的用戶和項目。甚至還能夠指定某個組爲成員之一(在組名前加上@ 前綴),自動繼承該組的成員:
[group mobile_committers] members = scott josie jessica [group mobile] members = @mobile_committers writable = iphone_project [group mobile_2] members = @mobile_committers john writable = another_iphone_project
若是遇到意外問題,試試看把loglevel=DEBUG加到[gitosis]的段落(把日誌設置爲調試級別,記錄更詳細的運行信息)。若是一不當心搞錯了配置,失去了推送權限,也能夠手工修改服務器上的/home/git/.gitosis.conf文件——Gitosis實際是從該文件讀取信息的。它在獲得推送數據時,會把新的gitosis.conf存到該路徑上。因此若是你手工編輯該文件的話,它會一直保持到下次向gitosis-admin推送新版本的配置內容爲止
Gitolite是在Git之上的一個受權層,依託sshd或者httpd來進行認證
認證是肯定用戶是誰,受權是決定該用戶是否被容許作他想作的事情
Gitolite容許你定義訪問許可而不僅做用於倉庫,而一樣於倉庫中的每一個branch和tag name。你能夠定義確切的人(或一組人)只能push特定的"refs"(或者branches或者tags)而不是其餘人。
【安裝】
安裝Gitolite很是簡單,甚至不用讀自帶的那一大堆文檔。你須要一個unix服務器上的帳戶;許多linux變種和solaris 10都已經試過了。不須要root訪問,假設git,perl,和一個openssh兼容的ssh服務器已經裝好了。在下面的例子裏,咱們會用git帳戶在gitserver進行
Gitolite是不一樣於「服務」的軟件——其經過ssh訪問,並且每一個在服務器上的userid都是一個潛在的「gitolite主機」。咱們在這裏描述最簡單的安裝方法
開始,在你的服務器上建立一個名爲git的用戶,而後以這個用戶登陸。從你的工做站拷貝你的SSH公鑰(也就是你用ssh-keygen默認生成的~/.ssh/id_dsa.pub文件),重命名爲<yourname>.pub(咱們這裏使用scott.pub做爲例子)。而後執行下面的命令:
$ git clone git://github.com/sitaramc/gitolite $ gitolite/install -ln # assumes $HOME/bin exists and is in your $PATH $ gitolite setup -pk $HOME/scott.pub
最後一個命令在服務器上建立了一個名爲gitolite-admin的Git倉庫
最後,回到你的工做站,執行git clone git@gitserver:gitolite-admin。而後你就完成了!Gitolite如今已經安裝在了服務器上,在你的工做站上,你也有一個名爲gitolite-admin的新倉庫。你可用經過更改這個倉庫以及推送到服務器上來管理你的Gitolite配置。
【配置文件和訪問規則】
安裝結束後,你切換到gitolite-admin倉庫(放在你的HOME目錄)而後看看都有啥:
$ cd ~/gitolite-admin/ $ ls conf/ keydir/ $ find conf keydir -type f conf/gitolite.conf keydir/scott.pub $ cat conf/gitolite.conf repo gitolite-admin RW+ = scott repo testing RW+ = @all
注意"scott"(以前用gl-setup命令時候的pubkey名稱)有讀寫權限並且在gitolite-admin倉庫裏有一個同名的公鑰文件
添加用戶很簡單。爲了添加一個名爲alice的用戶,獲取她的公鑰,命名爲alice.pub,而後放到在你工做站上的gitolite-admin克隆的keydir目錄。添加,提交,而後推送更改。這樣用戶就被添加了
gitolite配置文件的語法在conf/example.conf裏,咱們只會提到一些主要的。
你能夠給用戶或者倉庫分組。分組名就像一些宏;定義的時候,無所謂他們是工程仍是用戶;區別在於你使用「宏」的時候
@oss_repos = linux perl rakudo git gitolite @secret_repos = fenestra pear @admins = scott @interns = ashok @engineers = sitaram dilbert wally alice @staff = @admins @engineers @interns
你能夠控制許可在」ref「級別。在下面的例子裏,實習生能夠push "int"分支。工程師能夠push任何有"eng-"開頭的branch,還有refs/tags下面用"rc"開頭的後面跟數字的。並且管理員能夠隨便更改(包括rewind)對任何參考名
repo @oss_repos RW int$ = @interns RW eng- = @engineers RW refs/tags/rc[0-9] = @engineers RW+ = @admins
在RWorRW+以後的表達式是正則表達式(regex)對應着後面的push用的參考名字(ref)。因此咱們叫它「參考正則」(refex)
一樣,你可能猜到了,Gitolite字頭refs/heads/是一個便捷句法若是參考正則沒有用refs/開頭
一個這個配置文件語法的重要功能是,全部的倉庫的規則不須要在同一個位置。你能報全部普通的東西放在一塊兒,就像上面的對全部oss_repos的規則那樣,而後建一個特殊的規則對後面的特殊案例,就像:
repo gitolite
RW+ = sitaram
那條規則剛剛加入規則集的gitolite倉庫
此次你可能會想要知道訪問控制規則是如何應用的,咱們簡要介紹一下
在gitolite裏有兩級訪問控制。第一是在倉庫級別;若是你已經讀或者寫訪問過了任何在倉庫裏的參考,那麼你已經讀或者寫訪問倉庫了
第二級,應用只能寫訪問,經過在倉庫裏的branch或者tag。用戶名若是嘗試過訪問(W或+),參考名被更新爲已知。訪問規則檢查是否出如今配置文件裏,爲這個聯合尋找匹配(可是記得參考名是正則匹配的,不是字符串匹配的)。若是匹配被找到了,push就成功了。不匹配的訪問會被拒絕。
【帶「拒絕」的高級訪問控制】
目前,咱們只看過了許但是R,RW,或者RW+這樣子的。可是gitolite還容許另一種許可:"-"表明「拒絕」。這個給了你更多的能力,固然也有一點複雜,由於不匹配並非惟一的拒絕訪問的方法,所以規則的順序變得無關了
在前面的狀況中,咱們想要工程師能夠rewind任意branch除了master和integ。這裏是如何作到的
RW master integ = @engineers - master integ = @engineers RW+ = @engineers
你再一次簡單跟隨規則從上至下知道你找到一個匹配你的訪問模式的,或者拒絕。非rewind push到master或者integ 被第一條規則容許。一個rewind push到那些refs不匹配第一條規則,掉到第二條,所以被拒絕。任何push(rewind或非rewind)到參考或者其餘master或者integ不會被前兩條規則匹配,即被第三條規則容許
【經過改變文件限制 push】
此外限制用戶push改變到哪條branch的,你也能夠限制哪一個文件他們能夠碰的到。好比,可能Makefile (或者其餘哪些程序) 真的不能被任何人作任何改動,由於好多東西都靠着它呢,或者若是某些改變恰好不對就會崩潰。你能夠告訴 gitolite:
repo foo RW = @junior_devs @senior_devs - VREF/NAME/Makefile = @junior_devs
這是一個強力的功能寫在 conf/example.conf裏
【我的分支】
Gitolite也支持一個叫「我的分支」的功能 (或者叫「我的分支命名空間」)在合做環境裏很是有用。
在git世界裏許多代碼交換經過"pull"請求發生。然而在合做環境裏,委任制的訪問是「毫不」,一個開發者工做站不能認證,你必須push到中心服務器而且叫其餘人從那裏pull
這個一般會引發一些branch名稱簇變成像VCS裏同樣集中化,加上設置許可變成管理員的苦差事
Gitolite讓你定義一個「我的的」或者「亂七八糟的」命名空間字首給每一個開發人員(好比,refs/personal/<devname>/*);看在doc/3-faq-tips-etc.mkd裏的"personal branches"一段獲取細節
【「通配符」倉庫】
Gitolite容許你定義帶通配符的倉庫(其實仍是perl正則式),好比隨便整個例子的話assignments/s[0-9][0-9]/a[0-9][0-9]。這是一個很是有用的功能,須要經過設置$GL_WILDREPOS = 1; 在rc文件中啓用。容許你安排一個新許可模式("C")容許用戶建立倉庫基於通配符,自動分配擁有權對特定用戶——建立者,容許他交出R和RW許可給其餘合做用戶等等。這個功能在doc/4-wildcard-repositories.mkd文檔裏
【其餘功能】
咱們用一些其餘功能的例子結束這段討論,這些以及其餘功能都在"faqs, tips, etc"和其餘文檔裏
記錄:Gitolite記錄全部成功的訪問。若是你太放鬆給了別人rewind許可(RW+)和其餘孩子弄沒了"master",記錄文件會救你的命,若是其餘簡單快速的找到SHA都無論用。
訪問權報告:另外一個方便的功能是你嘗試用ssh鏈接到服務器的時候發生了什麼。Gitolite告訴你哪一個 repos你訪問過,那個訪問多是什麼。這裏是例子:
hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4 R anu-wsd R entrans R W git-notes R W gitolite R W gitolite-admin R indic_web_input R shreelipi_converter
委託:真正的大安裝,你能夠把責任委託給一組倉庫給不一樣的人而後讓他們獨立管理那些部分。這個減小了主管理者的負擔,讓他瓶頸更小。這個功能在他本身的文檔目錄裏的doc/下面
鏡像:Gitolite能夠幫助你維護多個鏡像,若是主服務器掛掉的話在他們之間很容易切換
對於提供公共的,非受權的只讀訪問,咱們能夠拋棄HTTP協議,改用Git本身的協議,這主要是出於性能和速度的考慮。Git協議遠比HTTP協議高效,於是訪問速度也快,因此它能節省不少用戶的時間
重申一下,這一點只適用於非受權的只讀訪問。若是建在防火牆以外的服務器上,那麼它所提供的服務應該只是那些公開的只讀項目。若是是在防火牆以內的服務器上,可用於支撐大量參與人員或自動系統(用於持續集成或編譯的主機)只讀訪問的項目,這樣能夠省去逐一配置SSH公鑰的麻煩
但無論哪一種情形,Git協議的配置設定都很簡單。基本上,只要以守護進程的形式運行該命令便可:
git daemon --reuseaddr --base-path=/opt/git/ /opt/git/
這裏的--reuseaddr選項表示在重啓服務前,不等以前的鏈接超時就當即重啓。而--base-path選項則容許克隆項目時沒必要給出完整路徑。最後面的路徑告訴Git守護進程容許開放給用戶訪問的倉庫目錄。假若有防火牆,則須要爲該主機的9418端口設置爲容許通訊
以守護進程的形式運行該進程的方法有不少,但主要還得看用的是什麼操做系統。在Ubuntu主機上,能夠用Upstart腳本達成。編輯該文件:
/etc/event.d/local-git-daemon
加入如下內容:
start on startup stop on shutdown exec /usr/bin/git daemon \ --user=git --group=git \ --reuseaddr \ --base-path=/opt/git/ \ /opt/git/ respawn
出於安全考慮,強烈建議用一個對倉庫只有讀取權限的用戶身份來運行該進程——只須要簡單地新建一個名爲git-ro的用戶
新建用戶默認對倉庫文件不具有寫權限,但這取決於倉庫目錄的權限設定。務必確認git-ro對倉庫只能讀不能寫,並用它的身份來啓動進程。這裏爲了簡化,後面咱們仍是用之運行Gitosis的用戶'git'
這樣一來,當你重啓計算機時,Git進程也會自動啓動。要是進程意外退出或者被殺掉,也會自行重啓。在設置完成後,不重啓計算機就啓動該守護進程,能夠運行:
initctl start local-git-daemon
而在其餘操做系統上,能夠用xinetd,或者sysvinit系統的腳本,或者其餘相似的腳本——只要能讓那個命令變爲守護進程並可監控
接下來,咱們必須告訴Gitosis哪些倉庫容許經過Git協議進行匿名只讀訪問。若是每一個倉庫都設有各自的段落,能夠分別指定是否容許Git進程開放給用戶匿名讀取。好比容許經過Git協議訪問iphone_project,能夠把下面兩行加到gitosis.conf文件的末尾:
[repo iphone_project]
daemon = yes
在提交和推送完成後,運行中的Git守護進程就會響應來自9418端口對該項目的訪問請求。
若是不考慮Gitosis,單單起了Git守護進程的話,就必須到每個容許匿名只讀訪問的倉庫目錄內,建立一個特殊名稱的空文件做爲標誌:
$ cd /path/to/project.git
$ touch git-daemon-export-ok
該文件的存在,代表容許 Git 守護進程開放對該項目的匿名只讀訪問。
Gitosis還能設定哪些項目容許放在GitWeb上顯示。打開GitWeb的配置文件/etc/gitweb.conf,添加如下四行
$projects_list = "/home/git/gitosis/projects.list"; $projectroot = "/home/git/repositories"; $export_ok = "git-daemon-export-ok"; @git_base_url_list = ('git://gitserver');
接下來,只要配置各個項目在Gitosis中的gitweb參數,便能達成是否容許GitWeb用戶瀏覽該項目。好比,要讓iphone_project項目在GitWeb裏出現,把repo的設定改爲下面的樣子:
[repo iphone_project] daemon = yes gitweb = yes
在提交併推送過以後,GitWeb就會自動開始顯示iphone_project項目的細節和歷史