歡迎光臨
每天分享高質量文章

搭建自己的 Git 伺服器

根據 RhodeCode[1] 在 2016 年做過的一項分析報告 Version Control Systems Popularity in 2016[2],在如今的 VCS(版本控制系統)領域,Git 幾乎已經一統江山,在選擇自己的 VCS 時,有 87% 的人會選擇使用 Git,排在第二名的 SVN 只佔 6%,無論是從 Google Trends,還是在 Stack Overflow 上的提問,都可以看到 Git 的爆髮式增長。另外,根據 Eclipse 的社群調查 (Eclipse Community Survey),在 2010 年前後,SVN 的使用率都遠超其他幾款 VCS,從 2010 年開始,SVN 的使用率開始快速下滑,相應的,Git 的使用率快速上升,併在 2014 年超過了 SVN。 
現在,Git 已經成為了程式員的必備技能,越來越多的企業開始採用 Git。在開源的世界裡,GitHub 是程式員聚集的狂歡之地,但這並不適合企業的私有專案,雖然 GitHub 也支援建立私有專案,但是搭建一個自己的 Git 伺服器在很多時候可能是更好的選擇,這篇部落格將介紹並學習幾種搭建 Git 伺服器的方法。
Git 支援四種不同的傳輸協議:本地協議(Local)、HTTP(S) 協議、SSH(Secure Shell)協議以及 Git 協議,這四種協議在不同的場合有不同的用途,並且各有利弊,可以根據實際情況來選擇。
一、本地協議

 

本地協議是 Git 最基本的協議,當我們想在本地做一些 Git 實驗時,這將非常有用。我們首先建立兩個目錄:/git/repo 和 ~/working,前者作為遠端版本庫,後者作為本地工作目錄。
  1. aneasystone@little-stone:~$ sudo mkdir -p /git/repo
  2. aneasystone@little-stone:~$ sudo git init --bare /git/repo/test.git
  3. 已初始化空的 Git 倉庫於 /git/repo/test.git/
我們在 /git/repo 目錄透過 git init –bare 命令建立一個裸倉庫(bare repository,即一個不包含當前工作目錄的倉庫),只要這一步,我們就可以開始使用了。接著我們在工作目錄 clone 這個版本庫:
  1. aneasystone@little-stone:~$ cd ~/working/
  2. aneasystone@little-stone:~/working$ git clone /git/repo/test.git
  3. 正克隆到 'test'...
  4. warning: 您似乎克隆了一個空倉庫。
  5. 完成。
然後我們可以使用 pull、push 就像操作其他的版本庫一樣。
  1. aneasystone@little-stone:~/working$ cd test/
  2. aneasystone@little-stone:~/working/test$ touch 1
  3. aneasystone@little-stone:~/working/test$ touch 2
  4. aneasystone@little-stone:~/working/test$ git add .
  5. aneasystone@little-stone:~/working/test$ git commit -m 'first commit'
  6. [master (根提交) 4983f84] first commit
  7. 2 files changed, 0 insertions(+), 0 deletions(-)
  8. create mode 100644 1
  9. create mode 100644 2
  10. aneasystone@little-stone:~/working/test$ sudo git push
  11. [sudo] aneasystone 的密碼:
  12. 物件計數中: 3, 完成.
  13. Delta compression using up to 8 threads.
  14. 壓縮物件中: 100% (2/2), 完成.
  15. 寫入物件中: 100% (3/3), 205 bytes | 205.00 KiB/s, 完成.
  16. Total 3 (delta 0), reused 0 (delta 0)
  17. To /git/repo/test.git
  18. * [new branch]      master -> master
本地協議不僅在做 Git 實驗時很有用,如果你的團隊有一個共享檔案系統,可以在這個共享檔案系統上建立一個遠端版本庫,團隊成員把這個共享檔案系統掛在本地,就可以直接使用本地協議進行協作開發,完全不需要搭建一臺專門的 Git 伺服器。
二、SSH 協議

 

本地協議雖然簡單,但是一般來說並不適用,因為你無法控制使用者對共享檔案系統的操作,使用者擁有 push 許可權也就意味著使用者對遠端目錄擁有完整的 Shell 許可權,他們有可能會無意甚至有意的修改或刪除 Git 內部檔案,損壞 Git 倉庫。
更安全的做法是使用專門的 Git 伺服器,如果你有一臺可以使用 SSH 連線的伺服器,搭建 Git 服務將會非常簡單。首先我們要確保伺服器上執行著 SSH 服務(sshd),大多數 Linux 伺服器版本都預設包含了該服務,如果沒有,可以先安裝 openssh-server。然後在伺服器上建立 Git 遠端版本庫:
  1. root@myserver:~# mkdir -p /git/repo
  2. root@myserver:~# git init --bare /git/repo/test.git
  3. 已初始化空的 Git 倉庫於 /git/repo/test.git/
然後在本地 clone 這個版本庫:
  1. aneasystone@little-stone:~/working$ git clone ssh://root@myserver/git/repo/test.git
  2. 正克隆到 'test'...
  3. root@myserver's password:
  4. warning: 您似乎克隆了一個空倉庫。
可以看到和使用本地協議幾乎一樣,不同的地方在於,在 clone 的時候需要在 URL 前面加上 ssh://root@myserver,你也可以使用 scp 式的寫法:
  1. $ git clone root@myserver:/git/repo/test.git
另外一點不同的地方是,每次 pull、push 的時候都需要輸入遠端伺服器的 root 密碼。很顯然,讓每個 Git 使用者都使用 root 來訪問伺服器是一種很不安全的做法,有幾種方法可以解決這個問題:
  • 最顯而易見的方法是為每個 Git 使用者建立一個獨立的賬號,並分別為他們分配對倉庫的讀寫許可權,這種方法行的通,但是對賬號的管理非常麻煩,在團隊人員不是很多的時候可以嘗試,但是並不推薦;

  • 另一種方法是配置 SSH 伺服器使用某個已有的認證系統來管理使用者,比如 LDAP,這在很多企業中是很常見的,這樣可以省去用 adduser 手工管理伺服器賬號的麻煩;

  • 還有一種方法是隻建立一個賬號,比如叫做 Git,他對倉庫具有讀寫許可權,大家都使用這個賬號來訪問倉庫。這種方法的好處是使用者管理起來比較簡單,而且可以使用後面介紹的 authorized_keys 檔案對使用者的公鑰進行管理。

 

下麵我們嘗試下第三種方法。首先在伺服器上建立一個名叫 Git 的賬號:
  1. root@myserver:~# adduser git
  2. Adding user `git' ...
  3. Adding new group `git' (1000) ...
  4. Adding new user `git' (1000) with group `git' ...
  5. Creating home directory `/home/git' ...
  6. Copying files from `/etc/skel' ...
  7. Enter new UNIX password:
  8. Retype new UNIX password:
  9. passwd: password updated successfully
  10. Changing the user information for git
  11. Enter the new value, or press ENTER for the default
  12.    Full Name []: git
  13.    Room Number []:  
  14.    Work Phone []:
  15.    Home Phone []:
  16.    Other []:
  17. Is the information correct? [Y/n] Y
再設定一下 Git 倉庫的許可權(預設情況下,Git 倉庫的許可權為 rwxr-xr-x,只有建立者 root 有寫的許可權,也就意味著使用 Git 賬號只能 clone pull,不能 push):
  1. # chmod a+w -R /git/repo/test.git
我們這裡非常粗暴的使用 chmod a+w 將 Git 倉庫設定為對所有人可寫,這裡可以想一想,如果我們希望設定某些使用者對倉庫具有隻讀的許可權,該怎麼做呢?
然後就可以在本地愉快的進行 Git 操作了:
  1. $ git clone git@myserver:/git/repo/test.git
到這裡似乎一切都很正常,但是幾次實操之後你就會發現,每次 Git 操作都要輸入一次密碼,這也太麻煩了,能不能“免密提交程式碼”呢?首先我們要知道,只要能透過 SSH 登陸到伺服器,我們就能操作 Git,所以如果 SSH 能支援免密登陸,我們就可以“免密提交程式碼”。還好,SSH 支援公鑰認證,這種認證方式無需密碼登陸。在 Linux 作業系統中,每個使用者都可以擁有自己的一個或多個金鑰對(公鑰和私鑰成對出現),這些金鑰一般情況會儲存在 ~/.ssh 目錄下,在開始之前,我們先確認下自己是否已經生成過公鑰了,可以看下這個目錄下是否有 iddsa.pub 或 idrsa.pub 這樣的檔案,如果沒有,我們透過 ssh-keygen 來生成:
  1. aneasystone@little-stone:~/.ssh$ ssh-keygen
  2. Generating public/private rsa key pair.
  3. Enter file in which to save the key (/home/aneasystone/.ssh/id_rsa):
  4. Enter passphrase (empty for no passphrase):
  5. Enter same passphrase again:
  6. Your identification has been saved in /home/aneasystone/.ssh/id_rsa.
  7. Your public key has been saved in /home/aneasystone/.ssh/id_rsa.pub.
  8. The key fingerprint is:
  9. SHA256:4Ulpufuhs/AgDMb0VXnqMUTw6bD/HrAOI2z9c1cod9I aneasystone@little-stone
  10. The key's randomart image is:
  11. +---[RSA 2048]----+
  12. |      .oo.       |
  13. |       oo+.      |
  14. |  .   o.Oo       |
  15. | o . . B++       |
  16. |  + . ..So   o   |
  17. | . + . ..+. + E  |
  18. |    * * + oo +   |
  19. |   . o Oo+.o.    |
  20. |        **+.     |
  21. +----[SHA256]-----+
這樣我們在 ~/.ssh 目錄生成了兩個檔案,idrsa 是你的私鑰,idrsa.pub 是你的公鑰。關於私鑰和公鑰的原理以及 RSA 加密演演算法等內容可以參考我之前寫過的一篇介紹 HTTPS 和證書[3]的文章。
我們假設你的 Git 伺服器是由專門的伺服器管理員負責維護和管理,當你生成你的公鑰之後,就可以給伺服器管理員傳送一封申請 Git 服務的郵件,並附上你的公鑰。伺服器管理員在收到你的申請之後,如果同意了,就可以進行下麵的操作:
首先將公鑰檔案複製到伺服器上:
  1. # scp id_rsa.pub root@myserver:/home/git
將公鑰檔案的內容追加到 Git 賬戶的 authorizedkeys 檔案中(要註意的是,如果是第一次操作,/home/git 目錄下是沒有 .ssh 目錄的,需要手工建立 .ssh 目錄和 authorizedkeys 檔案):
  1. root@myserver:/home/git# cat id_rsa.pub >> /home/git/.ssh/authorized_keys
後續如果有其他的使用者申請 Git 服務,都可以按照這個步驟操作。一旦完成這個操作,伺服器管理員將會回覆你的郵件,通知你 Git 服務已經開通,這個時候你再進行 Git 操作就可以不用輸入密碼了。關於 SSH 的使用,更詳細的步驟可以參考 GitHub 上的這篇指南:Connecting to GitHub with SSH[4]。
作為伺服器管理員,關於 SSH 還有一點需要考慮,那就是 SSH 的安全問題。在上面介紹本地協議時,我們說這種方式無法控制使用者對 Git 倉庫的操作,無法防止使用者有意或無意的損壞 Git 倉庫,使用 SSH 協議一樣存在這樣的問題,使用者能透過 SSH 拉取和提交程式碼,也就意味著使用者可以透過 SSH 連線到伺服器,對 Git 倉庫進行任何操作,這是一件很讓人擔心的事情。
因此,我們還需要對 Git 賬號做一些限制。預設情況下,我們新建賬號的登陸 shell 是 /bin/bash,這個配置在 /etc/passwd 檔案中:
  1. git:x:1000:1000:git,,,:/home/git:/bin/bash
可以使用 chsh 命令修改使用者的登陸 shell,讓他不能透過 SSH 訪問伺服器,怎麼修改呢?我們可以看一下 /etc/shells 檔案,這裡定義了所有可以使用的登陸 shell,你可以將 /bin/bash 改成這裡的任何一個:
  1. root@myserver:~# cat /etc/shells
  2. # /etc/shells: valid login shells
  3. /bin/sh
  4. /bin/dash
  5. /bin/bash
  6. /bin/rbash
很顯然,這些 shell 並不是我們想要的,有沒有一個 shell 只允許使用者進行 Git 操作,而不允許其他操作呢?還好,Git 的軟體包提供了一個名叫 git-shell 的登陸 shell,我們可以把他加進去,一般情況下位於 /usr/bin/git-shell。我們使用 chsh 修改 Git 的登陸 shell:
  1. root@myserver:~# chsh git
  2. Changing the login shell for git
  3. Enter the new value, or press ENTER for the default
  4.    Login Shell [/bin/bash]: /usr/bin/git-shell
這樣當使用者 Git 透過 SSH 連線伺服器時,就會直接被拒絕了。
三、Git 協議

 

SSH 協議解決了使用者直接操作 Git 倉庫的許可權問題,但是如果我們希望對除倉庫維護者之外的所有人都開放 Git 倉庫的只讀許可權,這在開源專案中和企業內部往往是很常見的,任何人都可以去檢視倉庫的程式碼,這時管理員需要給每一個使用者配置 SSH 金鑰是非常麻煩的。雖然也可以使用變通的方法來達到這個效果,但是很繁瑣,下麵是具體的步驟:
  • 使用 g+w 設定 Git 倉庫的許可權,讓倉庫建立者所在的使用者組具有寫許可權,而不是所有人都有寫許可權(這一步通常也可以在 git init 的時候加上 –shared 引數);

  • 然後將 Git 賬號加到倉庫建立者的使用者組;

  • 再建立一個 git_ro 賬戶,這個賬戶對倉庫只有隻讀許可權;

  • 最後為 gitro 賬戶建立一個金鑰對,把 gitro 的私鑰公開出來供所有人使用。

可以看到使用 SSH 協議最終都逃不過授權這一步,而且公開私鑰的做法也不是很優雅。實際上,Git 提供了另一種方式來讓這個操作更簡單,那就是 Git 協議。使用 Git 協議必須要在伺服器上執行 Git 守護行程,Git 命令自帶了一個 daemon 引數:
  1. root@myserver:~# git daemon --reuseaddr --base-path=/git/repo/ /git/repo/
上面的各個引數可以 參考 git-daemon[5] 的檔案。git-daemon 會監聽 9418 埠,如果你的伺服器有防火牆,需要將該埠新增到白名單,如果你使用的是阿裡雲伺服器,需要像下麵這樣新增一個安全組規則: 
為了讓所有的使用者都可以訪問我們的倉庫,還需要在倉庫目錄下建立一個名為 git-daemon-export-ok 的檔案:
  1. root@myserver:~# cd /git/repo/test.git/
  2. root@myserver:/git/repo/test.git/# touch git-daemon-export-ok
至此,所有人都可以透過 Git 協議來克隆或拉取專案原始碼了(註意上面指定了 base-path 引數為 /git/repo/,所以 URL 可以直接寫 git://myserver/test.git):
  1. aneasystone@little-stone:~/working$ git clone git://myserver/test.git
一般情況下,伺服器管理員還會做一些其他的配置,譬如在伺服器重啟時讓 Git 守護行程自動啟動,這有很多種方式可以實現,可以參考《Pro Git[6]》 Git 守護行程這一節的內容。
四、HTTP(S) 協議

 

我們一般透過 Git 協議進行無授權訪問,透過 SSH 協議進行授權訪問,如果你的專案是內部專案,只針對部分授權使用者,那使用 SSH 協議就足夠了,但是如果既需要授權訪問也需要無授權訪問,可能需要 SSH 協議和 Git 協議搭配使用,這在維護上成本很高。這時就到了我們的壓軸戲 —— HTTP 協議出場的時候了,它同時支援上面兩種訪問方式。
透過 HTTP 協議訪問 Git 服務是目前使用最廣泛的方式,它支援兩種樣式:舊版本的 Dumb HTTP 和 新版本的 Smart HTTP,Dumb HTTP 一般很少使用,下麵除非特殊說明,所說的 HTTP 協議都是 Smart HTTP。使用 HTTP 協議的好處是可以使用各種 HTTP 認證機制,比如使用者名稱/密碼,這比配置 SSH 金鑰要簡單的多,對普通使用者來說也更能接受。如果擔心資料傳輸安全,也可以配置 HTTPS 協議,這和普通的 Web 服務是一樣的。
下麵我們就來嘗試搭建一個基於 HTTP 協議的 Git 伺服器。《Pro Git》上提供了一個基於 Apache 的配置示例,如果你是使用 Apache 作為 Web 伺服器,可以參考之,我們這裡使用 Nginx 來作為 Web 伺服器,其原理本質上是一樣的,都是透過 Web 伺服器接受 HTTP 請求,並將請求轉發到 Git 自帶的一個名為 git-http-backend 的 CGI 指令碼。
首先我們安裝所需的軟體:
  1. # apt-get install -y git-core nginx fcgiwrap apache2-utils
其中,Nginx 作為 Web 伺服器,本身是不能執行外部 CGI 指令碼的,需要透過 FcgiWrap來中轉,就像使用 php-fpm 來執行 PHP 指令碼一樣。apache2-utils 是 Apache 提供的一個 Web 伺服器的工具集,包含了一些有用的小工具,譬如下麵我們會用到的 htpasswd 可以生成 Basic 認證檔案。
啟動 Nginx 和 FcgiWrap,並訪問 http://myserver 測試 Web 伺服器是否能正常訪問:
  1. # service nginx start
  2. # service fcgiwrap start
然後我們開啟並編輯 Nginx 的配置檔案(/etc/nginx/sites-available/default):
  1. location / {
  2.        include fastcgi_params;
  3.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
  4.        fastcgi_param GIT_HTTP_EXPORT_ALL "";
  5.        fastcgi_param GIT_PROJECT_ROOT /git/repo;
  6.        fastcgi_param PATH_INFO $uri;
  7.        fastcgi_param REMOTE_USER $remote_user;
  8.        fastcgi_pass unix:/var/run/fcgiwrap.socket;
  9. }
這裡透過 fastcgi_param 設定了一堆的 FastCGI 引數,如下:
  • SCRIPT_FILENAME:指定 CGI 指令碼 git-http-backend 的位置,表示每次 HTTP 請求會被轉發到該 CGI 指令碼;

  • GITHTTPEXPORTALL:git-http-backend 預設只能訪問目錄下有 git-daemon-export-ok 檔案的 Git 倉庫,和上面介紹的 Git 協議是一樣的,如果指定了 GITHTTPEXPORTALL,表示允許訪問所有倉庫;

  • GITPROJECTROOT:Git 倉庫的根目錄;

  • REMOTE_USER:如果有認證,將認證的使用者資訊傳到 CGI 指令碼;

改完之後我們重啟 Nginx,並透過 HTTP 協議 clone 倉庫:
  1. aneasystone@little-stone:~/working$ git clone http://myserver/test.git
4.1 開啟身份認證
到這裡一切 OK,但是當我們 push 程式碼的時候,卻會報下麵的 403 錯誤:
  1. aneasystone@little-stone:~/working/test$ git push origin master
  2. fatal: unable to access 'http://myserver/test.git/': The requested URL returned error: 403
為瞭解決這個錯誤,我們可以在 git-http-backend 的官網檔案上找到這樣的一段描述:
By default, only the upload-pack service is enabled, which serves git fetch-pack and git ls-remote clients, which are invoked from git fetch, git pull, and git clone. If the client is authenticated, the receive-pack service is enabled, which serves git send-pack clients, which is invoked from git push.
第一次讀這段話可能會有些不知所云,這是因為我們對這裡提到的 upload-pack、fetch-pack、receive-pack、send-pack 這幾個概念還沒有什麼認識。但是我們大抵可以猜出來,預設情況下,只有認證的使用者才可以 push 程式碼,如果某個 Git 倉庫希望所有使用者都有許可權 push 程式碼,可以為相應的倉庫設定 http.receivepack:
  1. root@myserver:/# cd /git/repo/test.git/
  2. root@myserver:/git/repo/test.git# git config http.receivepack true
當然最好的做法還是對 push 操作開啟認證,官網檔案上有一個 lighttpd 的配置我們可以借鑒:
  1. $HTTP["querystring"] =~ "service=git-receive-pack" {
  2.    include "git-auth.conf"
  3. }
  4. $HTTP["url"] =~ "^/git/.*/git-receive-pack$" {
  5.    include "git-auth.conf"
  6. }
這個配置看上去非常簡單,但是想要理解為什麼這樣配置,就必須去瞭解下 Git 的內部原理。正如上面 git-http-backend 檔案上的那段描述,當 Git 客戶端執行 git fetch,git pull,and git clone 時,會呼叫 upload-pack 服務,當執行 git push 時,會呼叫 receive-pack 服務,為了更清楚的說明這一點,我們來看看 Nginx 的訪問日誌。
執行 git clone:
  1. [27/Nov/2018:22:18:00] "GET /test.git/info/refs?service=git-upload-pack HTTP/1.1" 200 363 "-" "git/1.9.1"
  2. [27/Nov/2018:22:18:00] "POST /test.git/git-upload-pack HTTP/1.1" 200 306 "-" "git/1.9.1"
執行 git pull:
  1. [27/Nov/2018:22:20:25] "GET /test.git/info/refs?service=git-upload-pack HTTP/1.1" 200 363 "-" "git/1.9.1"
  2. [27/Nov/2018:22:20:25] "POST /test.git/git-upload-pack HTTP/1.1" 200 551 "-" "git/1.9.1"
執行 git push:
  1. [27/Nov/2018:22:19:33] "GET /test.git/info/refs?service=git-receive-pack HTTP/1.1" 401 204 "-" "git/1.9.1"
  2. admin [27/Nov/2018:22:19:33] "GET /test.git/info/refs?service=git-receive-pack HTTP/1.1" 200 193 "-" "git/1.9.1"
  3. admin [27/Nov/2018:22:19:33] "POST /test.git/git-receive-pack HTTP/1.1" 200 63 "-" "git/1.9.1"
可以看到執行 clone 和 pull 請求的介面是一樣的,先請求 /info/refs?service=git-upload-pack,然後再請求 /git-upload-pack;而 push 是先請求 /info/refs?service=git-receive-pack,然後再請求 /git-receive-pack,所以在上面的 lighttpd 的配置中我們看到了兩條記錄,如果要對 push 做訪問控制,那麼對這兩個請求都要限制。關於 Git 傳輸的原理可以參考 《Pro Git》的 Git 內部原理 – 傳輸協議這一節。
我們依葫蘆畫瓢,Nginx 配置檔案如下:
  1. location @auth {
  2.        auth_basic "Git Server";
  3.        auth_basic_user_file /etc/nginx/passwd;
  4.        include fastcgi_params;
  5.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
  6.        fastcgi_param GIT_HTTP_EXPORT_ALL "";
  7.        fastcgi_param GIT_PROJECT_ROOT /git/repo;
  8.        fastcgi_param PATH_INFO $uri;
  9.        fastcgi_param REMOTE_USER $remote_user;
  10.        fastcgi_pass unix:/var/run/fcgiwrap.socket;
  11. }
  12. location / {
  13.        error_page 418 = @auth;
  14.        if ( $query_string = "service=git-receive-pack" ) {  return 418; }
  15.        if ( $uri ~ "git-receive-pack$" ) { return 418; }
  16.        include fastcgi_params;
  17.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
  18.        fastcgi_param GIT_HTTP_EXPORT_ALL "";
  19.        fastcgi_param GIT_PROJECT_ROOT /git/repo;
  20.        fastcgi_param PATH_INFO $uri;
  21.        fastcgi_param REMOTE_USER $remote_user;
  22.        fastcgi_pass unix:/var/run/fcgiwrap.socket;
  23. }
其中相同的配置我們也可以用 include 指令放在一個共用的配置檔案裡,這樣我們就實現了在 push 的時候需要填寫使用者名稱和密碼了。我們透過 Nginx 的 authbasicuser_file 指令來做身份認證,使用者名稱和密碼儲存在 /etc/nginx/passwd 檔案中,這個檔案可以使用上面提到的 apache2-utils 包裡的 htpasswd 來生成:
  1. root@myserver:/# htpasswd -cb /etc/nginx/passwd admin 123456
另外,在 push 的時候,有時候可能會遇到 unpack failed: unable to create temporary object directory 這樣的提示錯誤:
  1. aneasystone@little-stone:~/working/test$ git push origin master
  2. Counting objects: 3, done.
  3. Writing objects: 100% (3/3), 193 bytes | 0 bytes/s, done.
  4. Total 3 (delta 0), reused 0 (delta 0)
  5. error: unpack failed: unable to create temporary object directory
  6. To http://myserver/test.git
  7. ! [remote rejected] master -> master (unpacker error)
  8. error: failed to push some refs to 'http://myserver/test.git'
這一般情況下都是由於 Git 倉庫目錄的許可權問題導致的,在這裡 Git 倉庫的根目錄 /git/repo 是 root 建立的,而執行 nginx 和 fcgiwrap 的使用者都是 www-data,我們可以把 Git 倉庫目錄設定成對所有人可讀可寫,也可以像下麵這樣將它的擁有者設定成 www-data 使用者:
  1. root@myserver:/# chown -R www-data:www-data /git/repo
4.2 憑證管理
上面我們站在管理員的角度解決了使用者身份認證的問題,但是站在使用者的角度,每次提交程式碼都要輸入使用者名稱和密碼是一件很痛苦的事情。在上面介紹 SSH 協議時,我們可以使用 SSH 協議自帶的公鑰認證機制來省去輸入密碼的麻煩,那麼在 HTTP 協議中是否存在類似的方法呢?答案是肯定的,那就是 Git 的憑證儲存工具:credential.helper。
譬如像下麵這樣,將使用者名稱和密碼資訊儲存在快取中:
  1. $ git config --global credential.helper cache
這種方式預設只保留 15 分鐘,如果要改變保留的時間,可以透過 –timeout 引數設定,或者像下麵這樣,將密碼儲存在檔案中:
  1. $ git config --global credential.helper store
這種方式雖然可以保證密碼不過期,但是要記住的是,這種方式密碼是以明文的方式儲存在你的 home 目錄下的。可以借鑒作業系統自帶的憑證管理工具來解決這個問題, 比如 OSX Keychain 或者 Git Credential Manager for Windows。更多的內容可以參考《Pro Git》憑證儲存這一節。
除此之外,還有一種更簡單粗暴的方式:
  1. aneasystone@little-stone:~/working$ git clone http://admin:123456@myserver/test.git
五、綜合對比

 

這一節對 Git 的四大協議做一個綜合對比。
本地協議
  • 優點:架設簡單,不依賴外部服務,直接使用現有檔案和網路許可權,常用於共享檔案系統

  • 缺點:共享檔案系統的配置和使用不方便,且無法保護倉庫被意外損壞,傳輸效能較低

SSH 協議
  • 優點:架設簡單,所有資料經過授權加密,資料傳輸很安全,傳輸效能很高

  • 缺點:不支援匿名訪問,配置 SSH 的金鑰對小白使用者有一定的門檻

Git 協議
  • 優點:對開放的專案很適用,無需授權,傳輸效能最高

  • 缺點:缺乏授權機制,架設較麻煩,企業一般不會預設開放 9418 埠需要另行新增

HTTP/S 協議
  • 優點:同時支援授權訪問和無授權訪問,傳輸效能較高,配合 HTTPS 也可以實現資料安全

  • 缺點:架設 HTTP 服務較麻煩,認證憑證不好管理

六、更高階的工具

 

上面介紹的是搭建 Git 伺服器最基本的方法,如果你只是希望能找一個版本控制系統來替代現有的 SVN,這也許就足夠了。但如果你希望你的版本控制系統能擁有一個更友好的 UI 介面,能更好的管理你的使用者和許可權,能支援更現代的 Pull Request 功能以及能和 CI/CD 系統更緊密的聯絡起來,你就需要一個更高階的工具,你可以試試 GitWeb、Gitolite、GitLab、Gogs、Gitea,當然,如果你願意,你也可以把程式碼放在那些流行的程式碼託管平臺上,比如 GitHub 等等。
相關連結:
  1. https://rhodecode.com/

  2. https://rhodecode.com/insights/version-control-systems-2016

  3. http://www.aneasystone.com/archives/2016/04/java-and-https.html

  4. https://help.github.com/articles/connecting-to-github-with-ssh/

  5. https://git-scm.com/docs/git-daemon

  6. https://git-scm.com/book/zh/v2

     

原文連結:https://www.aneasystone.com/archives/2018/12/build-your-own-git-server.html

贊(0)

分享創造快樂