碼雲已經支持 Git Wire Protocol 頂 原 薦

前言

兩個半月前,Google 開發者宣佈了 Git Wire Protocol,即 Git v2 協議,Git Wire Protocol 協議改進了 Git 的傳輸過程,增加了可擴展性。關於協議的背景和細節介紹,大家可以去 《碼雲即將支持 Git v2 Protocol》 瞭解。

進展

兩個多月過去了,我們可以大聲的告訴大家,碼雲目前已經支持 Git Wire Protocol。

碼雲的 Git SSH 服務器並不是 OpenSSH,而是基於 libssh 開發的一個服務,叫 Basalt Sshd。用戶可以通過使用命令:

ssh -Tvvv [email protected]

在命令輸出裏面可以找到類似下面的字符串。

debug1: Remote protocol version 2.0, remote software version Basalt-1.2

對碼雲比較瞭解的朋友應該知道,碼雲目前已經完全改造成分佈式了,而 Basalt 是碼雲的 SSH 服務,它需要與存儲機器上的 git-srv 建立連接,無論是 fetch 還是 push,碼雲都是通過啓動 git 命令實現的,這樣的好處是能夠享受 git 改進帶來的性能優勢和增加的新功能。這一點,無論是 libgit2 還是 JGIT 都並不容易做到的。

分析了碼雲平臺 Git 傳輸的架構,那麼就可以知道如何實現對 Git Wire Protocol 的支持,首先得讓 Basalt 接受環境變量,然後得傳遞給 git-srvgit-srv 在啓動的時候設置 git 命令的環境變量即可,很簡單嗎,沒有一點難度。當然需要等待 git 2.18 的發佈,碼雲在計劃支持 Git Wire Protocol 就等了一段時間。

在 libssh 的 channel_env_request_function callback 中就可以接受環境變量,這裏就可以得知請求是否是 v2 的,在 git-srv 中,我們在傳輸數據之前有個 Handshake 階段,在 Handshake 數據包中增加一個字段即可。

等到 git 2.18 發佈後,我們將所有後端服務器上的 Git 升級到 2.18,然後升級所有的 git-srv,最後把 Basalt 升級了,然後就支持 Git Wire Protocol 了。

我們使用 git-dist 升級的 git/cmake。

# update git
bash <(curl -fsSL https://gitee.com/oscstudio/git-dist/raw/master/git-dist.sh)
# update cmake
bash <(curl -fsSL https://gitee.com/oscstudio/git-dist/raw/master/cmake.sh)

以上是 SSH,那麼 HTTP,GIT 呢?

在碼雲的設計中,HTTP 也應當直接與 git-srv 通訊,而在 Gitlab 中,提供 Git HTTP 功能的是 grack,但 Gitlab 都有幾年沒有維護 Grack 了,他們已經使用 gitaly 了,雖然碼雲也將完全去除 grack,但由於各種各樣的原因,目前依然使用 grack 提供 Git HTTP 訪問。爲了讓開發者及早的體驗 Git Wire Protocol,筆者一個非 Ruby 開發人員不情願的改進了 Grack: https://gitee.com/oscstudio/grack 。如果哪一天你使用 HTTP 體驗了 Git Wire Protocol,那就說明我們更新了。

git:// 協議沒有驗證機制,爲了避免惡意請求,我們也就沒有開放 git:// 協議,但我們內部同步使用了 git:// 協議,並且也在第一時間支持了 Git Wire Protocol.

如何使用

我們可以設置 git config,使默認的傳輸使用 v2。

針對存儲庫的設置:git config protocol.version=2
針對全局設置: git config --global protocol.version=2

git 實際上可以使用 -c 去強制指定一些設置,所以可以使用 git -c protocol.version=2 clone url 這樣的格式去使用 v2 協議去克隆或者操作 git 存儲庫。

如果已經碼雲上已經有存儲庫了,可以使用 ls-remote 查看 Git Wire Protocol 細節。

GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote

這是 oscstudio/grack 的輸出:

15:52:27.525041 git.c:415               trace: built-in: git ls-remote
15:52:27.525181 run-command.c:637       trace: run_command: unset GIT_CONFIG_PARAMETERS GIT_PREFIX; GIT_PROTOCOL=version=2 ssh -o SendEnv=GIT_PROTOCOL [email protected] 'git-upload-pack '\''oscstudio/grack.git'\'''
15:52:27.941054 pkt-line.c:80           packet:          git< version 2
15:52:27.941085 pkt-line.c:80           packet:          git< agent=git/2.18.0
15:52:27.941091 pkt-line.c:80           packet:          git< ls-refs
15:52:27.941096 pkt-line.c:80           packet:          git< fetch=shallow
15:52:27.941101 pkt-line.c:80           packet:          git< server-option
15:52:27.941107 pkt-line.c:80           packet:          git< 0000
15:52:27.941113 pkt-line.c:80           packet:          git> command=ls-refs
15:52:27.941127 pkt-line.c:80           packet:          git> agent=git/2.18.0
15:52:27.941133 pkt-line.c:80           packet:          git> 0001
15:52:27.941150 pkt-line.c:80           packet:          git> peel
15:52:27.941156 pkt-line.c:80           packet:          git> symrefs
15:52:27.941160 pkt-line.c:80           packet:          git> 0000
15:52:27.967209 pkt-line.c:80           packet:          git< 715a91a2b22de70a78ba7e0cda2e36a65885184b HEAD symref-target:refs/heads/master
15:52:27.989776 pkt-line.c:80           packet:          git< 642cbc5f73d6eb1947f3120e48cd8c401dd66961 refs/fetches/wenjiachengy/wire_debug
15:52:27.989817 pkt-line.c:80           packet:          git< d77535c7d2892fede73f957d7041e66f6196c1da refs/heads/dev
15:52:27.989829 pkt-line.c:80           packet:          git< 715a91a2b22de70a78ba7e0cda2e36a65885184b refs/heads/master
15:52:27.989866 pkt-line.c:80           packet:          git< 94fafdc22aecf4561a7a94bd76a97336ab845654 refs/heads/stderr
15:52:27.989883 pkt-line.c:80           packet:          git< 715a91a2b22de70a78ba7e0cda2e36a65885184b refs/heads/wire
15:52:28.005575 pkt-line.c:80           packet:          git< 9795dec8d00c9c402ebf3db9e9d0f637d4f9dd6f refs/heads/wire_debug
15:52:28.033921 pkt-line.c:80           packet:          git< 34eb1b8d0be0398044b45660effb9cfa21f2f324 refs/pull/1/MERGE
15:52:28.033973 pkt-line.c:80           packet:          git< 36053e3bed3c355b0f184138df4d5e97a66a529a refs/tags/v0.1 peeled:623bc4f455bca96a6431e20babb436974417a5fc
15:52:28.033992 pkt-line.c:80           packet:          git< 30d8963cefb373b9ccc10caebc80859f7e32ca28 refs/tags/v0.2 peeled:5295cd7b31a85197949c9f348210965907c7214b
15:52:28.034013 pkt-line.c:80           packet:          git< eac92e5bd234f6a42db3f63a55c6909311ac998d refs/tags/v1.0.0
15:52:28.034032 pkt-line.c:80           packet:          git< a6c716e02da853e811b96e6a6c37e21ec893a06a refs/tags/v2.0.0
15:52:28.034047 pkt-line.c:80           packet:          git< 0000
15:52:28.034060 pkt-line.c:80           packet:          git> 0000
From [email protected]:oscstudio/grack.git
715a91a2b22de70a78ba7e0cda2e36a65885184b	HEAD
642cbc5f73d6eb1947f3120e48cd8c401dd66961	refs/fetches/wenjiachengy/wire_debug
d77535c7d2892fede73f957d7041e66f6196c1da	refs/heads/dev
715a91a2b22de70a78ba7e0cda2e36a65885184b	refs/heads/master
94fafdc22aecf4561a7a94bd76a97336ab845654	refs/heads/stderr
715a91a2b22de70a78ba7e0cda2e36a65885184b	refs/heads/wire
9795dec8d00c9c402ebf3db9e9d0f637d4f9dd6f	refs/heads/wire_debug
34eb1b8d0be0398044b45660effb9cfa21f2f324	refs/pull/1/MERGE
36053e3bed3c355b0f184138df4d5e97a66a529a	refs/tags/v0.1
623bc4f455bca96a6431e20babb436974417a5fc	refs/tags/v0.1^{}
30d8963cefb373b9ccc10caebc80859f7e32ca28	refs/tags/v0.2
5295cd7b31a85197949c9f348210965907c7214b	refs/tags/v0.2^{}
eac92e5bd234f6a42db3f63a55c6909311ac998d	refs/tags/v1.0.0
a6c716e02da853e811b96e6a6c37e21ec893a06a	refs/tags/v2.0.0

使用 Wire 協議的好處

場景好處
clone淺表克隆之類的操作被簡化了
fetch能夠過濾掉不需要的引用,意味着只需要關係自己的分支
push暫未使用

當你在碼雲上有存儲庫,並且存儲庫分支比較多的時候,你可以分別使用如下命令觀察:

GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=2 fetch origin master
GIT_TRACE=1 GIT_TRACE_PACKET=1 git fetch origin master

可以發現 v1 協議需要去查看所有的引用,而 Wire 並不需要這樣做。當然 Wire 才推出不久,用戶體驗上改進還不是很明顯,但隨着 git 其他功能與 wire 傳輸協議的整合,用戶在使用 git 的感受也將越來越好。

Git V2 協議總結

Google 雲平臺最開始支持 Git Wire Protocol,現在碼雲也支持了,下面是廠商支持列表:

平臺是否支持 Git v2
Gitee支持 SSH/HTTP
Github不支持
Gitlab在做,但 Gitlab.org 不支持
Bitbucket不支持
Gitea不支持,但有 Issue 討論
Gogs不支持,但有 Issue 討論
Coding不支持

Git V2 對於一些小型存儲庫並不明顯,但對於淺表克隆,海量分支的項目,v2 帶來的改進非常明顯,另外其擴展性對於 git 正在做的部分克隆(類似 Git VFS/GVFS)非常有利,隨着項目規模的擴大,Git 這種分佈式版本控制系統越來越力不從心,不斷的出現 Git LFS, Git GVFS 也就是人們不斷的探索。

其他改進

無論是 SSH 還是 HTTP,碼雲的基礎設施團隊都對其進行了大量的改進,比如目前的 Basalt libssh 已經升級到 0.8.1,修復了 ED25519 HostKey 的支持,對於一些網絡不穩定,或者特殊存儲庫克隆到 100% 時,出現 Broken Pipe 錯誤,我們也已經修復。

如果諸位再次出現此錯誤,那就給我們反饋,如果是我們的錯誤那就說明可能還沒有修復。

我們還有提升了 git-srv 的穩定性。

對於 Basalt 而言,錯誤提示現在更加清晰,用戶一眼就知道錯誤出現在哪裏。比如克隆一個不存在的存儲庫提示如下:

下一步

除了這些改進,碼雲還有 Git LFS,SVN-SSH 等等功能即將上線,碼雲基礎設施團隊還實現了一個 Git VFS (aka GVFS) 的原型,大家有更好的想法和建議歡迎與碼雲開發者交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章